12 KiB
宠小它生产发布与回滚 Runbook
版本:2026-08-01
适用范围:3~5 家独立宠物洗护单店试点;backend、admin、H5、微信小程序。
当前结论:仓库交付到
Ready for Release,未取得真实生产域名、凭据、备份和线上验收证据前,不得标记Released。
1. 发布原则
- 发布单元必须冻结为四元组:
backend commit + admin commit + frontend commit + docs/RC manifest commit,同时记录 jar/静态包校验和。 - 生产数据库只通过已审核 SQL 迁移;应用固定
ddl-auto=validate,禁止启动期改表或修复数据。 - 后端预检和自动 smoke 均为只读;创建预约、开始服务、提交报告等写路径只在明确指定的试点门店和人工验收窗口执行。
- 应用、静态站点采用版本目录加
current软链接切换;数据库迁移为向前兼容的追加式变更,不做自动向下迁移。 - Petstore 使用独立域名、Nginx
server块、systemd unit 和发布目录。不得覆盖、重启或复用同机 Gitea/GitLab 的配置与服务。 - 任何命令输出都不得包含数据库密码、微信 AppSecret、session secret、完整报告 token、手机号或私密媒体 URL。
2. 本次发布任务卡
| 字段 | 值 |
|---|---|
| Task Name | 建立可重复的生产发布与回滚闭环 |
| Role | Backend Ops / Frontend Release Ops |
| Owner Agent | Backend Ops(后端与 Nginx)/ Frontend Release Ops(admin、H5、小程序) |
| Paired QA | Core Flow QA / Report Share QA |
| Workstream | Release |
| Track | Ops |
| Status | Ready for Release(生产证据待补) |
| Priority | P0 |
| Repo/Path | backend/deploy/**、前端发布配置、docs/** |
| Service Lock | Petstore backend unit + Petstore 专用 Nginx server blocks + Petstore static roots |
| Depends On | 冻结 RC、真实域名/TLS、备份、五个迁移、微信合法域名 |
| Acceptance | 预检、构建、readiness、只读 smoke、三角色人工 smoke、回滚演练均有证据 |
| RC Included | Yes |
| Due Date | TBD |
| Output Link | 当前 Runbook + RC manifest |
| Blocker Owner | 生产环境负责人(域名/凭据/变更窗口) |
| Commit / RC | Not Frozen,提交后写入 RC manifest |
| Architecture Review Required | Yes |
| Data Model Review Required | Yes(迁移顺序与回滚边界) |
| Access / Privacy Review Required | Yes |
3. 立即停止条件
出现任一情况立即停止,不继续切流:
- 四仓 commit、构建产物或校验和与 RC manifest 不一致;
- 生产域名仍为 localhost、
.invalid、api.s-good.com或www.s-good.com等非本项目域名; - 数据库备份未完成、校验和缺失或未在隔离库验证可恢复;
- 任一迁移末尾验证查询非 0,或预检的 18 项只读不变量非 0;
nginx -t失败,或 diff 显示将修改 Gitea/GitLab 的 server block;- readiness 非
UP,上传目录/FFmpeg/数据库任一依赖失败; - 发现凭据、完整 token、手机号或私密媒体地址进入日志/工单/截图;
- 无明确值班人、回滚执行人或生产变更授权。
4. 发布前冻结
RC Steward 在 docs/qa-reports 创建当次 manifest,至少记录:
- 四仓 commit、分支、
git status --short(必须为空); - Java/Node/npm/Maven 版本;
- jar、admin
dist、H5dist、小程序构建目录的 SHA-256; - 目标环境、变更窗口、操作者、审核人;
- 本次包含/排除项、已知风险、旧版本回滚点;
- 域名只记 host,不记 query/token;配置只记变量名和“已配置”,不记值。
冻结后重新运行本地门禁:
cd /Users/apple/_src/petstore/backend
mvn test
mvn -DskipTests package
bash -n deploy/release-preflight.sh deploy/production-smoke.sh
cd /Users/apple/_src/petstore/admin
npm run build
cd /Users/apple/_src/petstore/frontend
npm run build:h5
npm run build:mp-weixin
cd /Users/apple/_src/petstore
python3 docs/graph/validate_ontology.py docs
python3 docs/graph/audit_drift.py
5. 数据库备份与迁移
5.1 备份证据
使用权限受控的 MySQL option file,避免把密码写在命令行。备份必须包含表结构、数据、触发器、事件和存储过程,并记录文件大小、SHA-256、开始/结束时间。示例:
mysqldump --defaults-extra-file=/secure/path/petstore-mysql.cnf \
--single-transaction --routines --triggers --events --hex-blob \
petstore > /secure/backup/petstore-before-<rc>-<timestamp>.sql
shasum -a 256 /secure/backup/petstore-before-<rc>-<timestamp>.sql
上线前必须把该备份恢复到隔离数据库并完成基础计数核对;“命令退出 0”不能替代恢复演练。备份保留周期由数据负责人决定,本流程不自动删除任何备份。
5.2 固定迁移顺序
在维护窗口中按以下顺序人工执行,每一步都保存执行时间和脚本 SHA-256,并检查脚本末尾验证查询:
backend/db/migrations/20260801_split_service_identity.sqlbackend/db/migrations/20260801_create_store_customer.sqlbackend/db/migrations/20260801_create_business_event.sqlbackend/db/migrations/20260801_create_booking_capacity.sqlbackend/db/migrations/20260801_create_report_send_status.sql
禁止跳步、交换顺序或让应用自动补表。任一验证项非 0,停止发布并由 Data Model/业务 owner 判断修复方案;不得猜测性回填客户身份、报告作者或事件。
5.3 生产只读预检
把 backend/deploy/petstore-backend.env.example 复制到服务器权限受控的 /etc/petstore/backend.env 并填入真实值;文件权限建议 0600,所有者为服务账号。不要在交互 shell 中 source 该文件,也不要用 env $(cat ...),避免特殊字符被 shell 解释或泄露。通过一次性 systemd unit 以与正式服务相同的 EnvironmentFile 和服务账号执行:
systemd-run --wait --pipe --collect \
--unit=petstore-preflight-<rc> \
--property=Type=oneshot \
--property=User=petstore \
--property=Group=petstore \
--property=WorkingDirectory=/opt/petstore/backend/releases/<rc> \
--property=EnvironmentFile=/etc/petstore/backend.env \
/usr/bin/env BUILD_FIRST=0 \
JAR_PATH=/opt/petstore/backend/releases/<rc>/petstore-backend.jar \
./deploy/release-preflight.sh
通过条件:静态配置检查通过、JPA validate 通过、18 项数据不变量全部为 0,并以退出码 0 结束。预检不会执行迁移或修复数据。
6. 构建发布产物
6.1 后端
将已冻结 jar 放入 /opt/petstore/backend/releases/<rc>/petstore-backend.jar,同时归档 commit、SHA-256 和 deploy/ 模板。systemd unit 以 backend/deploy/petstore-backend.service.example 为基线,由服务器管理员安装为 Petstore 独立 unit。
6.2 Admin 与 H5
真实域名配置保存在权限受控文件,不提交仓库。门禁和构建必须使用同一份内容:
cd /opt/build/petstore/admin
PETSTORE_ADMIN_ENV_FILE=/secure/path/petstore-admin.env npm run preflight:release
cp /secure/path/petstore-admin.env .env.production.local
npm run build
cd /opt/build/petstore/frontend
PETSTORE_FRONTEND_ENV_FILE=/secure/path/petstore-h5.env npm run preflight:release
cp /secure/path/petstore-h5.env .env.production.local
npm run build:h5
产物进入版本目录后再切换 current 软链接。构建结束应清除工作区内临时 .env.*.local,但保留受控配置源和构建证据。
6.3 微信小程序
cd /opt/build/petstore/frontend
PETSTORE_FRONTEND_ENV_FILE=/secure/path/petstore-mp.env npm run preflight:release
cp /secure/path/petstore-mp.env .env.mp-weixin.local
npm run build:mp-weixin
微信公众平台的 request / downloadFile 合法域名必须与门禁通过的实际域名一致。先上传体验版并完成真机三角色验收,再决定提审/发布;后端或 H5 发布不会自动更新用户手机里的小程序。
7. 切换应用与 Nginx
- 将后端
current指向新版本目录,执行systemctl daemon-reload,只重启 Petstore 独立 unit。 - 确认进程稳定并通过本机 readiness,再切 admin/H5 静态目录
current。 - 以
backend/deploy/nginx-petstore.conf.example新建 Petstore 专用配置文件;替换域名、证书路径和静态根目录。 - 执行
nginx -t。检查配置 diff 仅增加/修改 Petstore 的三个 server block,不改 Gitea/GitLab upstream、端口、证书和 location。 - 只执行 Nginx reload,不停止 Nginx;reload 后同时检查 Petstore、Gitea、GitLab 的既有健康入口。
证书续签必须沿用服务器现有 ACME/证书管理方式,为 Petstore 新域名单独申请/续签;不要替换其他产品证书。续签后先 nginx -t 再 reload,并记录证书到期时间。
8. 上线验证
8.1 自动只读 smoke
cd /opt/petstore/backend/current
API_ORIGIN=https://<api-domain> ./deploy/production-smoke.sh
脚本验证 liveness、readiness、公开门店、服务时长和可约容量契约;提供受控的 SMOKE_BEARER_TOKEN 时才增加两个 protected GET。脚本不会创建或修改业务数据。
8.2 三角色人工 smoke
仅在预先标记的试点门店和测试宠主上执行,记录匿名化预约 ID/报告 ID,不记录完整 token/手机号:
- boss:登录 admin,核对门店营业时段、并发容量、服务时长;创建员工;查看工作台、客户、日程。
- staff:代客预约,开始服务,上传最小合规素材,提交一约一报告,复制报告话术;确认重复提交被拒绝。
- customer:小程序自助预约并验证长服务跨时段占号;打开匿名报告页;提交提醒留资;再次预约。
- 权限反例:customer 不可进入后台;A 店账号不可读取 B 店预约/报告/线索;公开报告响应不含内部身份字段。
- 异常反例:无容量、非法状态迁移、缺前/后照片、错误 token、FFmpeg 失败均有可理解提示。
9. 回滚
9.1 应用与静态资源回滚
- 保留前一版本目录和软链接目标。若新版本 readiness、错误率或主链路失败,先停止切流,把 backend/admin/H5 的
current恢复到 RC manifest 中的前一版本,再只重启 Petstore unit、nginx -t并 reload。 - 微信小程序不能靠服务器软链接回滚。应在公众平台保留上一稳定版本,按微信流程回退;同时确认其 API 契约仍受当前后端兼容。
- 回滚后重新执行只读 smoke,并记录故障窗口、影响门店、回滚时间和 owner。
9.2 数据库回滚边界
本批五个迁移以新增列/表/索引和兼容回填为主,旧应用应忽略新增结构。因此常规回滚只回应用,不删除列、表、索引,不执行自动 down migration,也不把已产生的新业务数据覆盖回旧备份。
只有确认发生灾难性数据破坏、已冻结所有写入、明确接受备份时间点之后的数据丢失,并取得用户/业务负责人、DBA 和隐私责任人的书面授权后,才可执行整库恢复。恢复必须先在隔离库验证,再制定专门变更单;本 Runbook 不授权该操作。
10. 发布完成定义
只有以下证据全部归档,RC 才能由 Ready for Release 改为 Released:
- 四仓冻结 commit 与产物校验和;
- 备份及隔离恢复验证;
- 五个迁移执行和末尾验证结果;
- 最终配置门禁与后端只读预检;
nginx -t、readiness、自动只读 smoke;- boss/staff/customer 三角色人工 smoke;
- Gitea/GitLab 回归未受影响;
- 监控、告警联系人、回滚点和值班窗口;
- 未解决问题清单及 Go/No-Go 决策人。