用 Docker 单容器部署 FastAPI
个人简历站、内容后台和轻量业务系统不一定需要 Docker Compose。只要边界清楚,一个 Docker 容器就可以同时提供 FastAPI 应用、Jinja2 模板页面、静态资源和健康检查。关键是把配置、数据和镜像职责分清楚。
镜像:只放运行应用需要的东西
镜像应该包含 Python 运行时、依赖包、应用代码、模板和静态资源。不要把本地开发缓存、测试输出、临时文件打进镜像。.dockerignore 要排除虚拟环境、Git 目录、缓存目录和本地内容数据。
依赖安装要可重复
构建时先复制 requirements.txt,安装依赖,再复制应用代码。这样代码变更不会每次都重新安装依赖,构建速度更稳定。生产镜像里不建议安装调试工具,保持镜像轻量。
启动:一个 ASGI 进程即可
FastAPI 推荐用 uvicorn 启动,监听 0.0.0.0,容器内部端口固定为 8000,宿主机端口通过 docker run -p 映射。这样本地测试可以映射到 9900,线上可以交给反向代理转发。
代理头要考虑
如果前面有 Nginx、Traefik 或云负载均衡,启动时应启用 proxy headers,让应用能识别真实协议和来源。否则生成 canonical、跳转地址或日志 IP 时可能不准确。
环境变量:配置不要写死进镜像
管理员账号、密码、会话密钥、存储方式、MongoDB 地址、站点 URL 都应该走环境变量。镜像只定义默认行为,部署环境决定具体配置。
必须单独配置的值
SESSION_SECRET 必须足够长且不能使用默认值;ADMIN_PASSWORD 也不要写在代码里。CONTENT_DIR 指向容器内持久化目录,文件存储模式下尤其重要。
数据持久化:内容目录挂载卷
文件存储最大的风险是容器删除后数据丢失。解决方式是把 /app/content 声明为卷,并在运行时挂载 Docker volume 或宿主机目录。容器可以随时重建,内容数据不能跟着镜像生命周期走。
备份策略要简单可执行
如果使用 Docker volume,可以定期把卷内容打包;如果挂宿主机目录,可以纳入服务器备份。备份不只看是否存在,还要偶尔做恢复演练,确认 Markdown 正文和 JSON 索引能一起恢复。
健康检查:让服务状态可判断
单容器也需要健康检查。应用提供 /health,返回运行状态和当前存储后端;Dockerfile 里配置 HEALTHCHECK,让 Docker 能判断容器是否真的可用,而不是进程还活着就算成功。
健康检查不要做重活
健康检查应该轻量,不要渲染复杂页面,也不要执行耗时查询。它只需要验证应用能响应、关键依赖能连通即可。
单容器运行示例
docker run -d \
--name wuzhiyang-site \
-p 9900:8000 \
-e ADMIN_USERNAME=admin \
-e ADMIN_PASSWORD=your-password \
-e SESSION_SECRET=replace-with-long-secret \
-v wuzhiyang-content:/app/content \
wuzhiyang-site:latest
上线前检查清单
- 镜像能构建成功,并且不依赖本机虚拟环境。
/health返回 200,Docker 状态为 healthy。- 管理员密码和会话密钥通过环境变量注入。
- 文件存储目录已挂载卷,重启容器后内容仍在。
- 静态资源使用本地文件,不依赖 CDN。
- 公开页面 canonical 和站点 URL 配置正确。
单容器部署的目标是降低复杂度,而不是牺牲可靠性。只要镜像、配置、数据持久化和健康检查边界清楚,它完全可以支撑一个可维护、可迁移、可持续迭代的 FastAPI 网站。