Skip to content

39. FastAPI 部署和执行 ​

部署让程序持续、可观测地提供服务 ​

本机能启动只是第一步。部署还要处理依赖复现、进程重启、HTTPS、代理、数据库迁移、日志、健康检查和回滚。先让单进程可靠运行,再按实际负载增加进程或实例。

以下默认使用第 29 篇的 app/main.py 入口;单文件练习把 app.main:app 换成 main:app。

开发与生产启动 ​

powershell
# 开发:自动重载,只监听本机。
uv run uvicorn app.main:app --reload --host 127.0.0.1 --port 8000

# 生产启动示例:先在交付目录同步已审核锁文件。
uv sync --locked --no-dev
uv run --no-sync uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 2

生产关闭 reload。不要同时使用 reload 与多 worker。0.0.0.0 只代表监听网卡,公网访问仍受网络路由、防火墙和安全组影响;浏览器用实际域名或 IP。

Uvicorn 多进程可在支持的平台上运行;启动必须使用可导入的模块路径。若在 Python 代码里调用 uvicorn.run(..., workers=...),需按要求放在 if __name__ == "__main__": 保护下。

多进程带来的实际变化 ​

每个 worker 都有自己的内存、应用生命周期和连接池。内存字典、聊天室房间、演示后台任务状态不会自动共享。第 37、38 篇的内存状态示例必须单进程运行,或先改成数据库、Redis、可靠队列。

每进程 MySQL 最大连接数若为 15,两个 worker 就可能使用 30 个,再加迁移、队列和其他服务。worker 数量应结合 CPU、内存、I/O 和数据库上限实测,不照抄固定公式。

容器化的最小流程 ​

在项目根目录先导出当前锁文件的运行依赖:

powershell
uv export --frozen --no-dev --no-emit-project --output-file requirements.txt

创建 Dockerfile,本例针对没有额外系统依赖的纯 Python 工程:

dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY app ./app
RUN useradd --create-home appuser
USER appuser
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

.dockerignore 排除 .git、.venv、.env、缓存和本地上传文件。构建前重新导出依赖;正式发布还应固定并维护基础镜像版本或摘要。

powershell
docker build -t fastapi-study:1.0 .
docker run --rm -p 8000:8000 --env-file .env fastapi-study:1.0

镜像不内置真实密钥;生产由运行平台注入配置。非 root 用户不能随意写 /app,上传和导出应挂载具有适当权限的持久目录或使用对象存储。容器内 127.0.0.1 指当前容器,不是宿主机或另一个 MySQL 容器。

反向代理、HTTPS 与长连接 ​

生产常见结构:客户端 → HTTPS 代理或负载均衡 → Uvicorn → 数据库。HTTPS 可在代理终止,内部网络访问按部署边界控制。

下面是 Nginx 的片段示意,不是含证书和站点配置的完整文件。map 放在 http 上下文;location 放在实际 server 中:

nginx
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

# 放入 server 块:普通 HTTP 与 WebSocket。
location / {
    proxy_pass http://127.0.0.1:8000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_read_timeout 300s;
}

# SSE 单独关闭缓冲;按实际接口路径调整。
location /chat/stream {
    proxy_pass http://127.0.0.1:8000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_buffering off;
    proxy_read_timeout 300s;
}

只在应用实际处于可信代理后时启用并限制转发头信任来源。公网客户端不能直接伪造真实 IP 或协议。反向代理若移除路径前缀,还要正确配置 root_path 与文档地址;不能靠随意改路由修补。

迁移、启动与回滚顺序 ​

  1. 备份并确认数据库恢复方案,审核 Alembic 迁移。
  2. 在独立发布步骤运行迁移,避免每个 worker 同时建表或改表。
  3. 启动新版本,验证健康检查、登录、数据库读写和长连接。
  4. 逐步切流量,观察错误率、延迟、连接池和资源占用。
  5. 异常时回滚应用;数据库结构变更不一定能直接逆转,应设计前后版本兼容窗口。

进程由容器编排平台、systemd 或合适的服务管理器负责重启,不能长期依赖一个手工打开的终端。停止时留出优雅退出时间;WebSocket 和长流连接还需安排重连与最大持续时长。

健康与日志 ​

存活探针回答进程是否活着;就绪探针回答能否接收业务,必要时检查关键依赖。避免每秒探针都做昂贵全表查询。日志写标准输出,包含请求 ID、路径、状态和耗时;指标至少观察错误率、延迟、数据库连接、任务积压。

练习:本机以生产命令运行,关闭进程后验证服务管理器是否恢复;容器中测试健康接口;检查 WebSocket、SSE 是否经过代理后仍能正常持续通信。