Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

c8d: Use maximum native platform for matching#52773

Merged
thaJeztah merged 4 commits into
moby:mastermoby/moby:masterfrom
vvoland:c8d-amd64-variantsvvoland/moby:c8d-amd64-variantsCopy head branch name to clipboard
Jun 18, 2026
Merged

c8d: Use maximum native platform for matching#52773
thaJeztah merged 4 commits into
moby:mastermoby/moby:masterfrom
vvoland:c8d-amd64-variantsvvoland/moby:c8d-amd64-variantsCopy head branch name to clipboard

Conversation

@vvoland

@vvoland vvoland commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Summary

The containerd image-store path used platforms.Default() in several unspecified-platform selection paths.
On amd64, containerd's default platform does not include the detected x86-64 micro-architecture variant, so a host capable of linux/amd64/v4 can behave like plain linux/amd64 when selecting manifests.
That can skip compatible linux/amd64/v3 or linux/amd64/v2 entries and report that no suitable manifest exists.

Release notes (optional)

Fix image selection with the containerd image store on amd64 hosts when images provide amd64 variant-specific manifests.

A picture of a cute animal (not mandatory but encouraged)

@vvoland vvoland self-assigned this Jun 5, 2026
@vvoland vvoland changed the title WIP: Reproduce https://github.com/moby/moby/issues/52751 WIP: Reproduce #52751 Jun 5, 2026
@github-actions github-actions Bot added area/daemon Core Engine containerd-integration Issues and PRs related to containerd integration labels Jun 5, 2026
@vvoland
vvoland force-pushed the c8d-amd64-variants branch 2 times, most recently from c510f2d to 5a40751 Compare June 8, 2026 19:01
@vvoland vvoland changed the title WIP: Reproduce #52751 c8d: Use maximum native platform for matching Jun 8, 2026
@vvoland vvoland added this to the 29.6.0 milestone Jun 8, 2026
@vvoland vvoland added the kind/bugfix PR's that fix bugs label Jun 8, 2026
@vvoland

vvoland commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Related PR: containerd/platforms#7

