From 7429792eed401c630d72cf296a921ee86d525579 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 26 Apr 2021 12:41:40 +0200 Subject: [PATCH] docker pull: warn when pulled single-arch image does not match --platform This takes the same approach as was implemented on `docker build`, where a warning is printed if `FROM --platform=...` is used (added in 399695305c67aae1010e6754f90f9078aa39e742) Before: docker rmi armhf/busybox docker pull --platform=linux/s390x armhf/busybox Using default tag: latest latest: Pulling from armhf/busybox d34a655120f5: Pull complete Digest: sha256:8e51389cdda2158935f2b231cd158790c33ae13288c3106909324b061d24d6d1 Status: Downloaded newer image for armhf/busybox:latest docker.io/armhf/busybox:latest With this change: docker rmi armhf/busybox docker pull --platform=linux/s390x armhf/busybox Using default tag: latest latest: Pulling from armhf/busybox d34a655120f5: Pull complete Digest: sha256:8e51389cdda2158935f2b231cd158790c33ae13288c3106909324b061d24d6d1 Status: Downloaded newer image for armhf/busybox:latest WARNING: image with reference armhf/busybox was found but does not match the specified platform: wanted linux/s390x, actual: linux/arm64 docker.io/armhf/busybox:latest And daemon logs print: WARN[2021-04-26T11:19:37.153572667Z] ignoring platform mismatch on single-arch image error="image with reference armhf/busybox was found but does not match the specified platform: wanted linux/s390x, actual: linux/arm64" image=armhf/busybox When pulling without specifying `--platform, no warning is currently printed (but we can add a warning in future); docker rmi armhf/busybox docker pull armhf/busybox Using default tag: latest latest: Pulling from armhf/busybox d34a655120f5: Pull complete Digest: sha256:8e51389cdda2158935f2b231cd158790c33ae13288c3106909324b061d24d6d1 Status: Downloaded newer image for armhf/busybox:latest docker.io/armhf/busybox:latest Signed-off-by: Sebastiaan van Stijn (cherry picked from commit 424c0eb3c09d373aaa9c72d81bb1c557d2e0f2e1) Signed-off-by: Sebastiaan van Stijn --- daemon/images/image_pull.go | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/daemon/images/image_pull.go b/daemon/images/image_pull.go index ed9099b2ef..d326caa9c6 100644 --- a/daemon/images/image_pull.go +++ b/daemon/images/image_pull.go @@ -15,10 +15,12 @@ import ( progressutils "github.com/docker/docker/distribution/utils" "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/progress" + "github.com/docker/docker/pkg/streamformatter" "github.com/docker/docker/registry" digest "github.com/opencontainers/go-digest" specs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // PullImage initiates a pull operation. image is the repository name to pull, and @@ -51,7 +53,29 @@ func (i *ImageService) PullImage(ctx context.Context, image, tag string, platfor err = i.pullImageWithReference(ctx, ref, platform, metaHeaders, authConfig, outStream) imageActions.WithValues("pull").UpdateSince(start) - return err + if err != nil { + return err + } + + if platform != nil { + // If --platform was specified, check that the image we pulled matches + // the expected platform. This check is for situations where the image + // is a single-arch image, in which case (for backward compatibility), + // we allow the image to have a non-matching architecture. The code + // below checks for this situation, and returns a warning to the client, + // as well ass logs it to the daemon logs. + img, err := i.GetImage(image, platform) + + // Note that this is a special case where GetImage returns both an image + // and an error: https://github.com/docker/docker/blob/v20.10.7/daemon/images/image.go#L175-L183 + if errdefs.IsNotFound(err) && img != nil { + po := streamformatter.NewJSONProgressOutput(outStream, false) + progress.Messagef(po, "", `WARNING: %s`, err.Error()) + logrus.WithError(err).WithField("image", image).Warn("ignoring platform mismatch on single-arch image") + } + } + + return nil } func (i *ImageService) pullImageWithReference(ctx context.Context, ref reference.Named, platform *specs.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {