FastAPI: 项目部署与上线 — 从开发到生产

最后更新:2026-08-26

上线就像火箭发射——前 24 课是设计和制造,这一课是倒计时和发射。发射前有一长串检查清单,每项打勾才能点火。没有检查清单的发射,叫赌博。

1. 你将学到


2. Alice 的真实故事

(1) 痛点:上线事故频发

PriceTracker 前两次上线都出了事故:第一次忘记配 HTTPS,第二次数据库迁移锁表导致服务中断 10 分钟,第三次日志没聚合,出问题后 Charlie 花 2 小时在 5 台服务器上翻日志。Alice 需要一份系统化的上线流程,确保每次上线安全可控。

(2) 上线 Checklist 的解法

上线不是"代码推上去就完事",而是一系列检查清单:安全加固、性能验证、迁移策略、灰度发布、监控确认——每一步打勾后才进入下一步。

(3) 收益

第三次上线 Checklist 全部打勾,HTTPS 配好、迁移零停机、灰度发布先切 10% 流量验证、日志自动聚合到 Loki——上线全程 0 事故,Charlie 的监控大屏全程绿灯。


3. 生产环境 Checklist

(1) 上线流程

100%
flowchart TD
    A[Code Freeze] --> B[Security Audit]
    B --> C[Load Test]
    C --> D[Staging Deploy]
    D --> E[Smoke Test]
    E --> F[Canary Release 10%]
    F --> G{Metrics OK?}
    G -->|Yes| H[Full Rollout 100%]
    G -->|No| I[Rollback]
    I --> J[Investigate]
    J --> A
    H --> K[Monitor 1h]
    K --> L[✓ Live]

(2) 三维度 Checklist

维度 检查项 状态
安全 HTTPS 证书配置
CORS 仅允许生产域名
Rate Limiting 启用
JWT SECRET_KEY 已更换
无硬编码密钥
安全扫描通过
性能 Uvicorn Workers ≥ 4
DB 连接池大小合理
Redis 缓存启用
GZip 压缩启用
负载测试通过(目标 QPS)
监控 /health 端点正常
Prometheus 采集指标
Grafana Dashboard 就绪
告警规则配置
日志聚合运行

4. 灰度发布策略

(1) 蓝绿部署

100%
flowchart LR
    LB[Load Balancer] -->|100% traffic| Blue[Blue v1]
    
    subgraph Deploy
        Green[Green v2]
    end
    
    LB -.->|Switch| Green
    
    style Blue fill:#4caf50
    style Green fill:#2196f3
步骤 操作 回滚
1 部署 Green(v2)环境 -
2 在 Green 运行冒烟测试 -
3 LB 切换到 Green 切回 Blue
4 监控 Green 30 分钟 切回 Blue
5 确认稳定,下线 Blue -

▶ 示例:Nginx 蓝绿配置

NGINX
# nginx/conf.d/pricetracker.conf
upstream pricetracker_blue {
    server api-blue:8000;
}

upstream pricetracker_green {
    server api-green:8000;
}

