直接用 uvicorn 启动的容器在生产环境不安全、不可靠,必须加进程管理或换镜像;单进程易崩溃退出、不处理 SIGTERM、默认 root 权限、无健康检查、不支持多 worker,且 --reload 仅限开发。

直接用 uvicorn 启动的容器在生产环境不安全、不可靠,必须加一层进程管理或换镜像,否则会挂得无声无息。
为什么不能只写 CMD ["uvicorn", "main:app"]
单进程模式下,Uvicorn 一崩溃整个容器就退出,Kubernetes 或 Docker 重启策略很难及时捕获;它也不处理 SIGTERM 信号,强制停止时可能丢请求;更严重的是,默认以 root 用户运行,违反最小权限原则。
- 没有健康检查端点,编排系统无法判断服务是否真正 ready
- 不支持多 worker,CPU 利用率低,压测时容易成为瓶颈
-
--reload参数仅限开发,Docker 镜像里带上它等于把源码暴露给生产容器
推荐用 tiangolo/uvicorn-gunicorn-fastapi 镜像
这个镜像是为生产打磨过的:内置 Gunicorn 管理多个 Uvicorn worker,自动处理信号、优雅关闭、日志重定向,并预装了 uvloop 和 httptools。你不用改一行代码,只要保证项目结构符合约定即可。
- 默认查找路径是
/app/main.py或/app/app/main.py,别放错位置 - 环境变量如
WORKERS_PER_CORE、MAX_WORKERS可直接覆盖默认配置 - 镜像内用户是
appuser,非 root,无需额外加USER指令 - 启动命令已封装好,你只需
COPY代码进去,不用写CMD
uv + 多阶段构建适合追求极致体积的场景
如果你用 uv 管理依赖,且对镜像体积敏感(比如边缘部署),可以自己写多阶段 Dockerfile。但要注意:uv 的 --system 安装方式在 slim 镜像中可能因缺失 gcc 而失败,得先装构建工具。
- 第一阶段用
python:3.12-slim+build-essential编译依赖 - 第二阶段只 COPY
/usr/local/lib/python3.12/site-packages和代码,不带编译器 -
uv.lock必须存在,否则uv sync --frozen会报错退出 - 最终
CMD推荐用["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"],避免 PATH 问题
环境变量比命令行参数更适合容器化
Docker Compose 或 Kubernetes 中,用环境变量传配置比硬编码进 CMD 更灵活、更安全。Uvicorn 原生识别 UVICORN_HOST、UVICORN_PORT、UVICORN_LOG_LEVEL 等前缀变量。
-
UVICORN_RELOAD=true只应在开发用的docker-compose.yml中设,千万别进生产镜像 -
--env-file对 Uvicorn 本身无效,它只影响 ASGI 应用(如 FastAPI 的.env),别混用 - 端口映射要和
UVICORN_PORT一致,否则容器内监听 8000,但宿主机映射到 8080,会连不通
最容易被忽略的是工作目录和模块路径的耦合:Docker 内 WORKDIR 设为 /app,但启动命令写成 uvicorn api.main:app,而 api/__init__.py 没有被复制进去——结果就是 ModuleNotFoundError。务必确认 ls -l /app 输出和你的模块导入路径完全匹配。


















