diff --git a/docs/agent-collab/addon-patch-image-build-handoff-roles-guide.md b/docs/agent-collab/addon-patch-image-build-handoff-roles-guide.md index 79514d1..201f244 100644 --- a/docs/agent-collab/addon-patch-image-build-handoff-roles-guide.md +++ b/docs/agent-collab/addon-patch-image-build-handoff-roles-guide.md @@ -57,6 +57,21 @@ Build 方不负责选择 PR,也不要复用旧 tag 覆盖不同镜像。 3. patch controller Deployment 的 image。 4. 重建 pod 后读取 `imageID`,确认它等于本次 build 的镜像。 +## Sideload + tag 别名陷阱 + +sideload 把镜像写进节点后,container runtime 上的同一个镜像可能同时挂着多个 tag。例如先用 base tag 拉过一次 base 镜像,又把 patch 镜像 sideload 进同一仓库时,runtime 会把 base tag 也指向 patch 镜像。kubelet 报到 pod 的 `status.containerStatuses[*].Image` 时,可能选其中**任意**一个 tag,并不保证用的是你 spec 里写的 patch tag。 + +如果 chart 用 tag 引用镜像,spec.Image 里是 patch tag,但 `status.Image` 显示成 base tag,KubeBlocks InstanceSet controller 现在还是用严格 tag 字符串比较来判 ready:tag 不一致 → 控制器认为 image 没匹配 → InstanceSet 不会标为 ready。 + +KubeBlocks 主分支的 InstanceSet controller 已经把 digest-pinned 场景接到 `status.ImageID` 兜底,但 tag-only 场景仍按严格 tag 比较,因为 controller 没法在运行时把 spec tag 解析回 digest 来分辨「同 digest 多 tag 别名」和「正常 image upgrade 待生效」这两个外观完全相同的情况。 + +所以 sideload 场景要么走出口 1,要么走出口 2: + +1. **删 base / 旧 tag 别名**:sideload patch 镜像后,把 runtime 上指向同一 digest 的 base / 旧 tag 删干净,只保留 patch tag。例:containerd `ctr -n k8s.io image rm `;docker `docker image rm `。tag 唯一以后 kubelet 报给 status 的就是 patch tag,InstanceSet 能正常 ready。 +2. **chart 改成 digest pin**:把 chart 里的 image 引用从 `repo:tag` 改成 `repo@sha256:...`。controller 拿到 digest pin 后,即使 `status.Image` 用 tag 形式不带 digest,也会用 `status.ImageID` 的 digest 兜底比较,能直接接受 sideload 镜像,不再依赖 tag 唯一性。 + +不论走哪条,最后都按一般规则核对 pod `imageID` 等于本次 build sha 作为收口,不要靠"pod 起来了"代替。 + ## 反模式 - 临时分支用 `release-*` 前缀。