4

Hello I'm trying to setup flask-socketio in a docker container. It seems to run but I get an error( from the browser) when I try to access localhost on port 5000 like I'm used to do with flask apps. It say's: unable to connect!

I will show you the 5 important files: Dockerfile, requirements.txt, docker-compose.yml, web_app.py and index.html

Dockerfile:

FROM python:3.6.5

WORKDIR /code
COPY * /code/
RUN pip install -r requirements.txt

requirements.txt:

Flask==1.0.2
Flask-SocketIO==3.0.1
eventlet==0.24.1

docker-compose.yml:

version: "3"
services:
  web:
    build: ./web
    ports:
      - '5000:5000'
    volumes:
      - './web:/code'

I use the commands docker-compose up --build and docker-compose run web /bin/bash to enter this container in interactive mode.

web_app.py:

from flask import Flask, render_template
from flask_socketio import SocketIO, emit

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)

@app.route('/')
def index():
    return render_template('index.html')

@socketio.on('my event')
def log_message(message):
    emit('my response', {'data': 'got it!'})

if __name__ == '__main__':
    socketio.run(app)

index.html:

<!doctype html>
<html>
<head>
  <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
  <title>SocketIO</title>
</head>
<body>

  <script type="text/javascript" charset="utf-8">
    //Establish connection and emit a message to confirm.

    var socket = io.connect('http://' + document.domain + ':' + location.port);
    socket.on('connect', function() {
        socket.emit('my event', {data: 'I\'m connected!'});
    });

  </script>

</body>
</html>

Once inside the container I simple run: python web_app.py but nothing happens. No error and no working page.

I feel like I'm missing so steps to initialize everything correctly but I cant find out what it is. The web is full of very different examples and I'm confused. What makes it even harder is that I'm using eventlet here but not every example goes this route. Some use gevent or other things.

I would be really glad if someone gave me a little hint. Cheers

The Fool
  • 16,715
  • 5
  • 52
  • 86
  • 2
    Try `socketio.run(app, host='0.0.0.0')`. I think you're only running on localhost by default meaning only other apps inside the docker container can access it (i.e. none) – Hitobat Aug 19 '18 at 19:04
  • @Hitobat well I can pass the host as second argument without error but evrything remains the same. No website and no error. The app "IS" running but I cant see it :( – The Fool Aug 19 '18 at 19:10
  • Maybe if I include expose in the docker-compose.yaml? – The Fool Aug 19 '18 at 19:11
  • Can you verify first that the code works without docker? i.e. If you run it locally can you get the page to load correctly? Then we can see if this is a code problem or a docker problem. – Hitobat Aug 19 '18 at 19:49
  • @Hitbat yes that would be a good thing to do but the problem is that I do not want to Install anything locally. I use docker in a virtual environment fashion to keep my OS clean. – The Fool Aug 20 '18 at 13:38

2 Answers2

5

When starting compose, make sure all environment variable are set for flask. Also provide the --host=0.0.0.0 to listen on all network interfaces, in your entrypoint or command.

The updated docker-compose file:

version: "3"
services:
    web:
        build: ./web
        volumes:
            - './application:/application'
        environment:
            FLASK_DEBUG: 1
            FLASK_ENV: development
            FLASK_APP: web_app.py
        ports:
            - '5000:5000'
        entrypoint:
            - flask
            - run
            - --host=0.0.0.0

When you want to run the container in interactive mode for development purposes, you could run it with docker-compose run the below command. --service-ports is required to expose the containers ports as specified in the compose file. If this flag isn't provided, no external traffic will reach the app. That was my original problem.

docker-compose run --service-ports web bash

Alternatively you could publish the port manually

docker-compose run --publish 5000:5000 web bash
The Fool
  • 16,715
  • 5
  • 52
  • 86
1

You haven't started app in your docker container. Add two more lines to the Dockerfile:

EXPOSE 5000

ENTRYPOINT ["python", "/code/web_app.py"]
Fine
  • 2,114
  • 1
  • 12
  • 18
  • well if you read carefully what I wrote you realize that while its true that docker-compose does not start the app when I use `docker-compose up --build` but thats why I run the following commads once my image is build: `docker-compose run app /bin/bash` and inside i run `python web_app.py` .( Its all written in my post like this) anyways I will try to experiment with expose and let you know about it soon. – The Fool Aug 20 '18 at 13:35
  • So it turns out very wierd. I do not need expose but when I use an entrypoint it works but only compined with setting the host to 0.0.0.0 in my socketio app. Ill post an answer below – The Fool Aug 20 '18 at 14:18