diff --git a/commands/build.go b/commands/build.go index 9c3ae2802992..3938e1bf1a4a 100644 --- a/commands/build.go +++ b/commands/build.go @@ -33,6 +33,7 @@ import ( "github.com/docker/buildx/util/cobrautil" "github.com/docker/buildx/util/confutil" "github.com/docker/buildx/util/desktop" + "github.com/docker/buildx/util/dockerutil" "github.com/docker/buildx/util/ioset" "github.com/docker/buildx/util/metricutil" "github.com/docker/buildx/util/osutil" @@ -321,12 +322,18 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions) if err != nil { return err } + _, err = b.LoadNodes(ctx) if err != nil { return err } driverType := b.Driver + dockerUsingContainerdSnapshotter := false + if driverType == "docker" || driverType == "docker-container" { + dockerUsingContainerdSnapshotter = isDockerUsingContainerdSnapshotter(ctx, dockerCli) + } + var term bool if _, err := console.ConsoleFromFile(os.Stderr); err == nil { term = true @@ -377,12 +384,12 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions) case progressui.RawJSONMode: // no additional display case progressui.QuietMode: - fmt.Println(getImageID(resp.ExporterResponse)) + fmt.Println(getImageID(resp.ExporterResponse, dockerUsingContainerdSnapshotter)) default: desktop.PrintBuildDetails(os.Stderr, printer.BuildRefs(), term) } if options.imageIDFile != "" { - if err := os.WriteFile(options.imageIDFile, []byte(getImageID(resp.ExporterResponse)), 0644); err != nil { + if err := os.WriteFile(options.imageIDFile, []byte(getImageID(resp.ExporterResponse, dockerUsingContainerdSnapshotter)), 0644); err != nil { return errors.Wrap(err, "writing image ID file") } } @@ -408,12 +415,26 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions) } // getImageID returns the image ID - the digest of the image config -func getImageID(resp map[string]string) string { - dgst := resp[exptypes.ExporterImageDigestKey] - if v, ok := resp[exptypes.ExporterImageConfigDigestKey]; ok { - dgst = v +func getImageID(resp map[string]string, dockerUsingContainerdSnapshotter bool) string { + if dockerUsingContainerdSnapshotter { + // If Docker is using the containerd snapshotter, use the image digest, not + // the image config digest. See https://github.com/moby/moby/issues/45458. + return resp[exptypes.ExporterImageDigestKey] + } else { + return resp[exptypes.ExporterImageConfigDigestKey] } - return dgst +} + +func isDockerUsingContainerdSnapshotter(ctx context.Context, dockerCli command.Cli) bool { + usingContainerdSnapshotter := false + + docker := dockerutil.NewClient(dockerCli) + features := docker.Features(ctx, "") + if features[dockerutil.OCIImporter] { + usingContainerdSnapshotter = true + } + + return usingContainerdSnapshotter } func runBasicBuild(ctx context.Context, dockerCli command.Cli, opts *controllerapi.BuildOptions, printer *progress.Printer) (*client.SolveResponse, *build.Inputs, error) { diff --git a/driver/docker-container/driver.go b/driver/docker-container/driver.go index 45f77b3146d3..1c571a5be8e1 100644 --- a/driver/docker-container/driver.go +++ b/driver/docker-container/driver.go @@ -63,6 +63,20 @@ func (d *Driver) IsMobyDriver() bool { return false } +func (d *Driver) UsesContainerdSnapshotter(ctx context.Context) bool { + var containerdSnapshotter bool + if c, err := d.Client(ctx); err == nil { + workers, _ := c.ListWorkers(ctx) + for _, w := range workers { + if _, ok := w.Labels["org.mobyproject.buildkit.worker.snapshotter"]; ok { + containerdSnapshotter = true + } + } + c.Close() + } + return containerdSnapshotter +} + func (d *Driver) Config() driver.InitConfig { return d.InitConfig } diff --git a/driver/docker/driver.go b/driver/docker/driver.go index 63682f9df2fe..9a32928cc48a 100644 --- a/driver/docker/driver.go +++ b/driver/docker/driver.go @@ -78,16 +78,7 @@ type features struct { func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool { d.features.once.Do(func() { - var useContainerdSnapshotter bool - if c, err := d.Client(ctx); err == nil { - workers, _ := c.ListWorkers(ctx) - for _, w := range workers { - if _, ok := w.Labels["org.mobyproject.buildkit.worker.snapshotter"]; ok { - useContainerdSnapshotter = true - } - } - c.Close() - } + useContainerdSnapshotter := d.UsesContainerdSnapshotter(ctx) d.features.list = map[driver.Feature]bool{ driver.OCIExporter: useContainerdSnapshotter, driver.DockerExporter: useContainerdSnapshotter, @@ -144,6 +135,20 @@ func (d *Driver) IsMobyDriver() bool { return true } +func (d *Driver) UsesContainerdSnapshotter(ctx context.Context) bool { + var containerdSnapshotter bool + if c, err := d.Client(ctx); err == nil { + workers, _ := c.ListWorkers(ctx) + for _, w := range workers { + if _, ok := w.Labels["org.mobyproject.buildkit.worker.snapshotter"]; ok { + containerdSnapshotter = true + } + } + c.Close() + } + return containerdSnapshotter +} + func (d *Driver) Config() driver.InitConfig { return d.InitConfig } diff --git a/driver/driver.go b/driver/driver.go index c82852cd8fc1..5d8c9b846cbb 100644 --- a/driver/driver.go +++ b/driver/driver.go @@ -74,6 +74,7 @@ type Driver interface { Features(ctx context.Context) map[Feature]bool HostGatewayIP(ctx context.Context) (net.IP, error) IsMobyDriver() bool + UsesContainerdSnapshotter(ctx context.Context) bool Config() InitConfig } diff --git a/driver/kubernetes/driver.go b/driver/kubernetes/driver.go index 3bfe568a5802..7a799a91a661 100644 --- a/driver/kubernetes/driver.go +++ b/driver/kubernetes/driver.go @@ -59,6 +59,10 @@ func (d *Driver) IsMobyDriver() bool { return false } +func (d *Driver) UsesContainerdSnapshotter(ctx context.Context) bool { + return false +} + func (d *Driver) Config() driver.InitConfig { return d.InitConfig } diff --git a/driver/remote/driver.go b/driver/remote/driver.go index 22145dd62bad..a976a835a464 100644 --- a/driver/remote/driver.go +++ b/driver/remote/driver.go @@ -181,6 +181,10 @@ func (d *Driver) IsMobyDriver() bool { return false } +func (d *Driver) UsesContainerdSnapshotter(ctx context.Context) bool { + return false +} + func (d *Driver) Config() driver.InitConfig { return d.InitConfig } diff --git a/tests/build.go b/tests/build.go index 09a75dc47062..6c3295773b0b 100644 --- a/tests/build.go +++ b/tests/build.go @@ -399,18 +399,9 @@ func testImageIDOutput(t *testing.T, sb integration.Sandbox) { require.Equal(t, dgst.String(), strings.TrimSpace(stdout.String())) - dt, err = os.ReadFile(filepath.Join(targetDir, "md.json")) - require.NoError(t, err) - - type mdT struct { - ConfigDigest string `json:"containerimage.config.digest"` - } - var md mdT - err = json.Unmarshal(dt, &md) - require.NoError(t, err) - - require.NotEmpty(t, md.ConfigDigest) - require.Equal(t, dgst, digest.Digest(md.ConfigDigest)) + // verify the image ID is the correct one + cmd = dockerCmd(sb, withArgs("run", imageID)) + require.NoError(t, cmd.Run()) } func testBuildMobyFromLocalImage(t *testing.T, sb integration.Sandbox) {