问题描述
我有一个Flask应用程序,它使用SocketIO从Postgres live中获取数据.
I have a Flask application that uses SocketIO to fetch data from Postgres live.
当我在本地运行该应用程序时,它运行正常.
The app works fine when I run this locally.
当我使用docker-compose托管我的Flask应用时,会引起问题.我的JS客户端和flask服务器托管在单个应用程序中,并且位于同一容器中.
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.
我在JS中的socketio如下:
My socketio in JS is like this:
var socket = io().connect(window.location.protocol + '//' + document.domain + ':' + location.port);
Dockerfile:
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
我的docker-compose就是这样:
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
我还尝试使用 var socket = io.connect('http://public_ip_of_website:8083')
,但是我的套接字连接仍然无法正常工作.
I've also tried to use var socket = io.connect('http://public_ip_of_website:8083')
but my socket connection still doesn't work.
当我在本地运行并单击某个按钮时,它通常如何工作,它将在我的JS中执行此功能:
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'
});
}
});
当我的服务器打个招呼时,它会启动一条tweet流并通过套接字发出它们.然后我的套接字就这样捕获它们:
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>
`);
});
但是当我在docker上运行时,什么也没发生.
But when i run it on docker, nothing happens.
当我检查我的浏览器JS控制台时,似乎正在以错误的请求进行轮询,我不知道为什么:
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)
这是我的docker ps,以获取更多信息:
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
我认为这不是可访问性问题,因为我尝试了从每个容器到每个容器的多个telnet测试.
I don't think this is an accessibility issue because i tried several telnet tests from each container and to each container also.
我检查了docker容器的日志,并给出了以下信息:
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
仅供参考,plutus容器只是我的Web应用程序连接到的Postgres数据库.
FYI, the plutus container is just my Postgres database that my web app connects to.
任何人都可以帮助我吗?
Can anyone please help me ?
推荐答案
TL; DR -您正在客户端和服务器之间使用不兼容的socketIO版本.检查下表,并确保您使用的是适当的python&javascript版本.
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.
就像容器日志中所说的那样,您在客户端和服务器之间使用了不兼容的SocketIO版本.套接字IOEngineIO协议已经过几次修订,它们是并非全部向后兼容,因此您必须确保在客户端和服务器端使用了可以互相通信的协议的适当实现.
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.
我怀疑它在本地运行应用程序而不是在Docker容器中运行时之所以起作用,是因为容器的 requirements.txt
中的依赖项引用了较旧的,不兼容的python实现版本.根据您的描述,socketIO的本地安装python实现似乎是较新的版本,因此与客户端上的较新JS版本兼容,并且连接没有问题(或者反之亦然....较旧的客户端,较新的服务器).
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).
如果您在客户端上使用本机javascript Socket.IO 3.0+版(可实现 SocketIO协议v5 和 EngineIO协议v4 ),那么您需要确保在服务器端使用了适当版本的Python实现.您没有指定,但我假设您使用的是 Flask-SocketIO
,它本身是SocketIO协议的实际Python实现 python-socketio
的包装.
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.
检查在Javascript中使用的SocketIO客户端版本.然后根据下表检查 requirements.txt
并确保python-socketio版本兼容(源):
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):
0.9.x | 1、2 | 1、2 | 不支持 |
1.x和2.x | 3,4 | 3 | 4.x |
3.x | 5 | 4 | 5.x |
您最有可能使用JS版本3.x和python方面的4.x版本(不兼容).确保您使用的是 Flask-SocketIO
v5.x, python-socketio
v5.x和 python-engineio
v4.x,以及您的JS客户端是3.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.
如果这在您的本地环境中正常运行,那么您只需运行点冻结>requirements.txt
并将其用于您的docker构建.该 requirements.txt
文件具有正确的依赖性,因为显然,当您在本地运行该文件时,该文件可以正常工作.
If this is working properly in your local environment, then you could simply runpip 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.
或者,如果要确保您拥有所有内容的最新版本,则可以运行 pip install --upgrade flask-socketio
.这将安装最新版本的Flask-SocketIO和最新的依赖项(包括python-socketio和python-engineio).然后只需重新生成您的requirements.txt文件并在您的Docker构建中使用它即可.
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.
这篇关于Flask Docker容器SocketIO问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!