
Python Web应用的Dockerfile必须指定明确的Python版本和基础镜像
用 python:latest 或 python:slim 不写小版本号,上线后可能突然构建失败或行为异常——因为镜像底层Python微版本升级了,比如 python:3.11-slim 某天变成 3.11.9,而你的 pydantic 依赖只兼容 3.11.7。
实操建议:
始终锁定小版本:用 python:3.11.7-slim-bookworm(推荐 Debian Bookworm,比 Alpine 更少遇到 glibc/SSL 兼容问题)避免 python:3-alpine,除非你清楚自己在处理 musl libc、缺少二进制 wheel、以及编译 psycopg2 或 numpy 的麻烦如果项目用 Poetry,别在 Dockerfile 里反复 poetry install;先本地 poetry export -f requirements.txt > requirements.txt,再 COPY 进容器用 pip install -r requirements.txt —— 构建更快、层更稳定
WORKDIR 和 COPY 顺序搞反会导致 pip install 缓存失效
Docker 构建缓存很敏感。把 COPY . . 放在 RUN pip install 前面,哪怕只改了一个空格,整个依赖安装步骤就全重来,每次都要下载几百 MB 包。
正确顺序是:
立即学习“Python免费学习笔记(深入)”;
先 COPY requirements.txt .(或 pyproject.toml + poetry.lock)再 RUN pip install -r requirements.txt(或 poetry install –no-dev)最后 COPY . .
这样改代码不影响依赖层缓存。注意:requirements.txt 文件本身必须存在且内容稳定,否则缓存照样失效。
启动命令不加 exec 导致信号转发失败,Ctrl+C 或 k8s kill 都杀不死进程
写成 CMD python app.py 或 CMD ["sh", "-c", "python app.py"],容器里实际跑的是 shell 进程,Python 是它的子进程。SIGTERM 来了,shell 不会自动转发给子进程,Web 服务无法优雅退出。
必须用 exec 形式:
推荐:CMD ["gunicorn", "–bind", "0.0.0.0:8000", "app:app"](直接起主进程)如果非要用 Python 启动,写成:CMD ["python", "app.py"],别套 shell绝对不要:CMD python app.py(这是 shell form,隐含 /bin/sh -c)
验证方法:进容器 ps aux,看 PID 1 是否是你期望的进程(如 gunicorn),不是 /bin/sh。
没暴露端口或没绑定 0.0.0.0,容器跑起来却访问不了
EXPOSE 8000 只是文档说明,不等于真的开放端口;Flask 默认绑定 127.0.0.1:5000,在容器里就只能本机访问,外部连不上。
关键点:
EXPOSE 要写,但更重要的是运行时加 -p 8000:8000;K8s 则靠 Service 配置Web 框架必须显式绑定 0.0.0.0:8000:Flask 用 app.run(host="0.0.0.0", port=8000),FastAPI 用 uvicorn.run(…, host="0.0.0.0", port=8000)检查日志有没有类似 Running on http://127.0.0.1:8000 —— 这就是坑,得改成 0.0.0.0
本地测试时,用 curl -v http://localhost:8000 成功不代表容器内没问题;要进容器 curl http://0.0.0.0:8000 和从宿主机 curl 都通才算。
最常被跳过的其实是环境变量注入方式:用 ENV 写死密钥很危险,应该用 docker run -e DATABASE_URL=… 或挂载 .env 文件,但记得在代码里用 dotenv.load_dotenv() 主动加载,别指望 Docker 自动读取。

评论(0)