先看现象。发布出问题后把 Deployment 镜像从 app:1.9.2 改回 app:1.9.1,滚动完成后接口返回的版本号仍是 1.9.2,docker inspect 显示两个 tag 指向同一个 digest。
原因不止一个,得分开看。构建流水线复用了 tag,1.9.1 被重新推送覆盖。还有一种是imagePullPolicy 为 IfNotPresent,节点上缓存了同 tag 镜像。
还有一种情况,回滚只改 tag 没触发滚动,Pod 仍是旧模板。
另外,仓库开了不可变 tag 但推送时被强制覆盖。
先比对两个 tag 的 digest 是否相同
docker manifest inspect repo/app:1.9.1 | grep digest && docker manifest inspect repo/app:1.9.2 | grep digest
再往下查看 Pod 实际使用的镜像 ID
kubectl get pod -o jsonpath='{.items[*].status.containerStatuses[*].imageID}'
然后改为按 digest 部署并强制拉取
kubectl set image deploy/app app=repo/app@sha256:abc123 && kubectl rollout restart deploy/app
等前面都确认过,再在流水线里加 digest 记录与校验
docker buildx imagetools inspect repo/app:1.9.1 --format '{{json .Manifest.Digest}}'
同事提醒我看一下最近一次发布,时间点确实对得上。
命令输出我都留了记录,免得改完记不清原来的值。
恢复的判定其实很直接。回滚后 Pod 的 imageID 与目标 digest 一致,接口版本号返回 1.9.1,节点上不再残留同 tag 的新镜像。
tag 是可变的,digest 才是身份,回滚要按 digest 部署,并在流水线里禁止同 tag 重复推送。这类问题最好一次改到位,反复小改反而容易把原因搅混。
