Files
xiaoxia-saas/docs/PRODUCTION-RELEASE-CHECKLIST.md

214 lines
9.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Production Release Checklist
小虾 SaaS 生产发布前必须逐项确认。本清单用于首次生产 Alembic 接入和后续 `v*` tag 发布。
## 1. 发布前冻结
- 确认目标 commit 已在 `develop` 部署到 staging,并完成 smoke。
- 确认 staging `/health` healthy。
- 确认 staging `alembic_version` 等于当前 head。
- 确认 CI validate job 通过:format、lint、Bandit、Alembic offline SQL、schema metadata drift、pytest。
- 确认没有未提交的 schema 变更:models、Alembic revision、schema snapshot 必须一起提交。
## 2. 生产环境检查
- `/var/lib/xiaoxia-saas-production/.env` 存在且权限正确。首次初始化必须使用非部署脚本生成独立 production env
```bash
scripts/init_production_env.sh
```
脚本只创建目录和 `.env`,不会启动应用容器;生成后必须人工替换 `CHANGE_ME_PRODUCTION_DB_PASSWORD`,并确认生产 DB/Redis 使用 `xiaoxia-postgres-production` / `xiaoxia-redis-production`,不得复用 staging 的 `xiaoxia-postgres` / `xiaoxia-redis`
生产基础设施使用独立 compose project 和端口:
- Postgres`xiaoxia-postgres-production`,宿主端口 `5433`
- Redis`xiaoxia-redis-production`,宿主端口 `6380`
- API 预留端口:`8001`
- Web 预留端口:`3002``3000` 已被 Gitea 占用)。
- `APP_ENV=production`
- `DEBUG=false`
- `AUTO_CREATE_SCHEMA=false`
- `JWT_SECRET_KEY` 已替换为生产强密钥。
- `DATABASE_URL` 指向生产数据库。
- `REDIS_URL` 指向生产 Redis。
- OSS 配置已确认或明确保持本地 fallback。
- `GENERATED_FILES_HOST_DIR` 生产环境不得指向 staging 目录。
- 本地校验文件:`python scripts/validate_release_env.py /var/lib/xiaoxia-saas-production/.env --strict-external`SMTP 仅在 `ENABLE_EMAIL_DELIVERY=true` 时强制)。
- 容器内校验已注入环境:`docker exec xiaoxia-api-production python /app/scripts/validate_release_env.py --from-environ --strict-external`SMTP 仅在启用邮件时强制)。
- 外部服务 smoke`docker exec xiaoxia-api-production python /app/scripts/smoke_external_services.py --strict --skip-smtp`SMTP 未启用时)。
- SMTP 真发信 smoke(启用邮件前必须执行):`docker exec xiaoxia-api-production python /app/scripts/smoke_external_services.py --strict --send-email-to <测试邮箱>`
- 如开启邮件/session
- `ENABLE_EMAIL_DELIVERY=true` 前先验证 SMTP 凭证。
- `ENABLE_REDIS_SESSIONS=true` 前先验证 Redis 连通性。
## 3. 数据库备份
生产 Alembic 升级前必须创建数据库备份。优先使用脚本:
```bash
BACKUP_ROOT=/root/xiaoxia-backups \
POSTGRES_CONTAINER=xiaoxia-postgres \
POSTGRES_USER=xiaoxia \
POSTGRES_DB=xiaoxia_saas \
scripts/backup_postgres.sh
```
脚本会输出备份目录,并写入 `manifest.txt``alembic_version.txt`
手动等价命令:
```bash
BACKUP_DIR=/root/xiaoxia-backups/$(date +%Y%m%d-%H%M%S)
mkdir -p "$BACKUP_DIR"
docker exec xiaoxia-postgres pg_dump -U xiaoxia -d xiaoxia_saas -Fc > "$BACKUP_DIR/xiaoxia_saas.dump"
docker exec xiaoxia-postgres psql -U xiaoxia -d xiaoxia_saas -Atc 'select version_num from alembic_version;' > "$BACKUP_DIR/alembic_version.txt" 2>/dev/null || true
```
确认备份非空:
```bash
test -s "$BACKUP_DIR/xiaoxia_saas.dump"
ls -lh "$BACKUP_DIR"
```
## 4. 首次 Alembic 接入判断
发布前只读检查生产库状态:
```bash
docker exec xiaoxia-api-production python /app/scripts/alembic_preflight.py
```
也可手动检查:
```bash
docker exec xiaoxia-postgres psql -U xiaoxia -d xiaoxia_saas -Atc "select to_regclass('public.alembic_version');"
docker exec xiaoxia-postgres psql -U xiaoxia -d xiaoxia_saas -Atc "select count(*) from pg_tables where schemaname='public' and tablename != 'alembic_version';"
```
脚本 `recommended_action` 判断规则:
- 已存在 `alembic_version`:执行 `alembic upgrade head`
- 有业务表但没有 `alembic_version`:先执行 `alembic stamp head`,再执行 `alembic upgrade head`
- 空库:执行 `alembic upgrade head`
生产首次接入不允许使用 `Base.metadata.create_all()` 或历史 SQL 快照。
## 5. 生产外部服务验证
上线前必须完成真实凭证 smoke,不能用 no-op 结果替代:
```bash
docker exec xiaoxia-api-production python /app/scripts/validate_release_env.py --from-environ --strict-external
docker exec xiaoxia-api-production python /app/scripts/smoke_external_services.py --strict --skip-smtp
docker exec xiaoxia-api-production python /app/scripts/smoke_external_services.py --strict --send-email-to <测试邮箱>
```
Staging 当前验证状态(2026-06-21):
- Redis session smoke:通过。
- SMTP strict smokeMVP 阶段允许 `--skip-smtp`,但启用 `ENABLE_EMAIL_DELIVERY=true` 前必须补真实 SMTP 凭证和真发信 smoke。
- OSS strict smoke:阻塞,缺少 OSS 环境变量/真实凭证。
缺少真实 OSS 凭证时不得把生产上传作为已验收项。SMTP 若暂不启用,必须保持 `ENABLE_EMAIL_DELIVERY=false` 并在 strict smoke 中显式使用 `--skip-smtp`
## 6. OSS 生命周期与生成文件保留
Production 推荐使用 OSS lifecycle rule 管理生成文件,不建议长期依赖本地 fallback。
建议策略:
- 临时/失败任务产物:7 天后删除。
- 已完成但未购买/未收藏产物:按产品套餐定义保留期。
- 已购买/订单关联产物:按订单合规要求保留,不由通用 cleanup 删除。
- 本地 fallback:每日 dry-run,每周人工复核后 `--apply`,并配置磁盘告警。
本地 fallback dry-run
```bash
python scripts/cleanup_generated_files.py --dir /var/lib/xiaoxia-saas-production/generated --days 7
```
确认后执行:
```bash
python scripts/cleanup_generated_files.py --dir /var/lib/xiaoxia-saas-production/generated --days 7 --apply
```
OSS 生命周期规则必须在云控制台或 IaC 中绑定到生产 bucket,并在发布记录里写明 rule id。
## 7. 发布执行
- 只能通过 `v*` tag 触发 production deploy。
- 生产 API/Worker 必须使用预构建 runtime image tar,不允许生产机临时 build。
- 生产 Web 必须使用预构建 `apps/web/dist`,不允许生产机运行 `npm`/Node build。
- 当前标准链路:
1. 推送 `v*` tag。
2. Gitea `build-production-runtime-images` job 在 `runtime-builder` 上运行。
3. `runtime-builder` 执行 `scripts/build_release_images.sh <tag>` 生成 `runtime-images-<tag>.tar`
4. `runtime-builder` 用 Node Docker 容器构建 `apps/web/dist`
5. `runtime-builder` 打包 `release-<tag>.tar.gz`,必须保留 `apps/web/dist/index.html`,同时排除根目录 `./dist`,避免把 runtime tar 再包进 release tar。
6. `runtime-builder` 上传两个产物到生产:
- `/var/lib/xiaoxia-saas-production/runtime-images-<tag>.tar`
- `/var/lib/xiaoxia-saas-production/release-<tag>.tar.gz`
7. Gitea `deploy-production` job 也在 `runtime-builder` 上运行,通过 SSH 驱动生产机部署。
8. SSH 部署必须传 `HOST_PREFIX=`,因为 `infra/docker/deploy-production.sh` 默认 `/host` 是给 Docker-in-Docker CI 场景用的。
9. 生产机只解包 artifact、复制 `.env``docker load` runtime images、运行 Alembic、重启容器和 health check。
- 发布期间持续观察 Gitea Actions deploy log。
- 部署后确认:
```bash
curl -fsS http://127.0.0.1:8001/health
docker ps --format '{{.Names}} {{.Image}} {{.Status}}' | grep xiaoxia
docker exec xiaoxia-postgres-production psql -U xiaoxia -d xiaoxia_saas -Atc 'select version_num from alembic_version;'
ls -lh /var/lib/xiaoxia-saas-production/runtime-images-<tag>.tar /var/lib/xiaoxia-saas-production/release-<tag>.tar.gz
```
- 缺少 runtime image tar、release tar 或 `apps/web/dist/index.html` 时,生产部署必须失败,禁止静默复用旧镜像或在生产机补 build。
- `v0.1.6``v0.1.7``v0.1.8` 是 release-chain 修复过程中的失败/中间态 tag,不作为回滚目标;当前可用回滚基准是已验证的 `v0.1.5``v0.1.9`
## 8. Smoke 测试
生产发布后至少验证:
- `/health` 返回 healthy。
- 注册/登录/`/auth/me` 正常。
- 创建 workspace 正常。
- 核心视频生成链路可创建任务。
- 生成文件下载 URL 返回真实文件,不返回前端 HTML fallback。
## 9. 回滚策略
生成恢复计划(不会自动恢复数据库):
```bash
scripts/restore_postgres_plan.sh /root/xiaoxia-backups/<backup-dir>
```
应用回滚:
- 若数据库未发生不可逆迁移,优先回滚到上一稳定 tag 并重新部署。
- 保留当前失败容器日志后再回滚。
数据库回滚:
- Alembic downgrade 只有在 revision 明确支持且已验证时才能执行。
- 首次生产接入阶段默认使用备份恢复作为最终兜底。
- 恢复前必须二次确认备份路径、目标数据库、停机窗口。
- 恢复步骤必须先由 `scripts/restore_postgres_plan.sh` 生成并复核,不允许紧急状态下即兴拼命令。
## 10. 发布记录
每次生产发布后,在 `docs/PHASE7-PROGRESS.md` 或对应 release note 记录:
- tag
- commit
- Alembic before/after version
- backup path
- smoke 结果
- OSS lifecycle rule id / 本地 cleanup 结果