FastAPI Docker 部署最佳实践
FastAPI 生产容器化的七条实践:扎实的 Dockerfile、环境配置、健康检查、层缓存优化、数据库连接与迁移、日志配置与水平扩展准备。
直接回答:FastAPI 从玩具到生产,Docker 部署要过七关:多阶段精简镜像、配置外置、健康检查、构建缓存优化、数据库连接管理、结构化日志与无状态扩展准备——每一条都是扛住真实流量的必修课。
1. 打好 Dockerfile 地基
FROM python:3.13-slim AS base
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
WORKDIR /app
FROM base AS deps
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
FROM base
COPY --from=deps /install /usr/local
COPY . .
RUN useradd -r app && chown -R app /app
USER app
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
slim 基础镜像、多阶段构建、非 root 运行——地基三件套一次到位。
2. 配置全部外置
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
database_url: str
secret_key: str
debug: bool = False
model_config = SettingsConfigDict(env_file=".env")
settings = Settings()
镜像里零密钥,dev/staging/prod 共用一份镜像。Pydantic Settings 顺带把类型校验也做了。
3. 健康检查
@app.get("/health/live")
def live():
return {"status": "ok"}
@app.get("/health/ready")
def ready():
# 局部片段:engine 为项目的 SQLAlchemy Engine
with engine.connect() as conn:
conn.execute(text("SELECT 1")) # 需 from sqlalchemy import text
return {"status": "ready"}
liveness 探活、readiness 探可服务——编排系统据此决定重启与摘流量,滚动发布不断线就靠这对组合。
4. 吃透层缓存
requirements.txt 先于源码 COPY:依赖不变时构建秒完。.dockerignore 排除 .git、__pycache__、测试目录、.env 和私钥,上下文小了传输也快。CI 里开 BuildKit 缓存挂载,已有缓存可减少重复下载,首次冷构建不保证提速。
5. 数据库连接与迁移
- 连接池:
create_engine(url, pool_size=10, max_overflow=20),池子别超过数据库承受力; - 迁移:Alembic 迁移作为发布流水线的独立步骤(独立 K8s Job,避免每个 Pod 的 init 容器并发迁移),绝不由每个副本启动时抢跑;
- 启动重试:数据库未就绪时采用有上限的退避重试或由编排器重启,并保持 readiness 失败。
6. 日志配置
容器里常用的日志方式:结构化 JSON 写 stdout。
import logging, json, sys
handler = logging.StreamHandler(sys.stdout)
from pythonjsonlogger.json import JsonFormatter # 需安装 python-json-logger
handler.setFormatter(JsonFormatter())
logging.basicConfig(level="INFO", handlers=[handler])
uvicorn 的访问日志同样引到 stdout。用 DataKit 容器日志采集接入观测云时,先触发一次接口错误,核对应用日志与访问日志的时间、服务名和请求标识,确认没有重复采集。
7. 为水平扩展做准备
FastAPI 应用天然易扩——前提是保持无状态:
- 会话与缓存放 Redis,不放进程内存;
- 文件上传走对象存储,不落本地盘;
- 后台重任务丢任务队列,不卡 worker;
--workers数按 CPU 核数定,多副本优先于单副本多 worker(滚动更新更平滑)。
常见问题(FAQ)
Q:Uvicorn 还要不要前面架 Nginx?
A:容器编排环境下,Ingress/网关已承担 TLS 与路由,Uvicorn 直连通常足够;裸机部署则建议加一层 Nginx/Caddy 做 TLS 与限流。
Q:Gunicorn+Uvicorn worker 还是纯 Uvicorn 多进程?
A:两者都行。K8s 时代更推荐纯 Uvicorn 单进程 + 多副本,生命周期由编排系统统一管理。
Q:镜像里要装 curl 吗(健康检查用)?
A:尽量不装——slim 镜像里用 Python 一行或编排系统的 HTTP 探针即可。每多一个包都是攻击面。
官方参考
本文基于官方文档整理,未进行运行时或性能测试。示例中的业务函数、数据模型和部署地址需结合项目补全;局部片段不等同于完整生产应用。