Level 36 / 阅读练习

FastAPI 项目配置、多环境和部署上线

理解 .env、多环境配置、Docker Compose、Nginx、HTTPS、健康检查、日志和上线检查。

Progress

阅读中

0/2 步完成 / 阅读后完成练习才算通关

Practice

本关怎么过

  • 读完正文后确认完成阅读
  • 完成 1 道选择题练习
  • 答错时看解释,再回到正文补理解

一句话:多环境和部署上线就是让同一套 FastAPI 代码,在本地、测试环境、生产环境都能用正确配置稳定跑起来。

本篇学完你会什么:理解 .env、环境变量、dev/test/prod、Docker Compose、Nginx、HTTPS、健康检查、日志和上线前检查这些部署必备概念。

1. 为什么不能只会本地运行

本地运行通常是:

uvicorn app.main:app --reload

这只能说明代码能在你电脑上跑。

真实上线还要考虑:

数据库地址是不是生产库
JWT_SECRET 有没有换成强密钥
Redis 密码有没有配置
前端请求能不能转到后端
接口挂了有没有健康检查
日志去哪看
HTTPS 有没有配置

部署不是“把代码丢到服务器”,而是让服务在另一个环境里可重复、可检查、可恢复地运行。

<!-- image-slot: fastapi-env-deploy-flow; purpose: 展示 FastAPI 从本地环境到测试环境和生产环境的配置与部署路径; alt: FastAPI 多环境部署流程图 -->

2. 多环境到底是什么

常见三套环境:

环境 用途 特点
dev 本地开发 写代码、调试 可以热更新,数据可重建
test 测试环境 给自己或团队验证 接近生产,但允许重置
prod 生产环境 给真实用户使用 稳定、安全、可备份

同一套代码,配置不同:

配置 dev test prod
数据库 本地 Docker 测试库 生产库
Redis 本地 Redis 测试 Redis 生产 Redis
JWT_SECRET 开发密钥 测试密钥 强随机密钥
日志级别 debug info info/warning
CORS localhost 测试域名 正式域名

3. 配置应该怎么分

代码里放默认结构,环境变量里放真实值。

app/core/config.py

from pydantic_settings import BaseSettings


class Settings(BaseSettings):
    APP_ENV: str = "development"
    DATABASE_URL: str
    REDIS_URL: str
    JWT_SECRET: str
    CORS_ORIGINS: list[str] = []
    LOG_LEVEL: str = "INFO"

    class Config:
        env_file = ".env"


settings = Settings()

这里的 env_file = ".env" 可以先理解成本地兜底配置:你直接运行 uvicorn app.main:app --reload 时,应用会从 .env 读配置。

到了 Docker Compose 里,env_file: .env.prod 是 Compose 先读取 .env.prod,再把里面的值注入到容器环境变量里。Pydantic Settings 会优先读取真实环境变量,所以容器里拿到的是 Compose 注入的生产配置,而不是本地 .env

如果你想做得更严格,也可以用 ENV_FILE=.env.prod 这类变量动态决定加载哪个文件;本篇先用更容易理解的写法。

运行方式 配置来源 适合场景
本地直接 uvicorn 应用读取 .env 自己开发调试
Docker Compose 测试/生产 Compose 读取 .env.test.env.prod 后注入容器 接近真实部署
正式生产密钥 服务器环境变量或密钥管理服务 避免敏感信息落在仓库里

重点规则:

内容 能不能提交
.env.example 可以,放示例
.env 不要,放本地真实配置
.env.prod 通常不要提交,或只放在服务器安全位置
JWT_SECRET 不能用默认值
数据库密码 不能写死在代码里

4. .env.example.env.test.env.prod 怎么用

.env.example 给别人看需要哪些配置:

APP_ENV=development
DATABASE_URL=postgresql+asyncpg://postgres:password@localhost:5432/appdb
REDIS_URL=redis://localhost:6379/0
JWT_SECRET=change-me
CORS_ORIGINS=["http://localhost:3000"]
LOG_LEVEL=INFO

.env.test 可以接测试服务:

APP_ENV=test
DATABASE_URL=postgresql+asyncpg://postgres:testpass@test-db:5432/appdb
REDIS_URL=redis://test-redis:6379/0
JWT_SECRET=test-random-secret
CORS_ORIGINS=["https://test.example.com"]
LOG_LEVEL=INFO

.env.prod 放生产配置:

APP_ENV=production
DATABASE_URL=postgresql+asyncpg://app:strongpass@prod-db:5432/appdb
REDIS_URL=redis://:strongpass@prod-redis:6379/0
JWT_SECRET=very-long-random-secret
CORS_ORIGINS=["https://example.com"]
LOG_LEVEL=WARNING

大白话:.env.example 是清单,.env.prod 是钥匙。清单可以给别人看,钥匙不要乱放。

5. Docker Compose 怎么组织服务

一个后端常见需要:

api FastAPI 服务
db PostgreSQL
redis 缓存
nginx 反向代理

简化版:

services:
  api:
    build: .
    env_file:
      - .env.prod
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: app
      POSTGRES_PASSWORD: strongpass
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
      interval: 5s
      timeout: 5s
      retries: 10

  redis:
    image: redis:7-alpine

volumes:
  pgdata:

注意:生产环境数据库密码不要直接写在公开仓库里。这里是为了讲结构,真实项目要用服务器环境变量、密钥管理或安全的部署文件。

再记一次配置优先级:应用里的 .env 只是本地默认值;Docker Compose 的 env_file 会把变量放进容器环境,容器环境里的值会优先被读取。

6. Nginx 在前面做什么

Nginx 像门口接待员:

用户访问 https://example.com

Nginx 接住请求

/api 转给 FastAPI
静态页面直接返回

常见配置思路:

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

Nginx 常做:

能力 大白话
反向代理 把请求转给后端
静态资源 直接返回前端构建文件
HTTPS 处理证书
gzip 压缩响应
上传大小限制 控制大文件

7. HTTPS 和域名先理解什么

域名解决:

用户记 example.com,不用记服务器 IP

HTTPS 解决:

浏览器和服务器之间的数据加密传输

正式系统建议:

  1. 域名解析到服务器。
  2. Nginx 接收 80/443。
  3. 用证书启用 HTTPS。
  4. HTTP 自动跳转 HTTPS。

初学不用一开始深挖证书原理,先知道:登录、token、后台系统上线时应该用 HTTPS。

8. 日志和健康检查怎么做

健康检查接口:

@app.get("/health")
async def health():
    return {"status": "ok"}

更完整一点可以检查数据库:

@app.get("/health")
async def health(db: AsyncSession = Depends(get_db)):
    await db.execute(text("SELECT 1"))
    return {"status": "ok", "database": "ok"}

日志至少要记录:

日志 用途
启动日志 确认服务是否启动
请求错误 排查 500
登录失败 发现异常尝试
关键操作 谁修改了重要数据

不要打印:

明文密码
完整 token
身份证、手机号等敏感信息

9. 上线流程建议

最稳的顺序:

1. 本地跑通测试
2. 构建 Docker 镜像
3. 上传或拉取代码到服务器
4. 准备 .env.prod
5. docker compose config 检查配置
6. docker compose up -d 启动
7. 执行数据库迁移
8. 检查 /health
9. 检查 Nginx 代理
10. 检查前端页面和接口联调

上线后不要只看“容器启动了”。要真的访问:

/health
/docs 或关键接口
登录
用户列表
新增/编辑/删除

10. 常见错误

错误 后果 修正
生产还用默认 JWT_SECRET token 安全风险 使用强随机密钥
忘记执行 Alembic 接口报表不存在 上线时跑迁移
CORS 只配 localhost 正式域名请求失败 配正式域名
只看容器 running 实际接口可能 500 检查 /health 和关键接口
日志只打到容器里 排查困难 配日志输出和采集
数据库没挂 volume 容器重建数据丢失 使用持久化卷和备份

11. 上线检查清单

[ ] .env.prod 已准备且不提交到公开仓库
[ ] JWT_SECRET 是强随机值
[ ] DATABASE_URL 指向正确数据库
[ ] CORS_ORIGINS 包含正式域名
[ ] Alembic migration 已执行
[ ] /health 正常
[ ] Nginx /api 能转发到后端
[ ] HTTPS 正常
[ ] 数据库有持久化和备份方案
[ ] 登录、列表、新增、编辑、删除已验收

12. 总结表

名词 大白话
多环境 同一套代码用不同配置运行
.env.example 配置清单
.env.prod 生产钥匙
Docker Compose 一张服务启动清单
Nginx 入口和反向代理
HTTPS 加密访问
健康检查 判断服务是否活着
migration 数据库结构升级记录
volume 容器数据持久化

上一篇建议:大白话讲解——SQLAlchemy 关系查询和性能优化.md

下一篇建议:大白话讲解——AI 应用里的 RAG 知识库实战.md

Checkpoint

读完后做题闯关

读完后做选择题检验理解,答错会显示解释。

0/1
先完成阅读

读完正文后点击“我已读完,进入练习”,题目会变成可答状态。

第 1 题

读完这一篇后,最适合怎么确认自己真的理解了?