fix: 隔离既有发布的数据库容器生命周期(09-05-existing-deploy-db-lifecycle-isolation)
这个提交包含在:
@@ -0,0 +1,60 @@
|
||||
# 既有环境应用发布隔离数据库容器生命周期
|
||||
|
||||
## Goal
|
||||
|
||||
既有环境发布应用时,发布链路不得显式或经 Compose 依赖传播启动、停止、重建、替换或删除数据库容器。保留首次初始化的数据库启动能力,以及获批发布中的既有迁移、seed 和发布验证流程。保护对象是数据库容器生命周期,不将本任务宣称为数据库内容完全只读或所有数据丢失风险的解决方案。
|
||||
|
||||
## Background
|
||||
|
||||
- 基线:`05d2a3f`。用户报告曾在应用发布时误重建生产数据库容器,因 PGDATA 为 bind mount 未丢失数据;本轮仅确认代码风险,不重演生产事件。
|
||||
- `deploy/trialrun/deploy-existing.sh:109` 起向 `deploy.sh` 固定传入 `DEPLOY_DATA_MODE=existing`。后者在 `:93` 校验模式,在 `:249` 区分数据目录检查,但关键容器操作未按模式隔离。
|
||||
- 三类入口:`deploy/trialrun/deploy.sh:317` 无条件 `up -d db`;`:326` 的 init `run` 未隔离依赖;`:329`、`:331` 的 server/worker `up` 未隔离依赖。`deploy/trialrun/docker-compose.yml:57`、`:79`、`:100` 分别声明三者依赖健康 db。
|
||||
- 因此只给 server 添加一个选项不足以解决问题,必须同时禁止显式 db 操作并隔离所有相关依赖启动入口。
|
||||
|
||||
## Requirements
|
||||
|
||||
### R1 模式与操作边界
|
||||
|
||||
- `existing` 模式禁止显式及隐式数据库生命周期操作,包括全项目操作;不能在 db 缺失、停止或不健康时自动切换到 initialize 或尝试启动/修复 db。
|
||||
- `initialize` 保留显式启动 db 的既有能力;不得把此能力泄漏到 existing 发布。缺失或非法模式在任何容器变更前非零退出。
|
||||
- 数据库只读状态检查、就绪探测与容器内数据库迁移/seed 不属于容器生命周期变更;后两者仍须遵循既有发布授权与迁移门禁,本任务不改变其内容或顺序。
|
||||
|
||||
### R2 发布链路隔离与失败行为
|
||||
|
||||
- 同时覆盖入口 wrapper、远端执行段、init、server、启用的 worker,以及可选 profile;按实际服务依赖判定,不遗漏间接通路。
|
||||
- existing 在 init 或应用切换前确认目标项目 db 已存在、正在运行并就绪;失败则有界停止,输出安全原因,不隐式自愈。
|
||||
- initialize 启动 db 后须有界确认就绪,再进入 init;隔离依赖不能取消原来依赖健康状态提供的时序保障。
|
||||
- 每次就绪等待固定为 120 秒(不可由环境变量放宽),轮询间隔 2 秒;单次总时限包含卡住的状态查询,超时必须非零退出,不运行后续 init 或继续应用切换。缺失、停止、不健康或缺健康检查时直接失败。构建、init 之后重新检查,不能只用发布开始时的健康快照;应用构建与切换分开,健康检查之后不允许隐式构建。
|
||||
- 保留现有 Compose V2 与 `docker-compose` 兼容入口;不支持所需隔离能力时失败,不回退为不隔离的启动。
|
||||
- 保留身份、发布来源、数据挂载与路径、迁移及回滚窗口、受控日志、备份合同刷新、`/ready` 和公网版本等检查。不改生产配置、数据目录权限或部署身份。
|
||||
|
||||
## Test Plan
|
||||
|
||||
### R3 本地可执行安全回归
|
||||
|
||||
- 在临时合成工作区运行实际发布 shell 路径,PATH 前置假的 docker/docker-compose,并截获 SSH、rsync 等外部入口,禁止接触真实 daemon、主机、网络服务、env 和数据目录。
|
||||
- 记录参数数组并解析操作、目标服务、项目及依赖传播;断言 existing 的数据库生命周期事件为零,不能只搜索选项字符串。全项目 up/down、直接 db 操作、依赖传播均纳入违规判定。
|
||||
- 测试必须证明 init 与预期应用服务实际执行,不能因脚本提前退出或 fake 总返回成功而得到“零 db 操作”的假通过。
|
||||
- initialize 应观察到允许的 db 启动与后续 init、应用执行;existing 缺失/停止/不健康 db、非法模式、init 失败应非零退出,且不切换应用或启动 db。
|
||||
- 正向矩阵覆盖 V2/V1、worker 开关及可选 MinIO profile;故意恢复无条件 `up db`,分别去掉 init/server/worker 的依赖隔离,测试均须发现 db 违规而失败。
|
||||
- 新回归进入既有本地 static 发布门禁,在任何生产执行前可运行;不为本任务重构整个部署测试体系。
|
||||
|
||||
## Scope And Authorization
|
||||
|
||||
- 拟涉及:`deploy/trialrun/deploy.sh`、必要时 `deploy-existing.sh` 的模式传递合同、新增专用容器生命周期回归、现有 deployment safety 回归的相关断言、`scripts/qa/run-release-gate.sh` 的 static 接入、现有 deployment spec,以及本 task 文件。
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 不改 Compose 服务拓扑、业务代码、schema/migration/seed 实现、付款及账号权限、IM routing、Trellis 升级、治理规则、目录权限、其他小债。财务 403 在本任务之后另开只读诊断。
|
||||
- 用户本轮只批准立 task 和规划。未经下一轮批准不实施;不启动生产发布、故障注入、数据修复或账号操作。一个 task、一个实施提交单元,实施后安排只读独立复核;提交、push、部署、归档各遵守明确授权边界。
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [x] AC1(R1):existing 实际执行捕获中没有显式或隐式 db 生命周期事件;无服务名的全项目操作同样受约束。
|
||||
- [x] AC2(R2):init、server、启用的 worker 均隔离依赖;init 的现有迁移/seed 命令内容和顺序保持,相关命令实际到达。
|
||||
- [x] AC3(R1/R2):initialize 可启动 db 并等待就绪;existing db 缺失/停止/不健康时失败,不启动或修复 db,不到达 init/应用切换;非法模式 fail closed。
|
||||
- [x] AC4(R3):四类真实源码变异(无条件 up db、init/server/worker 各自失去隔离)分别令捕获断言失败;正常模式矩阵通过,断言按服务生命周期语义而非字符串存在性成立。
|
||||
- [x] AC5(R3):测试完全本地合成,不访问真实 Docker、SSH、生产 env 或数据库;测试可经 static 门禁运行,fake 未知命令 fail closed,无提前退出假通过。
|
||||
- [x] AC6(R2):既有部署安全合同、身份/路径/迁移/日志/刷新/版本断言和 shell syntax 通过;未弱化其他安全约束。
|
||||
- [x] AC7:只读独立复核覆盖显式 db 操作、init 间接依赖、测试有效性与初始化兼容,问题闭环后才交实施 diff;同步现有 spec,未混入其他 task 或小债。
|
||||
- [ ] AC8:交付区分本地防护验证与生产执行;若未来单独批准生产验收,需比较同一项目 db 容器 ID/创建时间前后不变及应用版本更新、ready 通过,禁止在生产注入故障。本轮生产验证为未授权、不执行。
|
||||
在新工单中引用
屏蔽一个用户