7.9 KiB
7.9 KiB
ARM 应用健康监控上线
Goal
把已通过本地契约的公网 /ready 健康监控安全部署到现有 ARM 异机,启用 5 分钟 timer,并通过一次不影响 OA 用户的真实告警/恢复演练证明“持续故障能发现、重复故障会降噪、恢复会通知”。
Scope
- 通过现有受控 SSH alias 连接 ARM;先做只读身份、sudo、systemd、既有备份 dead-man 和 webhook/helper 合同预检。
- 只向临时目录传输已提交版本的探测器、共用告警 helper 和独立安装器;校验源/目标哈希,不传输 webhook 正文。
- 复用既有 dead-man unit 中已经配置的 root-owned
0600webhook 文件路径;路径只在 ARM 内解析和校验,不回显其内容。 - 先执行
install安装 disabled units,核对精确受管目标、权限和 unit 合同,再手工运行一次真实公网健康探测。 - 健康基线通过后启用 5 分钟 timer;演练期间暂时停止 timer,使用同一已安装探测器、helper、webhook 和生产状态目录对本机不可达 HTTPS 端口连续执行三次:第一次 pending、第二次发送真实故障告警、第三次验证降噪。
- 随后通过正式 systemd service 探测真实公网
/ready,发送一次恢复通知,再恢复 timer 并核对 enabled/active、最近结果和下一次计划时间。 - 将输出压缩为脱敏状态、类别、计数、布尔检查和提交哈希;不记录 webhook、地址、原始响应、完整 journal 或远端绝对配置路径。
Confirmed Facts
- 仓库提交
bb5113c已实现并通过应用健康专项 22 项、自动备份兼容回归 73 项、后端 1018 项及前端构建。 - 安装器固定受管探测器、helper、状态目录和 systemd unit 名;
install默认 disabled,uninstall保留共用 helper、webhook 和状态证据。 - ARM 已有 SSH alias,但当前 alias 不是 root;上线前必须证明非交互 sudo 可用,否则停止,不尝试口令或变更账户。
- webhook 不在仓库;既有 off-host dead-man service 是复用其路径的唯一事实源。
- 本任务已获用户确认:允许 ARM 安装、timer 启用、真实企微故障/恢复演练,并在失败时回滚应用健康组件。
Requirements
- R1:任何写入前先完成只读预检;SSH 身份、
sudo -n、既有 dead-man unit、root-owned0600webhook、Python/systemd 和公网/ready任一不满足即停止。 - R2:不得读取、打印或复制 webhook 正文;只允许把 ARM 内部已验证的 webhook 文件路径传给 root 安装器。
- R3:只安装提交版本的三个文件,并以 SHA-256 比对证明传输和受管目标一致;三个部署源相对
HEAD必须无未提交改动,Trellis 任务记录可按正常流程保持未提交;不得从远端旧副本部署。 - R4:首次安装发现应用健康 unit、探测器或状态已存在时停止并报告,不覆盖未知运行状态;只有确认是本任务中刚创建的对象后才继续。
- R5:手工健康探测必须在启用 timer 前成功,且只保留稳定状态字段;不得用本地成功代替 ARM 公网链路成功。
- R6:真实故障演练不得停止 OA、Caddy、数据库、备份 receiver 或 dead-man;只使用 ARM 本机确定不可达的 HTTPS 端口,并在演练期间停止应用健康 timer 避免竞态。
- R7:第一次失败不得发送,第二次发送一条,第三次 helper 返回降噪;正式 service 恢复后发送一次恢复通知。
- R8:最终 timer 必须 enabled/active,最近一次 service 为成功,下一次计划不超过 5 分钟;备份 dead-man timer 仍保持原状态。
- R9:任一步失败时停止继续扩大变更。若尚未发送故障告警,卸载本任务组件;若已经发送故障告警,优先恢复正式探测并发送恢复通知,失败则保持 timer 停用并明确报告未闭环告警。
Acceptance Criteria
- AC1:只读预检证明受控 alias 可连接、
sudo -n可用、既有 dead-man/webhook/helper 合同成立,且未输出秘密或完整配置路径。 - AC2:ARM 上安装的探测器和共用 helper 与提交版本哈希一致;unit/状态目录权限符合合同,install 后 timer 明确 disabled/inactive。
- AC3:ARM 手工正式
/ready探测成功,probe state 为健康且输出无地址、路径、payload 或原始异常。 - AC4:timer 启用后为 enabled/active,调度周期为 5 分钟且最近正式执行成功。
- AC5:受控演练证据显示第一次 pending、第二次 sent=true、第三次 sent=false;群内只产生一条脱敏故障告警。
- AC6:正式 service 恢复成功且 sent=true,后续健康执行 sent=false;群内只产生一条恢复通知。
- AC7:备份 receiver、dead-man unit/timer、归档与状态均未被卸载或覆盖;备份兼容合同在上线前仍通过。
- AC8:临时传输目录已清理;最终只保留已批准受管文件、独立状态和 units,工作树与审计记录不含秘密。
- AC9:用户确认实际收到一条故障告警和一条恢复通知;在此确认前只报告“自动链路证据通过,人工收件待确认”。
Out of Scope
- 修改 OA、Caddy、数据库、DNS、证书、Compose 或公网部署。
- 停止真实服务来制造故障。
- 修改备份 receiver/dead-man 配置、归档、timer 或 webhook 内容。
- 新建机器人、变更企业微信配置、发送业务数据或原始日志。
- 增加证书到期预警、业务登录/审批合成监控或第三方 dead-man。
Test Plan
- 上线前复跑
bash scripts/qa/run-app-health-monitor-contract.sh与bash scripts/qa/run-automatic-backup-contract.sh。 - ARM 只读预检、源/目标哈希、权限、unit 内容和 state schema 检查均返回有限布尔/状态 token。
- 先 disabled 安装和健康手工执行,再 enable;演练用同一正式状态链完成 pending/send/dedup/recovery。
- 结束后检查 timer、service、备份 dead-man 保持情况、临时目录清理、Trellis/task 治理和
git diff --check。
Key Decisions
- 使用“不影响 OA 的本机不可达端口”制造监控输入故障,不停止任何真实服务。
- 复用正式状态目录做一次完整状态机演练,timer 在演练窗口暂停,避免健康执行插入失败序列。
- webhook 路径从既有 dead-man unit 在 ARM 内解析,正文始终不读取、不传输、不回显。
- 用户已批准操作范围,但 Trellis 仍要求本规划摘要之后再明确批准实施。
Execution Evidence
- 2026-07-27:本地应用健康专项 22 项、自动备份兼容回归 73 项通过;三个部署源相对
HEAD无未提交改动,SHA-256 已记录为脱敏技术证据。 - 2026-07-27:受控 SSH alias 可连接,但首个
sudo -n true预检返回“需要密码”;流程按 R1 在任何远端写入前停止。 - 未创建 ARM 临时目录、未上传文件、未修改 systemd、未读取 webhook、未发送真实企微消息。
- 本地 SSH 配置中未发现指向同一 ARM 的 root alias。继续执行需要用户在 ARM 侧提供非交互 root 运维入口;不得在聊天中发送 sudo/root 密码。
- 2026-07-27:用户在自己的终端建立临时 sudoers 入口后,完整只读预检通过;disabled 安装、提交哈希、权限和 ARM 公网健康基线均通过,健康基线未发送消息。
- 2026-07-27:timer 已启用;隔离演练依次得到 pending、
sent=true、sent=false,正式 systemd service 恢复成功并更新为PASS_APP_HEALTH_READY,重复健康为sent=false。 - 2026-07-27:最终 timer enabled/active、下一次运行在 5 分钟内、最近 service 成功;备份 dead-man enabled/active 未变。临时上传目录和临时 sudoers 规则均已删除。
- 自动链路已证明一条故障和一条恢复发送成功;随后由用户完成实际群内收件确认。
- 2026-07-27:用户确认企微群实际收到一条“内部 OA 运维告警”和一条“内部 OA 运维恢复通知”,真实收件闭环完成。