不能用 flask run 启动生产容器,因其单线程、无进程管理、不支持多 worker,导致并发下卡死崩溃;必须改用 gunicorn,并确保镜像瘦身、依赖隔离、端口绑定 0.0.0.0。

直接用 flask run 启动的容器在生产环境会挂掉,必须换 gunicorn;镜像不瘦身、依赖不隔离、端口绑错 0.0.0.0,这三件事做错一个,容器就起不来或扛不住压。
为什么不能用 flask run 启动容器
Flask 自带的开发服务器是单线程、非异步、无超时控制的,Docker 容器里一有并发请求就卡死或崩溃。错误日志里常出现 Address already in use 或进程静默退出,其实不是端口冲突,而是 worker 崩溃后没重启机制。
-
flask run没有进程管理能力,容器启动后主进程一退,整个容器就Exited (0) - 它不支持多 worker,无法利用多核,QPS 上不去
- Docker 默认关闭
pty和信号转发,Ctrl+C无法终止flask run,调试极难 - 生产镜像里还留着
debug=True或reloader=True?那是安全漏洞
Dockerfile 必须用多阶段构建
用单阶段 FROM python:3.12-slim + RUN pip install -r requirements.txt 会把构建依赖(如 gcc、musl-dev)和测试工具(pytest、black)全打进最终镜像,体积翻倍、启动变慢、攻击面扩大——你看到的 800MB 镜像,70% 是冗余。
- 构建阶段只 COPY
requirements-prod.txt(不是requirements.txt),用pip wheel --no-deps --wheel-dir /wheels -r ...预编译依赖 - 运行阶段用同一基础镜像,但只
COPY --from=builder /wheels和COPY --from=builder /usr/local/lib/python3.12/site-packages,不装任何在线源 - 最后加
RUN pip install --find-links /wheels --no-index *,确保离线可重现,不因 PyPI 暂停而构建失败 - 别漏
RUN rm -rf /wheels,否则缓存污染、镜像膨胀
gunicorn 启动参数写错一个就 ModuleNotFoundError
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"] 看似简单,但 app:app 是模块名:实例名,大小写、路径、文件扩展名全要对上。常见错误:把 main.py 写成 app.py 却在 CMD 里写 main:app,或者 app.py 里 Flask 实例叫 application 却写成 app:app。
-
--bind必须是0.0.0.0:5000,写127.0.0.1:5000容器内网络不通,docker run -p映射无效 -
--workers建议设为CPU 核数 × 2 + 1,但最小别低于 2;单 worker 时一个慢查询就阻塞全部请求 - 加
--timeout 30和--keep-alive 5,防长连接耗尽资源 - 如果用了
alembic或需要执行flask db upgrade,得额外在运行阶段RUN pip install flask(因为flaskCLI 不随Flask包自动安装)
.dockerignore 和 requirements-prod.txt 容易被跳过
很多人写完 Dockerfile 就跑 docker build,结果镜像里混进 .git、__pycache__、venv,甚至本地 .env 文件——这些不会报错,但会导致配置泄露、构建变慢、镜像不可复现。
-
.dockerignore至少要包含:.git、__pycache__、*.pyc、venv、.env、tests/、docs/ -
requirements-prod.txt不能靠pip freeze > req.txt生成,要用pipreqs . --encoding=utf8 --force扫描代码真实 import,再手动删掉-e .、dev相关行 - 镜像里不要留
pip install -e .,它会把当前目录软链进 site-packages,导致 COPY . . 后路径错乱 - 检查最终镜像是否真干净:
docker run --rm -it my-flask-app:latest ls -la /app,确认没多余文件
最常被忽略的是:你以为改了 app.py 里的 app.run(host='0.0.0.0') 就够了,其实它根本不会被执行——因为 CMD 已指定 gunicorn,app.py 只是被当模块导入。所有逻辑必须能被 gunicorn app:app 正确加载,而不是靠 if __name__ == '__main__' 触发。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











