Skip to content

Fallback to manifest list when no platform match#41955

Merged
thaJeztah merged 2 commits into
moby:masterfrom
cpuguy83:fallback_manifest_on_bad_plat
Feb 18, 2021
Merged

Fallback to manifest list when no platform match#41955
thaJeztah merged 2 commits into
moby:masterfrom
cpuguy83:fallback_manifest_on_bad_plat

Conversation

@cpuguy83

@cpuguy83 cpuguy83 commented Feb 1, 2021

Copy link
Copy Markdown
Member

relates to / addresses docker/for-linux#1170 (comment)

In some cases, in fact many in the wild, an image may have the incorrect
platform on the image config.
This can lead to failures to run an image, particularly when a user
specifies a --platform.
Typically what we see in the wild is a manifest list with an an entry
for, as an example, linux/arm64 pointing to an image config that has
linux/amd64 on it.

This change falls back to looking up the manifest list for an image to
see if the manifest list shows the image as the correct one for that
platform.

In order to accomplish this we need to traverse the leases associated
with an image. Each image, if pulled with Docker 20.10, will have the
manifest list stored in the containerd content store with the resource
assigned to a lease keyed on the image ID.
So we look up the lease for the image, then look up the assocated
resources to find the manifest list, then check the manifest list for a
platform match, then ensure that manifest referes to our image config.

This is only used as a fallback when a user specified they want a
particular platform and the image config that we have does not match
that platform.

@cpuguy83
cpuguy83 requested review from tianon and tonistiigi February 1, 2021 19:17
@cpuguy83
cpuguy83 force-pushed the fallback_manifest_on_bad_plat branch from 0d33ce8 to 217f0db Compare February 1, 2021 19:41
Comment thread daemon/images/image.go Outdated
@cpuguy83
cpuguy83 force-pushed the fallback_manifest_on_bad_plat branch 2 times, most recently from c9476b8 to 7f83ec5 Compare February 1, 2021 19:48
Comment thread daemon/images/image.go Outdated
Comment on lines 165 to 170

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.

Just to note it somewhere - this is due to a quirk in containerd's platform matching where platforms.Normalize is invoked on both the argument to platforms.Only and the things it's being compared against, so linux/arm gets normalized to linux/arm/v7 in both cases (and thus fails if you specify --platform linux/arm/v6 on a single-arch, no-manifest-list image that only has os and architecture).

Ideally, we'd fix platforms.Only in containerd to handle this case better, but it's complicated. 😅

@tianon tianon 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.

Conceptually this seems like a good workaround IMO - the logic in GetImage makes sense.

I did my best to review the flow in manifestMatchesPlatform and it seems sane to me, but I felt like I was stretching my understanding of all the APIs at play in reviewing it (so it should definitely get more eyes 🙈).

@thaJeztah

This comment has been minimized.

@thaJeztah

Copy link
Copy Markdown
Member

Also check how it behaves on https://hub.docker.com/r/balenalib/rpi-raspbian, which is not multi-arch, but has wrong arch

In some cases, in fact many in the wild, an image may have the incorrect
platform on the image config.
This can lead to failures to run an image, particularly when a user
specifies a `--platform`.
Typically what we see in the wild is a manifest list with an an entry
for, as an example, linux/arm64 pointing to an image config that has
linux/amd64 on it.

This change falls back to looking up the manifest list for an image to
see if the manifest list shows the image as the correct one for that
platform.

In order to accomplish this we need to traverse the leases associated
with an image. Each image, if pulled with Docker 20.10, will have the
manifest list stored in the containerd content store with the resource
assigned to a lease keyed on the image ID.
So we look up the lease for the image, then look up the assocated
resources to find the manifest list, then check the manifest list for a
platform match, then ensure that manifest referes to our image config.

This is only used as a fallback when a user specified they want a
particular platform and the image config that we have does not match
that platform.

Signed-off-by: Brian Goff <[email protected]>
@cpuguy83

cpuguy83 commented Feb 17, 2021

Copy link
Copy Markdown
Member Author

@thaJeztah That image doesn't have a manifest list so this PR doesn't improve anything there as far as I can tell.

@cpuguy83
cpuguy83 force-pushed the fallback_manifest_on_bad_plat branch from 7f83ec5 to 504e418 Compare February 17, 2021 20:42
@cpuguy83

Copy link
Copy Markdown
Member Author

I updated this to move the CPU variant fallback to a platform matcher that wraps platforms.Only.

re: #41955 (comment)

In the case where a user does specify a platform and there is no match we error out with the same details. I don't think it makes sense to warn and error.

@cpuguy83
cpuguy83 force-pushed the fallback_manifest_on_bad_plat branch from 504e418 to 78fb419 Compare February 17, 2021 21:21
@cpuguy83
cpuguy83 force-pushed the fallback_manifest_on_bad_plat branch from 78fb419 to ca81b2a Compare February 18, 2021 00:44
@thaJeztah thaJeztah added this to the 21.xx milestone Feb 18, 2021
@thaJeztah

Copy link
Copy Markdown
Member

Looks like there's a linting failiure;

daemon/images/image.go:184:3: S1023: redundant `return` statement (gosimple)
		return
 		^

Comment thread daemon/images/image.go Outdated
Comment on lines 183 to 184

@thaJeztah thaJeztah Feb 18, 2021

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.

Suggested change
retErr = errdefs.NotFound(errors.Errorf("image with reference %s was found but does not match the specified platform: wanted %s, actual: %s", refOrID, platforms.Format(p), platforms.Format(imgPlat)))
return
retErr = errdefs.NotFound(errors.Errorf("image with reference %s was found but does not match the specified platform: wanted %s, actual: %s", refOrID, platforms.Format(p), platforms.Format(imgPlat)))

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.

(edited; noticed this was in the defer, so no error to return)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed

Wrap platforms.Only and fallback to our ignore mismatches due to  empty
CPU variants. This just cleans things up and makes the logic re-usable
in other places.

Signed-off-by: Brian Goff <[email protected]>
@cpuguy83
cpuguy83 force-pushed the fallback_manifest_on_bad_plat branch from ca81b2a to 50f39e7 Compare February 18, 2021 16:59

@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.

SGTM

@tonistiigi tonistiigi 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.

SGTM

@thaJeztah

Copy link
Copy Markdown
Member

Test failiure is unrelated;


[2021-02-18T17:11:53.367Z] === FAIL: amd64.integration.image TestRemoveImageGarbageCollector (1.08s)
[2021-02-18T17:11:53.367Z]     remove_unix_test.go:82: assertion failed: error is not nil: Error: No such image: test-garbage-collector

that test has the same problem as I fixed in #41936

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants