Flask Docker container SocketIO Issues

纵饮孤独 提交于 2021-02-18 12:18:06

问题


I have a Flask application that uses SocketIO to fetch data from Postgres live.

The app works fine when I run this locally.

The problem arouses when I use docker-compose to host my Flask app. My JS client and flask server is hosted into a single app and on the same container.

My socketio in JS is like this:

var socket = io().connect(window.location.protocol + '//' + document.domain + ':' + location.port);

Dockerfile:

# Using python 3.7 in Alpine
FROM python:3.6.5-stretch

# Set the working directory to /app
WORKDIR /app

# Copy the current directory contents into the container at /app
ADD . /app

RUN apt-get update -y && apt-get upgrade -y

# Install the dependencies from requirements
RUN pip install -r requirements.txt

# Tell the port number the container should expose
EXPOSE 8083

# Run the command
ENTRYPOINT ["./entry.sh"]

entry.sh:

#!/bin/sh
gunicorn -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -b :8083 -w 5 run:app

My docker-compose is as such:

version: "3.8"

services:
  fortweet:
    container_name: fortweet
    build: ./
    env_file:
      - secret.env
    networks:
      - plutusnet
    ports:
      - 8083:8083
    restart: always

networks:
  plutusnet:
    name: plutus_network
    driver: bridge

I've also tried to use var socket = io.connect('http://public_ip_of_website:8083') but my socket connection still doesn't work.

How it should normally work is when i run this locally and click a certain button, it executes this function in my JS:

$("#tweets-live-start").click(function(){
    if (is_streaming == true){
      alert("A stream is already running")
    }else{
      $.ajax({
        type: "POST",
        url : "/admin/startstream",
        data: {url : "print \"hello\""},
        contentType: 'application/json;charset=UTF-8'
      });
    }
  });

When my server gets the hello, it starts a tweet streaming and emits them through the socket. Then my socket captures them as such:

// Listens for tweets
socket.on('stream-results', function(results){

  // Insert tweets in divs
  $('#live-tweet-container').prepend(`
  <div class="row justify-content-md-center mt-3">
    <div class="col-md-2">
        <img width="56px" height="56px"  src="${results.profile_pic !== "" ? results.profile_pic : "/static/icons/profile-pic.png"}" class="mx-auto d-block rounded"  alt="">
    </div>
    <div class="col-md-8 my-auto">
      <div><b>${results.author}</b></div>
      <div>${results.message}</div>
    </div>
  </div>
  `);
});

But when i run it on docker, nothing happens.

When i check my browser JS console, it seems that it is polling with a bad request and i don't know why:

index.js:83 GET http://th3pl4gu3.com:8083/socket.io/?EIO=3&transport=polling&t=NPYYrxr 400 (BAD REQUEST)

Here is my docker ps for more info:

46446efeb472   mervin16/fortweet:dev   "/bin/bash entry.sh"  About a minute ago   Up About a minute   0.0.0.0:8083->8083/tcp   fortweet

12b2bff36af0   postgres    "docker-entrypoint.s…"   2 hours ago          Up 2 hours          0.0.0.0:5432->5432/tcp   plutus

I don't think this is an accessibility issue because i tried several telnet tests from each container and to each container also.

I checked logs of the docker container and it gives this:

fortweet    | [2020-12-26 15:18:55 +0000] [8] [INFO] Starting gunicorn 20.0.4
fortweet    | [2020-12-26 15:18:55 +0000] [8] [INFO] Listening at: http://0.0.0.0:8083 (8)
fortweet    | [2020-12-26 15:18:55 +0000] [8] [INFO] Using worker: geventwebsocket.gunicorn.workers.GeventWebSocketWorker
fortweet    | [2020-12-26 15:18:55 +0000] [11] [INFO] Booting worker with pid: 11
fortweet    | [2020-12-26 15:18:55 +0000] [12] [INFO] Booting worker with pid: 12
fortweet    | [2020-12-26 15:18:55 +0000] [13] [INFO] Booting worker with pid: 13
fortweet    | [2020-12-26 15:18:55 +0000] [14] [INFO] Booting worker with pid: 14
fortweet    | [2020-12-26 15:18:55 +0000] [15] [INFO] Booting worker with pid: 15
fortweet    | The client is using an unsupported version of the Socket.IO or Engine.IO protocols (further occurrences of this error will be logged with level INFO)
fortweet    | The client is using an unsupported version of the Socket.IO or Engine.IO protocols (further occurrences of this error will be logged with level INFO)
fortweet    | 172.16.0.1 - - [2020-12-26 15:19:57] "POST /admin/startstream HTTP/1.1" 204 170 0.023672
fortweet    | The client is using an unsupported version of the Socket.IO or Engine.IO protocols (further occurrences of this error will be logged with level INFO)
fortweet    | The client is using an unsupported version of the Socket.IO or Engine.IO protocols (further occurrences of this error will be logged with level INFO)
fortweet    | 172.16.0.1 - - [2020-12-26 15:20:20] "GET /socket.io/?EIO=3&transport=polling&t=1608996021267-7 HTTP/1.1" 400 195 0.001418
fortweet    | 172.16.0.1 - - [2020-12-26 15:20:20] "GET /socket.io/?EIO=3&transport=polling&t=1608996021267-7 HTTP/1.1" 400 195 0.001418
fortweet    | 172.16.0.1 - - [2020-12-26 15:20:21] "GET /socket.io/?EIO=3&transport=polling&t=1608996021395-8 HTTP/1.1" 400 195 0.001625
fortweet    | 172.16.0.1 - - [2020-12-26 15:20:21] "GET /socket.io/?EIO=3&transport=polling&t=1608996021395-8 HTTP/1.1" 400 195 0.001625
fortweet    | 172.16.0.1 - - [2020-12-26 15:20:26] "GET /socket.io/?EIO=3&transport=polling&t=1608996026417-9 HTTP/1.1" 400 195 0.001367
fortweet    | 172.16.0.1 - - [2020-12-26 15:20:26] "GET /socket.io/?EIO=3&transport=polling&t=1608996026417-9 HTTP/1.1" 400 195 0.001367
fortweet    | 172.16.0.1 - - [2020-12-26 15:20:26] "GET /socket.io/?EIO=3&transport=polling&t=1608996027270-8 HTTP/1.1" 400 195 0.003811
fortweet    | 172.16.0.1 - - [2020-12-26 15:20:26] "GET /socket.io/?EIO=3&transport=polling&t=1608996027270-8 HTTP/1.1" 400 195 0.003811
fortweet    | 172.16.0.1 - - [2020-12-26 15:20:34] "POST /admin/startstream HTTP/1.1" 204 170 0.015831
fortweet    | 172.16.0.1 - - [2020-12-26 15:20:36] "GET /socket.io/?EIO=3&transport=polling&t=1608996036486-11 HTTP/1.1" 400 195 0.001096

FYI, the plutus container is just my Postgres database that my web app connects to.

Can anyone please help me ?


回答1:


TL;DR - you're using incompatible socketIO versions between client and server. Check the table below and make sure you're using the appropriate python & javascript versions.

Like the container logs say, you're using incompatible versions of SocketIO between client and server. The SocketIO & EngineIO protocols have been through several revisions, and they're not all backward compatible, so you have to make sure you're using appropriate implementations of the protocol on the client and server side that can talk to one another.

I suspect that the reason it's working when you run your app locally but not in your Docker container is because the dependencies in your container's requirements.txt are referencing older, incompatible versions of the python implementation. Based on what you described, it seems like the locally installed python implementation of socketIO is a newer version, and therefore compatible with the newer JS version on client-side, and has no trouble connecting (or it could be vice-versa....older client, newer server).

If you're using the native javascript Socket.IO version 3.0+ on the client side (which implements the SocketIO Protocol v5 and EngineIO Protocol v4), then you need to make sure you're using the appropriate versions of the Python implementations on the server side. You didn't specify, but I assume you're using Flask-SocketIO, which itself is a wrapper around python-socketio, the actual Python implementation of the SocketIO protocol.

Check what version of SocketIO client you are using in your Javascript. Then check your requirements.txt and make sure the python-socketio version is compatible, per the below table (source):

JS SocketIO Version SocketIO Protocol EngineIO Protocol python-socketio
0.9.x 1, 2 1, 2 Not supported
1.x and 2.x 3, 4 3 4.x
3.x 5 4 5.x

You're most likely using the JS version 3.x with the 4.x version on the python side (which are NOT compatible). Make sure that you are using Flask-SocketIO v5.x, python-socketio v5.x, and python-engineio v4.x, and that your JS client is 3.x. That should fix your problem.

If this is working properly in your local environment, then you could simply run pip freeze > requirements.txt and use that for your docker build. This requirements.txt file would have the correct dependencies since clearly it is working when you run locally.

Alternatively, if you want to ensure that you have the latest version of everything, you could run pip install --upgrade flask-socketio. This will install the latest version of Flask-SocketIO and the most up to date dependencies (including python-socketio and python-engineio). Then just regenerate your requirements.txt file and use it in your docker build.




回答2:


The 400 (BAD REQUEST) indicates that there is a communication between Your Browser+JS and the Flask app.

I suspect an issue between The Flask App and Postgres.

Your Postgres has to be in the same network as you application server (the service you call "fortweet" in your docker-compose. Plus, you have give it a hostname so the app server can resolve it internally.

version: "3.8"

services:
  postgres:                               #    <=== same name here 
    image: postgres/postgres:11
    networks:
      - plutusnet                      #  <== same network

  fortweet:
    container_name: fortweet
    build: ./
    env_file:
      - secret.env
    networks:
      - plutusnet                        #  <=== same network
    links:
      - db:postgres                      #    <== than here
    ports:
      - 8083:8083
    restart: always

networks:
  plutusnet:
    name: plutus_network
    driver: bridge`

Then the app must be configured to use "postgres:5432" to connect to DB.

Have a try and tell us.



来源:https://stackoverflow.com/questions/65189422/flask-docker-container-socketio-issues

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!