# Currently serving Blue
server {
    listen 80;
    server_name api.pricetracker.example.com;

    location / {
        proxy_pass http://pricetracker_blue;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# Switch to Green by changing proxy_pass target
# Then: docker compose -f docker-compose.green.yml up -d

输出:

TEXT 📖 仅展示
// 执行成功

(2) 金丝雀发布

策略 流量分配 观察时间 回滚
10% 1 v2 + 9 v1 15 min 切回 v1
30% 3 v2 + 7 v1 15 min 切回 v1
50% 5 v2 + 5 v1 15 min 切回 v1
100% 全部 v2 30 min 回滚镜像版本

5. 零停机数据库迁移

(1) 安全迁移原则

原则 说明 示例
只加不删 先加新列,不删旧列 ALTER TABLE ADD COLUMN new_col
双写兼容 新旧代码都能工作 新代码写两列,旧代码只读旧列
延迟清理 确认稳定后再删旧列 部署 v2 后 7 天删旧列
小步迁移 每次只改一个东西 不在一个迁移中又加列又改类型

▶ 示例:安全添加列迁移

PYTHON
# alembic/versions/xxx_add_wholesale_price.py
"""Add wholesale_price column to products

Safe migration: ADD COLUMN is non-blocking in PostgreSQL
"""

def upgrade():
    op.add_column(
        "products",
        sa.Column("wholesale_price", sa.Float(), nullable=True),
    )
    # Set default for existing rows (separate statement for performance)
    op.execute("UPDATE products SET wholesale_price = base_price * 0.6 WHERE wholesale_price IS NULL")
    # Make non-nullable in next migration after code deployed

def downgrade():
    op.drop_column("products", "wholesale_price")

输出:

TEXT 📖 仅展示
# 函数定义成功

(2) 危险迁移 vs 安全迁移

迁移类型 安全性 锁表风险 建议
ADD COLUMN 安全 可在线执行
CREATE INDEX 较安全 可能 CREATE INDEX CONCURRENTLY
DROP COLUMN 危险 先确保代码不再使用
ALTER COLUMN TYPE 危险 分步迁移(加新列→迁移数据→删旧列)
RENAME COLUMN 危险 双写兼容后再改名

6. 日志聚合

(1) 结构化日志

▶ 示例:结构化日志配置

PYTHON
# app/core/logging.py
import logging
import json
from datetime import datetime

class JSONFormatter(logging.Formatter):
    def format(self, record):
        log_entry = {
            "timestamp": datetime.utcnow().isoformat(),
            "level": record.levelname,
            "message": record.getMessage(),
            "module": record.module,
            "function": record.funcName,
            "line": record.lineno,
        }
        # Add request context if available
        if hasattr(record, "request_id"):
            log_entry["request_id"] = record.request_id
        if hasattr(record, "user_id"):
            log_entry["user_id"] = record.user_id
        return json.dumps(log_entry)

# Configure logging
logger = logging.getLogger("pricetracker")
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger.addHandler(handler)
logger.setLevel(logging.INFO)

输出:

TEXT 📖 仅展示
# 函数定义成功

(2) 日志聚合方案对比

方案 优点 缺点 推荐场景
ELK(Elasticsearch+Logstash+Kibana) 功能全、搜索强 资源消耗大 大型项目
Loki+Grafana+Promtail 轻量、与 Grafana 一体 搜索能力弱 中小项目
CloudWatch Logs 零运维 AWS 锁定 AWS 部署

▶ 示例:Docker Compose 添加 Loki

YAML
# Add to docker-compose.yml
  loki:
    image: grafana/loki:latest
    ports:
      - "3100:3100"
    volumes:
      - loki_data:/loki

  promtail:
    image: grafana/promtail:latest
    volumes:
      - /var/log:/var/log:ro
      - ./docker/promtail.yml:/etc/promtail/config.yml
    depends_on:
      - loki

输出:

TEXT 📖 仅展示
CONTAINER ID   IMAGE          STATUS         PORTS
abc123         nginx:latest   Up 2 hours     0.0.0.0:80->80/tcp

7. PriceTracker 正式上线

(1) 项目完成里程碑

100%
gantt
    title PriceTracker Development Timeline
    dateFormat  YYYY-MM-DD
    section Phase 1
    FastAPI Intro           :p1a, 2026-01-01, 1d
    Installation & UV       :p1b, after p1a, 1d
    Path & Query Params     :p1c, after p1b, 1d
    Request Body & Pydantic :p1d, after p1c, 1d
    Response Models         :p1e, after p1d, 1d
    Phase 1 Capstone        :p1f, after p1e, 2d
    
    section Phase 2
    Middleware               :p2a, after p1f, 1d
    Dependency Injection     :p2b, after p2a, 1d
    Database SQLAlchemy      :p2c, after p2b, 2d
    CRUD Operations          :p2d, after p2c, 1d
    Authentication JWT       :p2e, after p2d, 2d
    Phase 2 Capstone         :p2f, after p2e, 2d
    
    section Phase 3
    WebSocket                :p3a, after p2f, 1d
    Celery                   :p3b, after p3a, 2d
    File Upload              :p3c, after p3b, 1d
    Testing                  :p3d, after p3c, 1d
    Caching                  :p3e, after p3d, 1d
    OpenAPI                  :p3f, after p3e, 1d
    
    section Phase 4
    Docker                   :p4a, after p3f, 1d
    Performance              :p4b, after p4a, 1d
    Monitoring               :p4c, after p4b, 1d
    CI/CD                    :p4d, after p4c, 1d
    
    section Phase 5
    Project Design           :p5a, after p4d, 1d
    Project Development      :p5b, after p5a, 2d
    Project Deployment       :p5c, after p5b, 1d

(2) 上线验证清单

验证项 验证方式 通过标准
API 可用性 curl /health {"status": "healthy"}
前端对接 Bob 前端调 API 全部端点正常
认证 JWT 登录+受保护端点 登录成功,未认证返回 401
权限 Free/Pro/Enterprise 限流 按计划正确限制
WebSocket 连接+价格推送 实时收到变动
缓存 热门商品缓存命中率 > 80%
监控 Grafana Dashboard 指标正常显示
告警 模拟 P99 飙升 告警触发通知
日志 查询 Loki 结构化日志可搜索
CI/CD Tag 推送触发部署 自动部署成功

❓ 常见问题

Q 蓝绿部署需要双倍服务器吗?
A 是的,切换期间需要两套环境。K8s 环境可以用滚动更新替代,不需要双倍资源。
Q 金丝雀发布如何分配流量?
A Nginx 用 weight 参数(server v2:8000 weight=1; server v1:8000 weight=9;),K8s 用 canary Deployment 调整副本数。
Q 数据库迁移锁表怎么办?
ACREATE INDEX CONCURRENTLY(不锁表建索引),避免 DDL 在高峰期执行。大表迁移分批进行。
Q 结构化日志和普通日志有什么区别?
A 结构化日志是 JSON 格式,每条日志有固定字段(timestamp, level, message, request_id),机器可解析可搜索。普通日志是人读的文本,机器难以解析。
Q 上线后第一小时应该看什么?
A 看 Grafana Dashboard 的三个核心指标:QPS(是否正常)、P99 延迟(是否飙升)、错误率(是否 > 1%)。同时看日志聚合是否有异常 ERROR。
Q 回滚需要多长时间?
A Docker 回滚约 30 秒(切回旧版本镜像+重启)。数据库回滚取决于迁移复杂度,简单列删除秒级,复杂迁移可能需要数据修复。

📖 小节


📝 作业

  1. 基础题(难度⭐):创建 PriceTracker 上线 Checklist(安全/性能/监控三维度各 5 项),逐项验证你的部署环境。提示:参考本文 Checklist 表格
  2. 进阶题(难度⭐⭐):实现结构化 JSON 日志(含 timestamp/level/message/request_id),添加日志中间件为每个请求注入 request_id,配置 Docker Compose + Loki 聚合日志。提示:JSONFormatter + logging.getLogger("pricetracker")
  3. 挑战题(难度⭐⭐⭐):完整上线流程——编写安全迁移脚本(只加不删原则)、配置 Nginx 蓝绿部署、配置 Grafana 告警规则(P99>500ms + 错误率>5%)、执行灰度发布验证(先 10% 流量到 v2 再全量)。提示:CREATE INDEX CONCURRENTLY + Nginx upstream 切换

---| 返回目录

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