# updater 双保险维护验收 日期:2026-10-08。代码位于 `/Users/wangbo/projects/easyai`。本记录补充前序 Watchtower 宿主机维护验收,描述本轮新增的 updater 独立定时更新通道。 ## 结果 宿主机定时任务每六小时分别维护 Watchtower 和已启用的 updater;原 Watchtower 每 24 小时维护 updater 的机制保留。无需新增容器或再注册另一条宿主机任务。 每项维护分别拉取、按需重建和验证健康状态。某项失败仍继续另一项,同时记录失败并返回非零结果。不会因 Watchtower 不可用而跳过 updater。旧部署未启用 updater 时保持原更新模式。 验收时尚未提交或推送源码;本轮真实运行结果不代表已部署至线上。本轮没有实际注册本机 cron 或 Windows 计划任务。旧机器需由运维执行一次新版部署脚本接入;发布源码本身不能给机器安装宿主机任务。 ## 修改前真实复现 独立 Compose 项目 `easyai-updater-insurance-20261008`,Watchtower 1.22.3、updater 1.1.0,本机 registry 发布 updater 1.2.0。主动停止本次自建的 Watchtower,并把该项目 Watchtower 镜像设置为不存在的标签,模拟 Watchtower 恢复失败。 分别运行原 Bash 和 PowerShell 定时入口:均在 Watchtower 拉取失败时退出;updater 继续运行旧版本 1.1.0,容器及镜像均未变化。 证据:`before.json`、`before-bash.log`、`before-powershell.log`,原入口快照保存在 `before-scripts/`。这说明原定时维护只负责 Watchtower,不能在其失效时直接维护 updater。 ## 本轮变更及影响范围 - 修改 `scripts/update-infrastructure.sh` 和 `scripts/Update-Infrastructure.ps1`:独立处理两个组件,失败分别记录,最后汇总结果;保持部署目录、Docker 登录配置、并发锁及只重建指定服务的行为。 - 修改 Bash/PowerShell 任务安装器的提示文案,保留原任务标识、每六小时周期、去重及关闭方式,不重复注册任务。 - 更新 `.env.sample` 和 README,说明 updater 两条维护路径。 - 扩展 `scripts/test-infrastructure-auto-update.py`,覆盖两种入口、两种 Compose 命令路径、独立失败、legacy 跳过及健康检查。 主要调用方仍为 `start.sh/update.sh/start.ps1/update.ps1` 安装的定时任务。没有修改业务自动更新开关,也没有改动 updater、后端、前端业务代码及已有任务存储格式。此前工作区中其他未提交改动均保留。 ## 实际运行结果 | 场景 | 实际结果 | | --- | --- | | Watchtower 已停止且拉取失败,Bash 定时入口 | updater 实际升级 1.1.0 → 1.2.0;Watchtower 仍停止,证明该升级不依赖它;返回失败以保留 Watchtower 故障结果 | | 相同条件,PowerShell 定时入口 | updater 实际升级 1.1.0 → 1.2.0;同样独立执行并报告部分失败 | | updater 历史任务 | Bash 独立更新后,实际任务 API 仍能读取原有成功任务及其消息 | | updater 拉取失败 | updater 容器未停止或重建;Watchtower 仍恢复健康;整体报告失败 | | 正常维护及镜像无变化 | 两组件均健康;镜像和配置无变化时容器 ID 不变 | | legacy profile 未启用 updater | Bash、PowerShell 均不创建或启动 updater | | 原 Watchtower 更新通道 | 重新开启轮询并发布 updater 新标签,Watchtower 仍实际更新 updater 1.1.0 → 1.2.0 | | 业务服务对照 | 全程容器 ID 不变,没有被维护入口直接重建 | 实际运行验收耗时 27.58 秒,不含镜像准备及修改前复现。证据:`after.json`、各场景 `.log`、`watchtower-final.log`。这是自建 registry、真实 Compose 和真实更新组件的运行结果。业务服务为独立 Node 对照容器,并未部署整套业务及数据库。 ## 定向检查 - `python3 scripts/test-infrastructure-auto-update.py`:通过,19.496 秒。覆盖 Bash/PowerShell、Compose v2/v1 命令路径、单项失败不影响另一项、全部拉取失败不重建、legacy 跳过、并发排除、健康探测,以及原有迁移和 cron 去重保护。 - `pwsh -NoProfile -File scripts/Test-InfrastructureUpdateTask.ps1`:通过,0.18 秒。验证注册参数及去重、关闭行为;计划任务 API 为测试替身。 - Bash/PowerShell 语法、ShellCheck、diff 空白检查:通过,合计 0.72 秒。PowerShell UTF-8 BOM 保持不变,供 Windows PowerShell 5.1 使用。 证据:`validation.json`、`quality-checks.json` 及本轮工具输出。没有运行全量前端质量门禁,本轮未涉及前端业务代码。 ## 验证边界 Windows 宿主机真实计划任务注册、生产六小时和 24 小时长周期、客户私有仓库网络及权限尚未验证。Compose v1 是命令适配行为验收,实际容器验收使用 Docker Compose v5.3.1。PowerShell 实际容器入口在 macOS 上运行。 历史终态任务持久化已实际验证;本轮没有在业务更新执行到一半时替换 updater 的故障演练,也不据此宣称所有活动任务恢复已验收。 Compose 根据启用的 profile 选择可维护服务,运行 `config --services` 已实测关闭 profile 时不包含 updater。避免直接显式启动未启用的 updater,因显式指定服务会自动启用其 profile。[Docker 官方说明](https://docs.docker.com/compose/how-tos/profiles/) 本方案仍需 Docker 和镜像仓库可用;镜像启动失败不会自动回滚。每项维护有健康等待并报告失败,后续定时任务继续检查。 本次已清理四个自建验收容器及独立网络,原本机 `test-watchtower-1` 保持健康。证据:`cleanup.json`。 原始运行日志与入口快照保存在本机证据目录:`/Users/wangbo/.codex/visualizations/2026/10/07/01a11505-cae4-76e0-9ba9-235f6962b2b4/updater-double-insurance-20261008`。本目录附带修改前、修改后及定向检查的结构化结果。