本节摘要:镜像自动更新由两件东西配合完成:容器上的 autoupdate 标签声明与 podman auto-update 命令(通常挂在 systemd 定时器上)。健康检查由镜像的 HEALTHCHECK 指令定义,Podman 记录健康状态供上层决策。本节讲两条机制的完整配置、更新策略的工程取舍,并对比 Docker 生态里 Watchtower 式第三方更新器的思路差异。
先立设计观念。Podman 的自动更新不靠外部守护进程扫描,而是把"这个容器允许自动更新"写进容器自身的标签:
# 创建一个声明了自动更新的容器(Quadlet 写法更佳,此处直命令演示) podman run -d --name web \ --label "io.containers.autoupdate=registry" \ docker.io/library/nginx:1.27-alpine # 解读标签值:registry 表示"按镜像引用自动更新"—— # auto-update 会重新 pull 该引用,若 digest 变了就用新镜像 # 重建容器;另一个取值 image 供本地构建镜像场景使用 # 手动触发一次全局自动更新(生产用定时器,见下) podman auto-update # Updating container "web" ... updating image # 非 registry 标签的容器被跳过——更新范围完全由声明决定 # 把它挂成 systemd 定时任务(Quadlet 的 .timer 文件): # ~/.config/containers/systemd/autoupdate.timer # [Timer] # OnCalendar=*-*-* 04:30:00 # Persistent=true systemctl --user enable --now autoupdate.timer # 每天凌晨四点半自动执行,Persistent 保证错过的补跑
这套机制与 Docker 生态的 Watchtower(第三方更新守护进程)思路对比值得展开:Watchtower 是"进程扫描所有容器决定更新",Podman 是"容器自己声明可否更新、系统定时统一执行"。前者部署简单但范围失控风险高(忘记某个容器不想自动更新),后者声明式可控但要求配置纪律。生产环境里我更倾向声明式——更新是高风险操作,范围必须显式圈定。
健康检查的定义在镜像里(HEALTHCHECK 指令),Podman 启动容器后按定义周期执行探测命令,把状态记录为 healthy 或 unhealthy:
# 一个自带健康检查的镜像(Dockerfile 片段) # HEALTHCHECK --interval=30s --timeout=3s --retries=3 \ # CMD wget -qO- http://127.0.0.1:8080/healthz || exit 1 # 查看健康状态 podman healthcheck run web podman ps # STATUS 列显示 (healthy) 或 (unhealthy) # 健康检查的意义在于暴露问题,而"不健康后做什么"是 systemd 的职责: # [Service] 段里 Restart=always 加 RestartSec=5, # 健康恶化导致进程退出的场景会被自动拉起; # 进程不退但 unhealthy 的场景,可以给 Quadlet 加 # ExecPostStart 里的看护脚本,或交给上层监控(7.3 节)
诚实说明一个与 Docker 的差异点:Docker 的 healthcheck 状态会被 swarm 等编排层直接用于摘除流量;Podman 的健康状态目前主要作为"可查询的信号"存在,联动动作(摘流量、告警)由 systemd 或监控栈完成——无守护进程架构里"状态"与"动作"分离,动作永远归你管。这既是灵活性也是配置负担,团队要自己把"看到 unhealthy 之后干什么"写清楚。
自动更新不是银弹,先把决策表摆出来:
| 策略 | 适用场景 | 代价 |
|---|---|---|
| 全自动(registry 标签加每日定时) | 边缘节点、内部工具、非关键负载 | upstream 破坏性更新会自动进入生产 |
| 半自动(定时器只 pull 不 apply) | 大多数业务服务 | 需要人工触发 apply 窗口 |
| 手动(不打标签,digest 锁定) | 核心数据库、支付路径 | 更新速度依赖运维响应 |
| CI 驱动(更新走完整流水线) | 有测试资产的团队 | 流水线延迟,需基础设施投入 |
半自动的做法值得一提:定时器里跑的是 podman auto-update --dry-run 或只 pull 的脚本,变更以通知形式发给值班(渠道用第 7.3 节的事件流接),人工确认后再执行真正的 apply。牺牲一点速度换控制权,对多数团队是甜点位。
背景:第 7.1 节那台边缘服务器(代理、应用、日志收集)要加自动更新,约束是"代理与应用必须同步更新,且更新失败要能回看旧版本"。操作:三个 Quadlet 单元都加 AutoUpdate=registry;再加一个 autoupdate.timer 每夜执行;应用镜像在仓库里保持双 tag(latest 跟随、上一版留档),CI 每次发布把旧 latest 重打为 backup。结果:一次上游 nginx 镜像出现破坏性变更的夜晚,auto-update 重建了代理容器,新容器启动失败,systemd 按 Restart 策略反复拉起三次后进入失败状态,次日值班看到服务降级告警(事件流),执行回退:把 Quadlet 单元的 Image 临时改为 backup tag 拉起旧版。解读:这次"故障恢复"没有用到任何回滚机制——旧镜像还在本地存储里(第 3.2 节:多 tag 共享层),改引用即回退。自动更新体系的可靠性不来自"更新一定成功",而来自"失败后状态可见、旧版本随手可用"。变式:对不能接受夜间变更的服务,把它的 timer 单独删掉、标签去掉,同一台机器上不同服务可以有不同更新节奏。