Skip to content

fix: support pinned image where possible - #554

Merged
awphi merged 5 commits into
mainfrom
support-pinned-image-digests
Oct 21, 2026
Merged

awphi merged 5 commits into
mainfrom
support-pinned-image-digests

Conversation

@awphi

@awphi awphi commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Background

Problem 1 - Digest preserving re-tagging

Pinning images to specific digests atm doesn't work with Topo e.g.

services: 
  digest-pinned: 
    platform: linux/arm64
    image: busybox:1.37.0@sha256:f10e809bcf667d8e9f01d2baf82869049a495cd448cdfe1f4dee94078b960ae9

This is because after pulling the image on both the Host and then the Target, we attempt to re-tag it to either push to our local registry or allow compose to resolve the image without its repo identifier:

  • Pull on Host -> re-tag <image> as localhost:12737/<image> -> push to registry
  • Pull on Target from Host registry -> re-tag localhost:12737/<image> as <image> -> compose up

However, tags cannot contain digests - so we error out. This is fixed by this PR where feasible*

Problem 2 - multi-image indices

Image digests can point to one of two things:

  • Image manifests e.g. busybox:1.37.0@sha256:f10e809bcf667d8e9f01d2baf82869049a495cd448cdfe1f4dee94078b960ae9
  • Multi-image indices e.g. busybox:1.37.0@sha256:9db7b59979c38555a39def84a31fb98b5296952f9e3afd4f6f11f05b07adfab0

The former case is covered by problem 1. The latter case is more complex as this indices are an index of other images that the container engine will pick between based on your target platform. This means the digest your compose pins to, is not the digest of the image that actually runs. For normal docker/podman workflows this is fine but falls apart for our registry-based flow. Here's a docker example:

INDEX=sha256:9db7b59979c38555a39def84a31fb98b5296952f9e3afd4f6f11f05b07adfab0
DEST=localhost:12737/digest-demo/busybox

docker pull --platform linux/arm64 "busybox@$INDEX"
docker tag "busybox@$INDEX" "$DEST:demo"
docker push "$DEST:demo" # will warn with "Not all multiplatform-content is present and only the available single-platform image was pushed"
docker pull --platform linux/arm64 "$DEST@$INDEX" # will fail

The situation is (approximately) the same for podman but without the warning of what exactly it did, so unless you pay careful attention to the digests it spits out, the issue is hard to see.

This issue is addressed by this this PR in so far as helping you see what broke and how to fix it but does not add support for pinning to these indices as all the solutions I could come up with introduced yet more stuff to consider:

  • Using something like Skopeo or regclient to copy the image directly from the upstream registry into ours without the pull, re-tag, push dance. This would need care to ensure authenticated registries, proxies and mirrors etc that are configured by the container engine still work
  • Manually PUTing the index into the registry. The hard bit here is obtaining the orignal index byte-for-byte - if we source it from the upstream then we need authentication/proxy/mirror support again and sourcing it from the local cache requires a docker save for docker and fragile internal storage access in podman.
  • Falling back to save/load transfer for index-pinned images - works fine for docker but not for podman as it discards the original index digest and can re-compress the layers, changing the platform-specific image digest too 😢
  • Re-writing the deployed compose file - feels wrong on many levels since your deployed artifact no longer exactly matches what you passed into Topo.

and most of these would effectively requiring upgrading our Host-side registry to v3+ to support sparse indices so we don't pull an every platform's image when pinning to a multi-image index.

Changes

  • To fix re-tagging digest-pinned images this PR adds a check to the target container engine to check it uses an image store that preserves digests across re-tags + strips the SHA from the tag command.
    • *This means we still error out if your target uses docker's legacy overlay store, but the error attempts to be helpful.
  • Checks that the digest we push into the registry is the same as the one we pulled into the local image store on the Host and bail out if it changed to catch the multi-image index error case. Gives users something actionable to resolve this.

Checklist

  • 🤖 This change is covered by tests as required.
  • 🤹 All required manual testing has been performed.
  • 📖 All documentation updates are complete.

awphi added 2 commits October 16, 2026 18:29
Signed-off-by: awphi <adam.hodson@arm.com>
Signed-off-by: awphi <adam.hodson@arm.com>
@awphi
awphi requested a review from a team as a code owner October 20, 2026 09:34
Signed-off-by: awphi <adam.hodson@arm.com>
Comment thread internal/deploy/docker/engine.go

@yejseo01 yejseo01 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@awphi
awphi merged commit 0aa0303 into main Oct 21, 2026
5 checks passed
@awphi
awphi deleted the support-pinned-image-digests branch October 21, 2026 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants