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 有没有配置部署不是“把代码丢到服务器”,而是让服务在另一个环境里可重复、可检查、可恢复地运行。
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,不用记服务器 IPHTTPS 解决:
浏览器和服务器之间的数据加密传输正式系统建议:
- 域名解析到服务器。
- Nginx 接收 80/443。
- 用证书启用 HTTPS。
- 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 | 容器数据持久化 |
Checkpoint
读完后做题闯关
先读正文,再用下面的选择题检查自己是否真的理解。答错会出现解释,可以回到正文补一眼再重选。
读完正文后点击“我已读完,进入练习”,题目会变成可答状态。