How to setup flask-socketio in a docker container?
Asked Answered
J

2

5

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

Janel answered 19/8, 2018 at 17:43 Comment(5)
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)Someday
@Someday 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 :(Janel
Maybe if I include expose in the docker-compose.yaml?Janel
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.Someday
@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.Janel
J
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
Janel answered 20/8, 2018 at 14:25 Comment(6)
Thanks for writing the answer afterwards.Someday
Why you run the app in dockerfile as flask run host='0.0.0.0' and not as python web-app.py since you are using socketio?Hexagram
@NikSp, this was long time ago. But looking at this, if you run main directly you would only run socketio but not flask. Probably not what we want. I guess that if main thing shouldnt be there to begin with.Janel
I am trying to do a similar case with socket.io() and flask through docker. But I cant get socket to connect and emit data. The flask app never connects to socket.io('localhost:5000') ... and I don't know how to debug it to find the error. Plus it should be socket.run(app) and python app.py for running flask-socketio apps.Hexagram
@Hexagram if you do it this way, you may not bind to the containers private network interface, which is used for port forwarding. I guess you are referring to this flask-socketio.readthedocs.io/en/latest/getting_started.html. If you look here, run takes the host. Try setting it to '0.0.0.0', to bind all availble interfaces: flask-socketio.readthedocs.io/en/latest/…Janel
Please check my repo here github.com/NikosSpanos/health-monitoring-appHexagram
S
2

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

EXPOSE 5000

ENTRYPOINT ["python", "/code/web_app.py"]
Spectacular answered 20/8, 2018 at 8:23 Comment(2)
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.Janel
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 belowJanel

© 2022 - 2024 — McMap. All rights reserved.