fix(build): use image content digest, not attested index digest#13946
Open
nabsei wants to merge 1 commit into
Open
fix(build): use image content digest, not attested index digest#13946nabsei wants to merge 1 commit into
nabsei wants to merge 1 commit into
Conversation
docker compose build (via Bake) recorded BuildKit's top-level "containerimage.digest" as the built image's identity. With provenance attestations enabled (the default) and the containerd image store, that digest covers the attestation manifest as well as the image manifest, and changes on every build even when the runnable image content is unchanged. This made compose recreate containers on every `up --build`, even with a fully cached build. Instead, inspect the built (or already local) image with the manifests API (Engine >= 28.0 / API 1.48) and use the digest of the "image" kind manifest, which reflects only the actual image content. Images that only exist in a registry (push/multi-platform builds) keep the Bake-reported digest, since they aren't inspectable locally. Fixes docker#13636 Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: nabsei <nsahrane@hotmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What I did
docker compose build(via Bake) recorded BuildKit's top-levelcontainerimage.digestmetadata field as the built image's identity, used to decide whether a container needs to be recreated. With provenance attestations enabled (the default since recent Buildx/BuildKit) and the containerd image store, this digest is for the whole attested index (image manifest + attestation manifest), and it changes on every build — even a fully cached one — because the attestation manifest embeds per-build metadata (timestamps, build refs). The image content itself never changes.This made
docker compose up --buildrecreate containers unnecessarily on every run, even when nothing actually changed.The fix inspects the built (or already-local) image via the Engine API with
manifests=true(API 1.48+ / Engine 28.0+) and picks the digest of the manifest withKind == "image", ignoring the"attestation"manifest. That digest only reflects the actual image content (config + layers), so it's stable across rebuilds with unchanged content, and still changes correctly when the content does change. I applied the same fix togetImageSummaries(used for already-local images) so both sides of the staleness comparison use the same, consistent digest. Images that only exist in a registry (push / multi-platform builds) aren't locally inspectable, so they keep the Bake-reported digest as before — this only affects the common local build case where the bug was reported.Verification
I reproduced the bug against a real Docker Desktop engine (containerd snapshotter, default provenance attestations on arm64), confirmed the root cause by inspecting BuildKit's raw Bake metadata and the daemon's
manifests=trueimage inspect response directly, then verified the fix end-to-end:docker buildx bakeon an unchanged Dockerfile produces a differentcontainerimage.digest/image ID on every run despiteCACHEDbuild steps.docker compose up -d --buildruns with no changes keep the exact same container (same ID, same creation timestamp) — no unnecessary recreate.Recreate/Recreated.go build ./...,go vet ./..., andgolangci-lint runare all clean.go test ./...passes; the only pre-existing failures (inpkg/watchandpkg/e2e) are environmental/flaky and reproduce identically on unmodifiedmain, unrelated to this change.TestContentDigest,TestGetImageSummariesUsesContentDigestNotAttestedIndexDigest) covering the digest-selection logic directly.Related issue
Fixes #13636
Disclosure: this PR was prepared with the assistance of Claude Code (Anthropic). All investigation, the root-cause diagnosis, the fix, and the verification steps above were done and checked by me; I'm disclosing the tool's involvement for transparency.