pythondockerflaskflask-socketioeventlet

How to setup flask-socketio in a docker container?


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


Solution

  • 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