开发与生产环境的差异
开发时一条命令 `uvicorn app.main:app --reload` 就能把服务跑起来,但生产环境要面对的是真实流量、宕机风险和运维边界。开发模式默认单进程、自动重载,方便改代码即时生效;生产模式要的是多进程、稳定运行、可观测和可回滚。
上线前首先要补几件基础能力:日志要有明确的格式和轮转、配置要与代码分离、进程要被守护、请求要有超时上限。缺少任何一项,服务一遇到流量峰值就容易出问题,而且出了问题还查不到原因。
FastAPI 本身只是 Web 框架,它不负责进程管理、不负责反向代理、也不负责容器打包。把这些能力组合起来,才构成完整的生产部署方案。下面按一条从开发机到生产服务器的路径,逐步把它搭起来。
部署的本质是把「能跑的代码」变成「能扛住流量、能查问题、能快速恢复的服务」。
- uvicorn多 worker 并发模型。
- Gunicorn成熟稳定的进程托管。
- Docker多阶段构建镜像。
- Nginx反向代理与 HTTPS。
uvicorn 多 worker 与进程模型
uvicorn 是 FastAPI 官方推荐的 ASGI 服务器。单 worker 只能用一个 CPU 核心,对现代多核服务器是浪费。加 `--workers` 参数就能起多个进程,每个进程各自处理请求,对外共享同一个端口。
uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
worker 数量一般按 CPU 核心数设定,常见做法是 2 到 4 倍核心数,视接口的 CPU 密集程度调整。进程之间不共享内存状态,需要共享的会话、计数等数据要放到 Redis 这类外部存储里,不能在进程内存里做文章。
多进程也意味着每个 worker 各自维护自己的日志和连接,排查问题时要注意把日志按 worker 维度聚合起来看。uvicorn 自带的 worker 管理比较简单,生产上更推荐交给 Gunicorn 托管。
Gunicorn 托管与配置
Gunicorn 是 Python 世界成熟的 WSGI 进程管理器,通过 `uvicorn.workers.UvicornWorker` 也能托管 ASGI 应用。它的优势是进程管理成熟:master 进程负责调度,worker 崩溃会自动重启,还能优雅处理信号。
| 配置项 | 含义 |
|---|---|
| workers | worker 进程数量 |
| timeout | worker 无响应超时(秒) |
| graceful_timeout | 优雅停机等待时间 |
| max_requests | 单个 worker 处理请求数上限 |
gunicorn app.main:app -k uvicorn.workers.UvicornWorker \
--workers 4 --timeout 60 --graceful-timeout 30 \
--max-requests 5000 --max-requests-jitter 500
`max_requests` 配合 jitter 可以让 worker 定期轮换,缓解内存缓慢增长的问题。配置写成文件放在仓库里,比命令行参数更可维护,也方便多环境复用。
Docker 镜像与多阶段构建
容器化让部署环境与代码一起交付,避免「在我机器上能跑」的问题。多阶段构建先用完整镜像安装依赖,再在精简运行镜像里只保留依赖和应用,显著缩小体积、减少攻击面。
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --prefix=/install -r requirements.txt
FROM python:3.12-slim
COPY --from=builder /install /usr/local
COPY . /app
WORKDIR /app
EXPOSE 8000
CMD ["gunicorn", "app.main:app", "-k", "uvicorn.workers.UvicornWorker", "-c", "gunicorn.conf.py"]
运行容器时要用 `--restart unless-stopped` 让 Docker 守护进程拉起异常退出的容器;镜像要打上版本标签而不是一律用 latest,回滚时才能精确切到上一个版本。
配置管理与密钥安全
数据库地址、密钥、令牌这些信息不能写死在代码里,也不能打进镜像。FastAPI 官方推荐用 Pydantic 的 BaseSettings 从环境变量读取配置,运行时再注入。
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
app_name: str = "demo"
database_url: str
secret_key: str
debug: bool = False
model_config = {"env_file": ".env"}
settings = Settings()
容器环境下通过 `-e` 参数或密钥管理服务注入环境变量,`.env` 文件只留在本地开发环境,绝不提交进仓库。日志里也不得打印密钥,避免敏感信息随日志外泄。
Nginx 反向代理与 HTTPS
生产环境通常不让用户直接访问应用端口,而是用 Nginx 做反向代理:Nginx 监听 80/443,把请求转发给内网的应用服务,同时承担静态资源、连接复用和 HTTPS 终结的职责。
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
配置好转发头之后,应用里要信任代理的转发头,否则拿到的客户端 IP 和协议都会失真。HTTPS 证书可以用 Let's Encrypt 免费签发并自动续期,这是成本最低的加密方案。
部署检查清单
- 多 worker 启动并确认进程数与预期一致。
- 健康检查接口可访问,监控探活能拿到状态。
- 日志按天轮转,访问日志与错误日志分开。
- 环境变量注入正确,密钥不落盘、不打印。
- HTTPS 证书有效,转发头配置无误。
- 镜像有版本标签,回滚路径演练过。
上线不是终点,能快速恢复才是。