fix(docker): accept the pinned image id when the stores report different ids

Docker ids are not comparable across image stores: for the same content a
classic store reports the config digest while a containerd store (or an
image loaded from an OCI archive) reports the manifest digest. The
controller pins the id of its own daemon, so a compute whose store reports
another id for that content answered ImageMissingError forever: every node
creation streamed the image again (save/load round trip) without ever
converging, then failed with "The image 'x' is missing" after the six
retries. Docker 29 makes this easy to hit, since the id a daemon reports
now depends on how the image entered it.

The load endpoint now takes the tag and the digest pinned by the
controller, and the compute records how its own daemon identifies the
image it just received. Node creation accepts the pin through that pair,
and only while the tag still resolves to the synced content: a tag moved
to some other image, or an image the controller never pushed here, still
counts as missing. The pair lives in the compute process, so a restarted
compute syncs once more.

Computes that predate the new endpoint parameters keep the previous
behaviour, as do controllers that do not send them.
This commit is contained in:
YueGuobin committed 2026-10-13 17:10:17 +08:00
1 parent 6d838c890d
commit 90917c4a2c
8 files changed
+259 -19

No files matched your search

+13 -8
View File
@@ -591,15 +591,20 @@ class DockerVM(DockerKernelDatapathMixin, BaseNode):
if image_infos is None:
raise DockerError(f"Cannot get information for image '{self._image}', please try again.")
if self._image_digest and image_infos.get("Id") != self._image_digest:
local_id = image_infos.get("Id")
if self._image_digest and local_id != self._image_digest:
# the tag exists but points to a different image (e.g. a moved :latest):
# report it as missing so the controller re-syncs the expected version
local_id = image_infos.get("Id")
log.info(
f"Image '{self._image}' version mismatch on this compute: "
f"local id '{local_id}' != expected '{self._image_digest}'"
)
raise ImageMissingError(self._image)
# report it as missing so the controller re-syncs the expected version.
# Image ids are not comparable across image stores (a classic store
# reports the config digest where a containerd store, or an image
# loaded from an OCI archive, reports the manifest digest), so accept
# the pin for the image this compute received from the controller.
if self.manager.image_id_translation(self._image) != (self._image_digest, local_id):
log.info(
f"Image '{self._image}' version mismatch on this compute: "
f"local id '{local_id}' != expected '{self._image_digest}'"
)
raise ImageMissingError(self._image)
available_cpus = psutil.cpu_count(logical=True)
if self._cpus > available_cpus: