eventlet 在 docker 中导入时抛出错误
eventlet throws error on import in docker
今天 docker 我遇到了一些奇怪的问题。我描述了一个问题@ 。我真的不需要导致中断的包之一,所以我把它拿出来了。请注意,此问题仅发生在 docker.
在 docker 上取出人工包依赖安装后成功通过,但在导入时在我的 flask 应用程序初始化文件中遇到 TypeError:
from flask_socketio import SocketIO, emit
需要 eventlet,这是错误的来源:
web_1 | from eventlet import greenio
web_1 | File "/usr/local/lib/python3.10/site-packages/eventlet/greenio/__init__.py", line 3, in <module>
web_1 | from eventlet.greenio.base import * # noqa
web_1 | File "/usr/local/lib/python3.10/site-packages/eventlet/greenio/base.py", line 32, in <module>
web_1 | socket_timeout = eventlet.timeout.wrap_is_timeout(socket.timeout)
web_1 | File "/usr/local/lib/python3.10/site-packages/eventlet/timeout.py", line 166, in wrap_is_timeout
web_1 | base.is_timeout = property(lambda _: True)
web_1 | TypeError: cannot set 'is_timeout' attribute of immutable type 'TimeoutError'
web_1 | ]
requirements.txt:
alembic==1.7.3
aniso8601==8.0.0
appdirs==1.4.4
attrs==20.3.0
bcrypt==3.2.0
beautifulsoup4==4.9.3
bidict==0.21.3
blinker==1.4
boto3==1.18.50
botocore==1.21.50
bs4==0.0.1
cachelib==0.3.0
certifi==2020.12.5
cffi==1.14.5
chardet==3.0.4
click==8.0.1
cryptography==3.4.6
distlib==0.3.2
dnspython==1.16.0
dominate==2.6.0
email-validator==1.1.3
et-xmlfile==1.1.0
eventlet==0.30.2
filelock==3.0.12
Flask==2.0.1
Flask-Bootstrap==3.3.7.1
Flask-Login==0.5.0
Flask-Mail==0.9.1
flask-marshmallow==0.14.0
Flask-Migrate==3.1.0
Flask-RESTful==0.3.8
Flask-Session==0.4.0
Flask-SocketIO==5.1.1
Flask-SQLAlchemy==2.5.1
Flask-User==1.0.2.2
Flask-WTF==0.15.1
greenlet==1.1.0
gunicorn==20.1.0
idna==2.10
iniconfig==1.1.1
is-safe-url==1.0
itsdangerous==2.0.1
Jinja2==3.0.1
jmespath==0.10.0
Mako==1.1.5
MarkupSafe==2.0.1
marshmallow==3.12.2
marshmallow-sqlalchemy==0.26.1
openpyxl==3.0.7
packaging==20.9
paramiko==2.7.2
passlib==1.7.4
pexpect==4.8.0
pluggy==0.13.1
psycopg2-binary==2.9.1
ptyprocess==0.7.0
py==1.10.0
pycparser==2.20
PyNaCl==1.4.0
pyparsing==2.4.7
pytest==6.2.3
python-dateutil==2.8.1
python-dotenv==0.19.0
python-engineio==4.2.1
python-socketio==5.4.0
pytz==2021.1
requests==2.24.0
s3transfer==0.5.0
scp==0.13.3
shippo==2.0.2
simplejson==3.17.2
six==1.15.0
soupsieve==2.2
SQLAlchemy==1.4.15
SQLAlchemy-Utils==0.37.8
toml==0.10.2
urllib3==1.25.11
virtualenv==20.4.7
visitor==0.1.3
Werkzeug==2.0.1
WTForms==2.3.3
XlsxWriter==1.4.3
所以当 运行 和 docker 时,它会因上述错误而失败。我的入口点看起来像:
flask db init
flask db migrate
flask db upgrade
gunicorn "main:create_app()" --workers 1 --threads 10 --bind=0.0.0.0:5010 --worker-class eventlet
但是如果相同的 gunicorn 命令在本地 运行 应用程序启动没有问题。
更新:
我想尝试一个更可重现的例子,并缩小范围如下:
app.py:
from flask import Flask
import flask_socketio
app = Flask(__name__)
def create_app():
return app
requirements.txt:
bidict==0.21.3
click==8.0.1
dnspython==2.1.0
eventlet==0.32.0
Flask==2.0.2
Flask-SocketIO==5.1.1
greenlet==1.1.2
gunicorn==20.1.0
itsdangerous==2.0.1
Jinja2==3.0.2
MarkupSafe==2.0.1
python-engineio==4.2.1
python-socketio==5.4.0
six==1.16.0
Werkzeug==2.0.2
Docker 文件:
FROM python:3
WORKDIR /usr/src/app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 8000
CMD ["gunicorn", "-b", "0.0.0.0:8000", "app:create_app()", "--worker-class", "eventlet"]
执行 docker build/docker 运行 -it --publish 8888:8000 image_name.
并得到同样的错误。如果从requirements中去掉eventlet,就没有错误了。
我做错了什么吗?我只想 运行 flask-socketio 和 eventlet
搜索异常,导致相应的 eventlet 问题:https://github.com/eventlet/eventlet/issues/687
总结是 eventlet (0.32.0) 目前与 Python 3.10 不兼容,因为它试图修补在 Python 3.10 中变得不可变的类型。
与您的要求一样,最好也更具体地说明您的 Docker 依赖项。今天使用标签 3
作为 Python Docker image 会给你 3.10.0
,除非它使用缓存。将来它可能是不同的版本。由于 Python 3.10 存在兼容性问题,请使用 Python 3.9 - 当前最新的 Python 3.9 Docker 标记为 3.9.7
.
即一旦您将 Dockerfile
的第一行更改为:
,它应该可以工作
FROM python:3.9.7
今天 docker 我遇到了一些奇怪的问题。我描述了一个问题@
在 docker 上取出人工包依赖安装后成功通过,但在导入时在我的 flask 应用程序初始化文件中遇到 TypeError:
from flask_socketio import SocketIO, emit
需要 eventlet,这是错误的来源:
web_1 | from eventlet import greenio
web_1 | File "/usr/local/lib/python3.10/site-packages/eventlet/greenio/__init__.py", line 3, in <module>
web_1 | from eventlet.greenio.base import * # noqa
web_1 | File "/usr/local/lib/python3.10/site-packages/eventlet/greenio/base.py", line 32, in <module>
web_1 | socket_timeout = eventlet.timeout.wrap_is_timeout(socket.timeout)
web_1 | File "/usr/local/lib/python3.10/site-packages/eventlet/timeout.py", line 166, in wrap_is_timeout
web_1 | base.is_timeout = property(lambda _: True)
web_1 | TypeError: cannot set 'is_timeout' attribute of immutable type 'TimeoutError'
web_1 | ]
requirements.txt:
alembic==1.7.3
aniso8601==8.0.0
appdirs==1.4.4
attrs==20.3.0
bcrypt==3.2.0
beautifulsoup4==4.9.3
bidict==0.21.3
blinker==1.4
boto3==1.18.50
botocore==1.21.50
bs4==0.0.1
cachelib==0.3.0
certifi==2020.12.5
cffi==1.14.5
chardet==3.0.4
click==8.0.1
cryptography==3.4.6
distlib==0.3.2
dnspython==1.16.0
dominate==2.6.0
email-validator==1.1.3
et-xmlfile==1.1.0
eventlet==0.30.2
filelock==3.0.12
Flask==2.0.1
Flask-Bootstrap==3.3.7.1
Flask-Login==0.5.0
Flask-Mail==0.9.1
flask-marshmallow==0.14.0
Flask-Migrate==3.1.0
Flask-RESTful==0.3.8
Flask-Session==0.4.0
Flask-SocketIO==5.1.1
Flask-SQLAlchemy==2.5.1
Flask-User==1.0.2.2
Flask-WTF==0.15.1
greenlet==1.1.0
gunicorn==20.1.0
idna==2.10
iniconfig==1.1.1
is-safe-url==1.0
itsdangerous==2.0.1
Jinja2==3.0.1
jmespath==0.10.0
Mako==1.1.5
MarkupSafe==2.0.1
marshmallow==3.12.2
marshmallow-sqlalchemy==0.26.1
openpyxl==3.0.7
packaging==20.9
paramiko==2.7.2
passlib==1.7.4
pexpect==4.8.0
pluggy==0.13.1
psycopg2-binary==2.9.1
ptyprocess==0.7.0
py==1.10.0
pycparser==2.20
PyNaCl==1.4.0
pyparsing==2.4.7
pytest==6.2.3
python-dateutil==2.8.1
python-dotenv==0.19.0
python-engineio==4.2.1
python-socketio==5.4.0
pytz==2021.1
requests==2.24.0
s3transfer==0.5.0
scp==0.13.3
shippo==2.0.2
simplejson==3.17.2
six==1.15.0
soupsieve==2.2
SQLAlchemy==1.4.15
SQLAlchemy-Utils==0.37.8
toml==0.10.2
urllib3==1.25.11
virtualenv==20.4.7
visitor==0.1.3
Werkzeug==2.0.1
WTForms==2.3.3
XlsxWriter==1.4.3
所以当 运行 和 docker 时,它会因上述错误而失败。我的入口点看起来像:
flask db init
flask db migrate
flask db upgrade
gunicorn "main:create_app()" --workers 1 --threads 10 --bind=0.0.0.0:5010 --worker-class eventlet
但是如果相同的 gunicorn 命令在本地 运行 应用程序启动没有问题。
更新: 我想尝试一个更可重现的例子,并缩小范围如下: app.py:
from flask import Flask
import flask_socketio
app = Flask(__name__)
def create_app():
return app
requirements.txt:
bidict==0.21.3
click==8.0.1
dnspython==2.1.0
eventlet==0.32.0
Flask==2.0.2
Flask-SocketIO==5.1.1
greenlet==1.1.2
gunicorn==20.1.0
itsdangerous==2.0.1
Jinja2==3.0.2
MarkupSafe==2.0.1
python-engineio==4.2.1
python-socketio==5.4.0
six==1.16.0
Werkzeug==2.0.2
Docker 文件:
FROM python:3
WORKDIR /usr/src/app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 8000
CMD ["gunicorn", "-b", "0.0.0.0:8000", "app:create_app()", "--worker-class", "eventlet"]
执行 docker build/docker 运行 -it --publish 8888:8000 image_name.
并得到同样的错误。如果从requirements中去掉eventlet,就没有错误了。
我做错了什么吗?我只想 运行 flask-socketio 和 eventlet
搜索异常,导致相应的 eventlet 问题:https://github.com/eventlet/eventlet/issues/687
总结是 eventlet (0.32.0) 目前与 Python 3.10 不兼容,因为它试图修补在 Python 3.10 中变得不可变的类型。
与您的要求一样,最好也更具体地说明您的 Docker 依赖项。今天使用标签 3
作为 Python Docker image 会给你 3.10.0
,除非它使用缓存。将来它可能是不同的版本。由于 Python 3.10 存在兼容性问题,请使用 Python 3.9 - 当前最新的 Python 3.9 Docker 标记为 3.9.7
.
即一旦您将 Dockerfile
的第一行更改为:
FROM python:3.9.7