5.2 KiB
5.2 KiB
自动备份运行身份失败
Goal
恢复每日自动成对备份,使生产 unit 冻结的存储路径重新与当前运行容器一致,补跑并完成一次数据库、附件和 ARM 异机归档闭环,同时保留失败告警的脱敏证据。
Scope
- 只读确认 02:30
phase_runtime_identity_failed的精确失败维度和最近成功恢复点。 - 使用当前运行 server 容器的实际附件挂载源刷新自动备份三个 systemd services/timers;其他已验证环境值沿用现有 unit,禁止打印路径或秘密。
- 刷新前后验证 active server/db 数量、运行状态、构建 SHA、附件挂载、PGDATA 和数据库身份。
- 手工运行一次 daily backup,要求本地完整批次、ARM finalize、success state 和一条恢复通知全部成功。
- 保持应用健康监控、备份 receiver、ARM dead-man 和业务服务不变。
Confirmed Facts
- 2026-07-28 02:30 daily service 以非零状态失败,脱敏状态为
FAIL_AUTOMATIC_BACKUP / phase_runtime_identity_failed。 - 生产机使用 standalone
docker-compose;最初诊断命令误用docker compose,已按 runner 相同选择逻辑更正,未把诊断工具错误当作根因。 - 当前 server/db 各唯一且运行中;unit 冻结的构建 SHA、PGDATA、应用/数据库身份均与运行容器匹配。
- 唯一不匹配项是
STORAGE_HOST_DIR:unit 配置目录和当前容器实际挂载源都存在,但 realpath/inode 均不同,不是符号链接或路径规范化差异。 - unit 早于当前 server 容器启动,说明部署/重建后容器使用了新附件目录,而自动备份 unit 仍保留旧目录。
- 最近一次成功异机恢复点约 11 小时前,项目和构建身份均匹配;当前未超过 24/26 小时窗口,但本次 02:30 没有产生新恢复点。
- runtime identity 阶段不写
last-error.log,因此没有原始诊断残留;脚本按设计在任何备份写入前失败关闭。 - 2026-07-28 07:10 watchdog 又发送
phase_stale_check_failed。check-stale在读取 success state 前同样调用resolve_active_runtime,因此该消息由同一个附件挂载漂移触发;它不是第二个独立故障,也不证明最后成功批次本身损坏或过期。
Requirements
- R1:刷新前再次从运行容器解析唯一实际附件挂载源,要求安全绝对目录、存在、非符号链接,且不得输出路径。
- R2:不得直接手改 unit 单行;使用已提交安装器以完整合同重写 daily/watchdog/drill units,并保持三个 timers enabled/active。
- R3:除
STORAGE_HOST_DIR改为当前实际挂载源外,Compose project、PGDATA、build、远端目标、SSH、webhook 和备份目录等合同必须与现有 unit 一致。 - R4:刷新后先只读复跑六项 runtime identity;任何一项不匹配均不得补跑备份。
- R5:手工补跑必须使用现有 runner,完成数据库 dump、附件归档、manifest、受限传输和 ARM finalize 后才写 success state。
- R6:成功后应把当前告警状态(最新类别为
phase_stale_check_failed)切换为PASS_AUTOMATIC_BACKUP_COMPLETE并发送一次恢复通知;相同健康状态不得重复发送。 - R7:不得删除旧成功批次、旧目录或失败状态;正常保留策略只在新批次已由 ARM finalize 后运行。
- R8:如果 unit 刷新失败,恢复原 unit 文件并 daemon-reload;如果补跑失败,保留刷新后的正确 identity 配置和脱敏失败状态,不回退到旧附件目录。
Acceptance Criteria
- AC1:根因证据明确为非规范化的附件宿主目录漂移,其他 runtime identity 维度全部匹配。
- AC2:三个自动备份 timer 仍为 enabled/active,刷新后的 daily unit 与当前附件挂载、PGDATA、build、项目和数据库身份全部匹配。
- AC3:手工 daily backup 成功生成并在 ARM finalize 一个新的完整批次,生产 success state 时间更新。
- AC4:群内只收到一次自动备份恢复通知,状态为成功;无秘密、路径或原始日志进入消息/任务证据。
- AC5:应用健康 timer、ARM backup dead-man 和备份 receiver 未受影响。
- AC6:补充防复发合同:部署后若容器宿主挂载变化,必须刷新/核对自动备份 unit,不能等次日告警发现。
Out of Scope
- 修改数据库、附件内容、OA/Caddy、备份保留数量或 ARM 归档结构。
- 删除旧附件目录或判断其业务处置。
- 重置数据库、恢复数据、改 webhook、SSH key 或真实业务数据。
- 将路径、容器 ID、数据库身份、连接串或原始日志写入文档/聊天。
Test Plan
- 刷新前后运行脱敏 runtime identity 矩阵。
- 运行本地自动备份 73 项合同,确保安装器/helper/runner 行为无回归。
- 生产补跑后检查 service result、last-success 新鲜度、ARM 新批次 finalize、alert state 和三个 timers。
- 运行 task validate、Trellis governance、敏感内容扫描、文档审计和
git diff --check。
Key Decision
立即修复 unit 的附件路径并补跑备份,不修改严格相等检查。两个目录不是同一 inode,放宽为 realpath 或“目录存在即可”会掩盖真实数据源漂移。