Comment on lines +78 to +80
p := platforms.DefaultSpec()
if p.Architecture == "amd64" {
p.Variant = archvariant.AMD64Variant()

@thaJeztah thaJeztah Jun 8, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hm... is this something that should be fixed in containerd/platforms ? Looks like it has support for ARM, but not x86; also looks like there may be consistency between platforms;

func getCPUVariant() (string, error) {
var variant string
switch runtime.GOOS {
case "windows", "darwin":
// Windows/Darwin only supports v7 for ARM32 and v8 for ARM64 and so we can use
// runtime.GOARCH to determine the variants
switch runtime.GOARCH {
case "arm64":
variant = "v8"
case "arm":
variant = "v7"

// getCPUVariantFromArch get CPU variant from arch through a system call
func getCPUVariantFromArch(arch string) (string, error) {
var variant string
arch = strings.ToLower(arch)
if arch == "aarch64" {
variant = "8"
} else if arch[0:4] == "armv" && len(arch) >= 5 {
// Valid arch format is in form of armvXx
switch arch[3:5] {
case "v8":
variant = "8"
case "v7":
variant = "7"
case "v6":

switch strings.ToLower(variant) {
case "8", "aarch64":
variant = "v8"
case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
variant = "v7"
case "6", "6tej":

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ultimately containerd/platforms should probably have a helper for this, but in the meantime we need to fix this on our side.

@vvoland
vvoland marked this pull request as ready for review June 11, 2026 11:31
@cpuguy83

Copy link
Copy Markdown
Member

Running this docker-in-docker I'm only getting the base arch on my test image (cpuguy83/test-amd64-subarch).

@cpuguy83

Copy link
Copy Markdown
Member
root@f469b75813a2:/go/src/github.com/docker/docker# go run github.com/tonistiigi/go-archvariant/cmd/amd64variant@latest
go: downloading github.com/tonistiigi/go-archvariant v1.0.0
v4

Image details:

{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:b0e32519fd3a105f05077ff23435f1e765aef559276c40e9cfb30ae7566c0881",
      "size": 480,
      "platform": {
        "architecture": "amd64",
        "os": "linux",
        "variant": "v3"
      }
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:5c7289f3ea2f993df6165eedce27af0f89c7a92a96ea1674b0343bdc395356ea",
      "size": 480,
      "platform": {
        "architecture": "amd64",
        "os": "linux"
      }
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:95b800ddba20f213ae52d51c11c1945f034649c1ed36c9ed307724df9951fb0b",
      "size": 564,
      "annotations": {
        "vnd.docker.reference.digest": "sha256:b0e32519fd3a105f05077ff23435f1e765aef559276c40e9cfb30ae7566c0881",
        "vnd.docker.reference.type": "attestation-manifest"
      },
      "platform": {
        "architecture": "unknown",
        "os": "unknown"
      }
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:a4f33a94fda8eb41395d1c49185aaabf28b44cceec35564e1351258fa0e1a91e",
      "size": 564,
      "annotations": {
        "vnd.docker.reference.digest": "sha256:5c7289f3ea2f993df6165eedce27af0f89c7a92a96ea1674b0343bdc395356ea",
        "vnd.docker.reference.type": "attestation-manifest"
      },
      "platform": {
        "architecture": "unknown",
        "os": "unknown"
      }
    }
  ]
}

@cpuguy83

Copy link
Copy Markdown
Member

Oh, interesting:

root@f469b75813a2:/go/src/github.com/docker/docker# docker run -it --rm cpuguy83/test-amd64-subarch
Unable to find image 'cpuguy83/test-amd64-subarch:latest' locally
latest: Pulling from cpuguy83/test-amd64-subarch
a278e1f259fb: Pull complete
ff353f22e1e2: Download complete
Digest: sha256:1598e33bd98eb272b771fb2207261b9dbf4cc7c5c683e42d45d80470468f403b
Status: Downloaded newer image for cpuguy83/test-amd64-subarch:latest
Hello from amd64/v1
root@f469b75813a2:/go/src/github.com/docker/docker# docker run --platform linux/amd64/v3 -it --rm cpuguy83/test-amd64-subarch
Unable to find image 'cpuguy83/test-amd64-subarch:latest' locally
latest: Pulling from cpuguy83/test-amd64-subarch
3d9b1ff0e3ff: Pull complete
f7500c9d6b27: Download complete
Digest: sha256:1598e33bd98eb272b771fb2207261b9dbf4cc7c5c683e42d45d80470468f403b
Status: Image is up to date for cpuguy83/test-amd64-subarch:latest
Hello from amd64/v3
root@f469b75813a2:/go/src/github.com/docker/docker# docker run -it --rm cpuguy83/test-amd64-subarch
Hello from amd64/v3
root@f469b75813a2:/go/src/github.com/docker/docker# docker run --platform linux/amd64/v1 -it --rm cpuguy83/test-amd64-subarch
Hello from amd64/v1
root@f469b75813a2:/go/src/github.com/docker/docker# docker run -it --rm cpuguy83/test-amd64-subarch
Hello from amd64/v3

Comment thread daemon/containerd/image_pull.go Outdated
}

p := platforms.Default()
p := i.hostPlatformMatcher()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This p never reaches client.Pull, so the variant-aware host platform isn't applied at pull time.

When platform == nil, no containerd.WithPlatform(...) opt is added (the opts block higher up only sets it when a platform is requested), and p is only handed to c8dimages.Check below — the progress check. In vendored client/pull.go (L63-67), an empty Platforms makes client.Pull fall back to c.platform, which is the containerd client default (platforms.Default(), plain amd64, no variant) since we construct the client without WithDefaultPlatform in daemon.go.

Net effect: a plain docker pull/docker run on a v4 host downloads and unpacks the v1 manifest. LimitManifests (limit 1) sorts the index by the variant-less matcher, so plain amd64 wins over amd64/v3. The store-side matching this PR adds is correct — which is why once v3 is in the store a subsequent plain docker run resolves to v3 — but the initial pull selection bypasses it.

Repro on a v4 host with an index containing amd64 + amd64/v3:

  • docker run <img> -> Hello from amd64/v1
  • docker run --platform linux/amd64/v3 <img> -> pulls v3
  • docker run <img> -> now Hello from amd64/v3

Suggested fix: pass the host spec through to the pull when no platform was requested, e.g. always add containerd.WithPlatform(platforms.FormatAll(i.hostPlatformSpec())) (using *platform when set). That gives containerd Only(amd64/v4), whose fallback vector still matches plain amd64, so it selects v3 here and stays consistent with the store-side matcher.

Review from Claude Opus 4.8

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@vvoland ptal

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I pushed a commit to address this. Can you verify on your side it's ok now?
It's late now and I didn't manage to get to my amd64 machine to test this properly 🙈

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Now the behavior is less suprising, but it only does v3 when specifically requested.
Not sure if that's the intent (certainly for builds it likely should be?).

Details
root@95139424b3c3:/go/src/github.com/docker/docker# docker run -it --rm cpuguy83/test-amd64-subarch
Unable to find image 'cpuguy83/test-amd64-subarch:latest' locally
latest: Pulling from cpuguy83/test-amd64-subarch
a278e1f259fb: Pull complete
ff353f22e1e2: Download complete
Digest: sha256:1598e33bd98eb272b771fb2207261b9dbf4cc7c5c683e42d45d80470468f403b
Status: Downloaded newer image for cpuguy83/test-amd64-subarch:latest
Hello from amd64/v1
root@95139424b3c3:/go/src/github.com/docker/docker# docker run -it --rm cpuguy83/test-amd64-subarch
Hello from amd64/v1
root@95139424b3c3:/go/src/github.com/docker/docker# docker run -it --rm --platform linux/amd64/v3 cpuguy83/test-amd64-subarch
Unable to find image 'cpuguy83/test-amd64-subarch:latest' locally
latest: Pulling from cpuguy83/test-amd64-subarch
3d9b1ff0e3ff: Pull complete
f7500c9d6b27: Download complete
Digest: sha256:1598e33bd98eb272b771fb2207261b9dbf4cc7c5c683e42d45d80470468f403b
Status: Image is up to date for cpuguy83/test-amd64-subarch:latest
Hello from amd64/v3
root@95139424b3c3:/go/src/github.com/docker/docker# docker run -it --rm cpuguy83/test-amd64-subarch
Hello from amd64/v1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Oh I see now, it's only the case if you have amd64/v1 locally.

If you don't then it will still prefer pulling v3:

root@1e364b189a46:/go/src/github.com/docker/docker# docker images
                                                                                                     i Info →   U  In Use
IMAGE   ID             DISK USAGE   CONTENT SIZE   EXTRA

root@1e364b189a46:/go/src/github.com/docker/docker# docker run cpuguy83/test-amd64-subarch:latest
Unable to find image 'cpuguy83/test-amd64-subarch:latest' locally
latest: Pulling from cpuguy83/test-amd64-subarch
3d9b1ff0e3ff: Pull complete 
f7500c9d6b27: Download complete 
Digest: sha256:1598e33bd98eb272b771fb2207261b9dbf4cc7c5c683e42d45d80470468f403b
Status: Downloaded newer image for cpuguy83/test-amd64-subarch:latest
Hello from amd64/v3

but if you have v1 already, it will just use this one using the "best locally available platform" logic.

This is also visible with non-native platforms:

root@1e364b189a46:/go/src/github.com/docker/docker# docker pull --linux/arm64 alpine
root@1e364b189a46:/go/src/github.com/docker/docker# docker run alpine
WARNING: The requested image's platform (linux/arm64/v8) does not match the detected host platform (linux/amd64/v3) and no specific platform was requested

See: #50043

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oh, looks like I must have had an issue checking out the branch before (stale git lock file).
Fixed it and now this is running as expected.

@vvoland
vvoland marked this pull request as draft June 12, 2026 17:36
vvoland added 4 commits June 17, 2026 22:09
Tests should replace the detected host platform, not the matcher built
from it.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
Introduce `hostPlatformSpec` as a replacement, so we can decouple from
containerd platforms logic and override for tests.

Default image-store operations should share the same host platform
preference as pulls, otherwise list, identity cache, and classic-builder
selection can still rank plain linux/amd64 ahead of compatible amd64
variants.

Route those unspecified-platform paths through the ImageService host
matcher so amd64 variant fallback stays consistent.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
containerd's default platform spec does not include amd64 CPU
variants.

Populate the host platform spec with the detected amd64 compatibility
level, using the existing go-archvariant dependency, so containerd
image-store matchers can prefer compatible variant manifests.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
Always pass the pull platform through WithPlatform.

For implicit pulls this is the host platform, including the amd64
variant; for explicit pulls it remains the requested platform.

This doesn't make the platform matching strict - containerd resolves
WithPlatform through platforms.Only, so linux/amd64/v3 still falls back
to compatible lower or plain linux/amd64 manifests when no v3 manifest
exists.

This keeps initial pull selection consistent with store-side matching
and preserves compatibility with non-variant amd64 images.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
@vvoland
vvoland force-pushed the c8d-amd64-variants branch from ef5b04e to d98515d Compare June 17, 2026 20:18
@vvoland
vvoland marked this pull request as ready for review June 18, 2026 15:05

@thaJeztah thaJeztah left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@thaJeztah
thaJeztah merged commit b6c53c2 into moby:master Jun 18, 2026
311 of 313 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/daemon Core Engine containerd-integration Issues and PRs related to containerd integration impact/changelog kind/bugfix PR's that fix bugs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Docker Image Pull/use not properly falling back to next-best architecture

3 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.