I have been having some odd issues with docker today. I described one issue @ pathlib: cannot import name 'Sequence' from 'collections'. I didn't really need one of the packages that was causing the break so I took it out. Note that this issue was only happening in docker.
After taking out artifactory package dependency install on docker passed successfully, but am hitting TypeError in my flask app init file when importing:
from flask_socketio import SocketIO, emit
which requires eventlet which is where the error comes from:
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
So when run with docker it fails with the above error. My entrypoint looks like:
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
But if the same gunicorn command is run locally the app boots with no issues.
UPDATE: I wanted to try a more reproducible example and have narrowed it down as such: 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
Dockerfile:
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"]
Executed with docker build/docker run -it --publish 8888:8000 image_name.
and get the same error. If eventlet is removed from requirements, there is no error.
Am I doing something wrong? I just want to run flask-socketio with eventlet
Searching for the exception, leads to the corresponding eventlet issue: https://github.com/eventlet/eventlet/issues/687
The summary is that eventlet (0.32.0) is currently not compatible with Python 3.10 because it tries to patch types that have become immutable in Python 3.10.
Like with your requirements, it is good practice to be more specific with your Docker dependencies too. Today using the tag 3
for the Python Docker image will give you 3.10.0
, unless it is using a cache. In the future it could be a different version. Since there is a compatibility issue with Python 3.10, use Python 3.9 - the currently latest Python 3.9 Docker tag is 3.9.7
.
i.e. it should work once you change your first line of the Dockerfile
to:
FROM python:3.9.7