8.2 KiB
8.2 KiB
每日自动异机备份
Goal
为 5–10 人内部 OA 建立低维护的每日自动恢复点:生产每天生成同批数据库、附件和 manifest,完整校验后复制到 ARM 备份机,失败可被当天发现并告警;同时用简单保留策略和季度人工影子恢复降低主机故障与静默备份失效风险。
Background
- 现有
scripts/backup-all.sh已能生成 DB、附件和脱敏 manifest 的完整批次,并在发布完整目录前验证 dump、tar 和 SHA-256。 - 当前仓库没有任何生产调度器调用
backup-all.sh;唯一活动 timer 是 07:30 运维巡检,不执行备份。 - 生产主机和 ARM 均有 systemd、SSH、
flock和 SHA-256 工具;生产有 rsync,ARM 当前没有 rsync。 - 两台主机之间当前没有可直接复用的免密 SSH 别名或密钥链路,不能把本地工作站的 SSH 配置误当作服务器间自动化能力。
- 当前手工正确批次和 ARM 影子恢复已证明格式可用,但不能满足 RPO 24 小时或自动失败发现。
- 已确认采用“生产主动推送到 ARM 的专用受限接收身份”:生产保留即时传输结果,ARM 的已归档批次不暴露给 rsync 写入根。
- 任务实施前,生产切换已完成并应用 61 项 migration;本地为 62 项,
2526052后续部署只新增 1 项 migration。当时自动备份三组 units 已安装但尚未形成可靠启用闭环。 - 首次真实自动批次曾证明源端成对备份可生成,但 ARM 因“同一 UTC 日仅允许一个不同 run_id”拒绝重试批次;当时即时告警仍依赖活动 server 容器,不能覆盖容器或整机故障。
Scope
- 生产每日成对备份、ARM 受限接收与目标端校验。
- 源端 7 个日批次、ARM 7 个日批次加 4 个周检查点的安全轮转。
- 每日 systemd 调度、独立 stale watchdog、失败企微告警和季度人工恢复提醒。
- 两端安装器、合成契约测试、现有运维文档/规约更新和一页脱敏恢复卡。
Requirements
- 每日自动从唯一活动 Compose project 解析 DB 容器、活动附件挂载和实际构建标识,不读取旧项目、固定容器名或仓库默认附件目录。
- 复用
backup-all.sh生成完整批次;任何来源核验、dump、tar、manifest 或哈希检查失败时不得进入异机完成态。 - 使用独立 systemd service/timer 和
flock,避免与部署、人工备份或自身上次运行重叠。 - 完整批次通过固定主机指纹和专用受限密钥自动推送到 ARM;该身份无普通 shell,只能把文件写入 inbox 或请求校验/归档,不能通过 rsync 读取或删除 archive。
- 传输端和目标端都要校验 manifest、文件大小和 SHA-256;同名已归档目标不得覆盖。中断传输可以在 inbox 内续传,但只有完整校验后才能原子进入 archive。
- 生产保留最近 7 个成功日批次;ARM 至少保留最近 7 个日批次和 4 个周检查点。清理只能发生在本次异机成功确认之后,且不得删除最后一个已知成功批次。
- 生产即时告警和 ARM dead-man 告警统一使用独立企微运维群机器人;Webhook 只从 root-only 文件读取,不依赖 OA server、数据库、员工绑定或默认个人工号,也不得进入仓库、
.env.example、Trellis、日志或聊天。 - ARM 安装独立 26 小时 dead-man timer,直接检查最近归档完成时间;生产整机或容器不可用、timer 未运行、传输未 finalize 时仍能从另一台主机发出告警。
- 生产 watchdog 的“恢复点缺失/损坏/超龄/Compose project 不匹配”继续硬失败;仅
buildSha早于当前部署时降级为一次 finding,不得误报为没有恢复点。部署后仍推荐立即触发一次获批备份。 - backup、rsync 和 finalize 的失败输出必须写入状态目录下权限
0600的最近失败诊断;企微告警仍只包含阶段、状态、finding 数和脱敏建议,不附原始输出。 - 同一 UTC 日已有不同自动归档时,新批次必须先完整通过 manifest、文件集、大小和 SHA-256 校验,再以可回滚的同文件系统 rename 顺序原子取代旧日批次;任一替换步骤失败必须恢复旧批次或保留可诊断状态。最终仍只保留每日一个恢复点。
- 告警只包含阶段、状态、finding 数和脱敏建议,不包含数据库凭证、完整目录、SSH 信息、真实业务数据、附件名或原始命令输出。
- 季度恢复保持人工触发,在 ARM 隔离目标执行;季度 timer 只发送一次脱敏提醒,不得自动运行恢复,更不得触碰生产库。
- 形成一页脱敏恢复卡,说明主机故障后的负责人、备份位置类别、恢复顺序和验收项,保存在现有运维 runbook 中,由唯一系统管理员维护并用于季度自查。
Acceptance Criteria
- 本地合成测试证明每日 wrapper 只接受唯一活动来源、互斥锁有效,并只发布完整备份批次。
- 传输测试证明不完整批次、哈希不一致、重复批次和不可达 ARM 均失败,且不产生异机成功状态。
- 保留测试覆盖 7 个日批次、4 个周检查点、最后成功批次保护和仅在异机确认后清理。
- 告警测试证明首次失败和状态恶化会告警,重复同一失败降噪;07:10 stale 检查能发现超过 24 小时没有异机成功记录。
- 本地合成测试证明同日不同 run_id 的完整新批次可取代旧批次,损坏新批次不会影响旧归档,且周检查点与日归档不产生悬空或错误指向。
- 本地合成测试证明 buildSha 不同仅产生 finding,恢复点缺失/损坏/超龄/project 不同仍失败;失败诊断为
0600且不进入告警摘要。 - 环境契约证明 Webhook 相关键和值不出现在
.env.example、仓库配置或报告;两端安装器只接受 root-only Webhook 文件路径。 - ARM 26 小时 dead-man 合成验证覆盖“源端停止/不产生新 finalize”而非仅验证机器人能发送,并覆盖首次失败、重复降噪与恢复通知。
- systemd 安装器显式绑定 Compose project、活动数据路径、构建标识、备份根和受限远端身份;安装后四组 timer 均 enabled/active,安装阶段未手工执行真实告警。
- 经单独生产授权后完成一次自动日备份:源端完整、ARM 目标端哈希一致、状态报告脱敏,且未读取附件正文或修改业务数据。
- 模拟源端停止产生一条脱敏企微告警,相同失败重复执行不再发送;恢复正常链路并完成成功批次后只发送一条恢复通知。
- 恢复卡已写入现有运维 runbook,覆盖恢复入口、影子目标和
/ready/关键计数验收项;公司只有一名系统管理员,不设置虚构的第二人走查门禁。
Out of Scope
- 不引入备份平台、对象存储、MinIO、云厂商 SDK、Kubernetes 或持续复制。
- 不自动执行生产恢复、数据库 reset、迁移改写或附件回写。
- 不把真实业务正文、附件清单、凭证、主机地址、完整目录或 SSH 私钥写入仓库、报告或聊天。
- 不把企微群机器人 Webhook URL、key 或配置文件正文写入仓库、
.env.example、Trellis、报告、日志或聊天。 - 不在本任务继续企微本人授权、员工角色、付款、报销或其他产品功能。
- 不因自动备份完成而取消季度人工影子恢复。
Test Plan
- Shell 语法与合成文件系统测试,覆盖锁、来源解析、传输失败、目标重复、哈希和保留轮转。
- 合成 receiver 测试覆盖同日完整批次取代、损坏候选保留旧批次、替换失败恢复以及周检查点一致性。
- 合成双主机告警测试覆盖生产无 server 容器、ARM 26 小时无新归档、重复降噪、恢复通知和 root-only Webhook 文件门禁。
- 复用
scripts/qa/run-backup-restore-drill.sh验证成对备份合同未回退。 - 聚焦测试现有企微运维告警的备份状态与 stale finding 适配。
node deploy/trialrun/validate-env-contract.js。python3 ./.trellis/scripts/task.py validate .trellis/tasks/07-27-automatic-offhost-backup。- Trellis governance、敏感扫描、文档注册/流程合同和
git diff --check。 - 生产安装、首次自动批次、真实失败告警和 ARM 目标验证分别保持外部门禁。