From 399695305c67aae1010e6754f90f9078aa39e742 Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Wed, 13 Jan 2021 01:14:36 +0000 Subject: [PATCH] Fix builder inconsistent error on buggy platform When pulling an image by platform, it is possible for the image's configured platform to not match what was in the manifest list. The image itself is buggy because either the manifest list is incorrect or the image config is incorrect. In any case, this is preventing people from upgrading because many times users do not have control over these buggy images. This was not a problem in 19.03 because we did not compare on platform before. It just assumed if we had the image it was the one we wanted regardless of platform, which has its own problems. Example Dockerfile that has this problem: ```Dockerfile FROM --platform=linux/arm64 k8s.gcr.io/build-image/debian-iptables:buster-v1.3.0 RUN echo hello ``` This fails the first time you try to build after it finishes pulling but before performing the `RUN` command. On the second attempt it works because the image is already there and does not hit the code that errors out on platform mismatch (Actually it ignores errors if an image is returned at all). Must be run with the classic builder (DOCKER_BUILDKIT=0). Signed-off-by: Brian Goff --- daemon/images/image_builder.go | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/daemon/images/image_builder.go b/daemon/images/image_builder.go index 2fd4335d6b..d401438ca2 100644 --- a/daemon/images/image_builder.go +++ b/daemon/images/image_builder.go @@ -5,18 +5,23 @@ import ( "io" "runtime" + "github.com/containerd/containerd/platforms" "github.com/docker/distribution/reference" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/backend" "github.com/docker/docker/builder" + "github.com/docker/docker/errdefs" "github.com/docker/docker/image" "github.com/docker/docker/layer" "github.com/docker/docker/pkg/containerfs" + "github.com/docker/docker/pkg/progress" + "github.com/docker/docker/pkg/streamformatter" "github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/system" "github.com/docker/docker/registry" specs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) type roLayer struct { @@ -161,7 +166,29 @@ func (i *ImageService) pullForBuilder(ctx context.Context, name string, authConf if err := i.pullImageWithReference(ctx, ref, platform, nil, pullRegistryAuth, output); err != nil { return nil, err } - return i.GetImage(name, platform) + + img, err := i.GetImage(name, platform) + if errdefs.IsNotFound(err) && img != nil && platform != nil { + imgPlat := specs.Platform{ + OS: img.OS, + Architecture: img.BaseImgArch(), + Variant: img.BaseImgVariant(), + } + + p := *platform + if !platforms.Only(p).Match(imgPlat) { + po := streamformatter.NewJSONProgressOutput(output, false) + progress.Messagef(po, "", ` +WARNING: Pulled image with specified platform (%s), but the resulting image's configured platform (%s) does not match. +This is most likely caused by a bug in the build system that created the fetched image (%s). +Please notify the image author to correct the configuration.`, + platforms.Format(p), platforms.Format(imgPlat), name, + ) + logrus.WithError(err).WithField("image", name).Warn("Ignoring error about platform mismatch where the manifest list points to an image whose configuration does not match the platform in the manifest.") + err = nil + } + } + return img, err } // GetImageAndReleasableLayer returns an image and releaseable layer for a reference or ID.