把 FastAPI 装进 Docker:从本地运行到可交付镜像
摘要:用一个最小 Dockerfile 固定 Python、依赖和启动命令,解释为什么容器必须监听 0.0.0.0、生产不能使用 reload,并用健康检查验证镜像。

图:解释器、依赖、应用和启动命令组成镜像,通过端口映射提供服务并接受健康检查。
虚拟环境解决了 Python 依赖隔离,却没有固定操作系统、解释器和启动命令。“在我的电脑上能运行”到了另一台机器,仍可能因为环境差异失败。
这篇文章把一个 FastAPI 服务装进可重复构建的镜像。重点不是背 Dockerfile 指令,而是看清几个直接影响交付的选择:复制顺序、构建上下文、监听地址和生产启动方式。
先看镜像构建和运行的最终命令
docker build -f examples/ch15_docker/Dockerfile -t fastapi-tutorial:ch15 .
docker run --name fastapi-ch15 -p 8000:8000 fastapi-tutorial:ch15
另开终端:
curl http://127.0.0.1:8000/health
预期返回 {"status":"ok"}。
先确认本机真的有可用的 Docker Server
cd 04-fastapi-beginner
docker version
命令需要同时显示 Client 和 Server 信息。若只有 Client 或提示无法连接 daemon,请先启动 Docker Desktop 或容器运行时。
本文镜像不需要本地虚拟环境;安装发生在镜像内部。
用四段 Dockerfile 固定运行环境
固定基础镜像和环境
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
WORKDIR /app
固定 Python 小版本系列比 python:latest 更可预测。slim 减少无关系统组件。
先复制依赖
COPY examples/ch15_docker/requirements.txt ./requirements.txt
RUN python -m pip install --no-cache-dir -r requirements.txt
COPY examples/ch15_docker/main.py ./main.py
代码变化但依赖不变时,Docker 可以复用安装层缓存。
使用容器启动命令
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
容器内必须监听 0.0.0.0 才能接受映射端口流量;生产启动不使用 --reload。

图:先固定基础环境和依赖层,再复制经常变化的应用代码,镜像构建会更稳定。
构建镜像,启动容器,再检查健康状态
docker build -f examples/ch15_docker/Dockerfile -t fastapi-tutorial:ch15 .
docker run -d --name fastapi-ch15 -p 8000:8000 fastapi-tutorial:ch15
curl -i http://127.0.0.1:8000/health
docker logs fastapi-ch15
docker stop fastapi-ch15
docker rm fastapi-ch15
预期构建成功、健康检查 200、日志出现 Uvicorn 启动信息,容器能够正常停止。静态校验:
python -m pytest tests/test_ch15.py -q
镜像、容器和端口映射分别解决什么
镜像是只读交付物,容器是镜像的一次运行实例。数据库文件、上传文件等持久数据不应只写在容器可写层,应使用数据库服务或显式 volume。
Dockerfile 中的 EXPOSE 8000 是元数据,不会自动发布端口;-p 8000:8000 才把宿主端口映射到容器。
生产还需要非 root 用户、镜像扫描、只读文件系统、资源限制、健康探针和外部秘密注入。本文先建立可重复交付闭环。

图:主机请求先到容器端口,再沿映射通道到达容器内部监听的应用。
容器启动了,接口却访问不到的常见原因
- 服务监听 127.0.0.1:容器外无法访问,改为 0.0.0.0。
- build context 选错:本 Dockerfile 要从项目根目录构建。
- 把
.venv复制进镜像:平台可能不同且体积巨大,使用.dockerignore。 - 容器删除后 SQLite 数据消失:使用 volume 或外部 PostgreSQL。
- 生产使用
--reload:增加文件监控和重启行为,不适合作为生产进程管理。
从教学镜像继续补齐生产约束
- 给镜像增加 Docker HEALTHCHECK。
- 使用
docker inspect查看端口映射和启动命令。 - 比较加入与移除
.dockerignore后的构建上下文。 - 增加非 root 用户运行应用。
- 把
APP_VERSION作为环境变量传入并在/health返回。
最后,用测试固定这次改动
手动请求通过后,运行与本文对应的自动化测试:
python -m pytest tests/test_ch15.py -q
python tests/validate_course.py
写在最后
应用已经形成可交付镜像。系列最后一篇会把认证、数据库、依赖、路由、所有者权限和场景测试合并成一个完整项目,并按真实用户旅程验证。