Skip to content

Commit abbd9e7

Browse files
committed
Output correct image ID when using Docker with the containerd-snapshotter.
Prior to this change, the following command emits the wrong image ID when buildx uses the "docker-container" driver and Docker is configured with the containerd-snapshotter. $ docker buildx build --load --iidfile=img.txt $ docker run --rm "$(cat img.txt)" echo hello docker: Error response from daemon: No such image: sha256:4ac37e81e00f242010e42f3251094e47de6100e01d25e9bd0feac6b8906976df. See 'docker run --help'. The problem is that buildx is outputing the incorrect image ID in this scenario (it's outputing the container image config digest, instead of the container image digest used by the containerd-snapshotter). This commit fixes this. See moby/moby#45458. Signed-off-by: Cesar Talledo <[email protected]>
1 parent bad5063 commit abbd9e7

File tree

5 files changed

+29
-5
lines changed

5 files changed

+29
-5
lines changed

build/build.go

+7
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,13 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opts map[
534534
}
535535
}
536536
}
537+
// if prefer-image-digest is set in the solver options, set it in the response
538+
for _, e := range so.Exports {
539+
if e.Attrs["prefer-image-digest"] == "true" {
540+
res[i].PreferImageDigest = true
541+
break
542+
}
543+
}
537544

538545
node := dp.Node().Driver
539546
if node.IsMobyDriver() {

build/opt.go

+5
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,11 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt *O
237237
opt.Exports[i].Output = func(_ map[string]string) (io.WriteCloser, error) {
238238
return w, nil
239239
}
240+
// if docker is using the containerd snapshotter, prefer to export the image digest
241+
// (rather than the image config digest). See https://github.com/moby/moby/issues/45458.
242+
if features[dockerutil.OCIImporter] {
243+
opt.Exports[i].Attrs["prefer-image-digest"] = "true"
244+
}
240245
}
241246
} else if !nodeDriver.Features(ctx)[driver.DockerExporter] {
242247
return nil, nil, notSupported(driver.DockerExporter, nodeDriver, "https://docs.docker.com/go/build-exporters/")

commands/build.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions)
321321
if err != nil {
322322
return err
323323
}
324+
324325
_, err = b.LoadNodes(ctx)
325326
if err != nil {
326327
return err
@@ -377,12 +378,12 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions)
377378
case progressui.RawJSONMode:
378379
// no additional display
379380
case progressui.QuietMode:
380-
fmt.Println(getImageID(resp.ExporterResponse))
381+
fmt.Println(getImageID(resp.ExporterResponse, resp.PreferImageDigest))
381382
default:
382383
desktop.PrintBuildDetails(os.Stderr, printer.BuildRefs(), term)
383384
}
384385
if options.imageIDFile != "" {
385-
if err := os.WriteFile(options.imageIDFile, []byte(getImageID(resp.ExporterResponse)), 0644); err != nil {
386+
if err := os.WriteFile(options.imageIDFile, []byte(getImageID(resp.ExporterResponse, resp.PreferImageDigest)), 0644); err != nil {
386387
return errors.Wrap(err, "writing image ID file")
387388
}
388389
}
@@ -412,8 +413,11 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions)
412413
}
413414

414415
// getImageID returns the image ID - the digest of the image config
415-
func getImageID(resp map[string]string) string {
416+
func getImageID(resp map[string]string, preferImageDigest bool) string {
416417
dgst := resp[exptypes.ExporterImageDigestKey]
418+
if preferImageDigest {
419+
return dgst
420+
}
417421
if v, ok := resp[exptypes.ExporterImageConfigDigestKey]; ok {
418422
dgst = v
419423
}

tests/build.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -399,18 +399,25 @@ func testImageIDOutput(t *testing.T, sb integration.Sandbox) {
399399

400400
require.Equal(t, dgst.String(), strings.TrimSpace(stdout.String()))
401401

402+
// read the md.json file
402403
dt, err = os.ReadFile(filepath.Join(targetDir, "md.json"))
403404
require.NoError(t, err)
404405

405406
type mdT struct {
407+
Digest string `json:"containerimage.digest"`
406408
ConfigDigest string `json:"containerimage.config.digest"`
407409
}
410+
408411
var md mdT
409412
err = json.Unmarshal(dt, &md)
410413
require.NoError(t, err)
411414

412415
require.NotEmpty(t, md.ConfigDigest)
413-
require.Equal(t, dgst, digest.Digest(md.ConfigDigest))
416+
require.NotEmpty(t, md.Digest)
417+
418+
// verify the image ID output is correct
419+
// XXX: improve this by checking that it's one of the two expected digests depending on the scenario.
420+
require.Contains(t, []digest.Digest{digest.Digest(md.ConfigDigest), digest.Digest(md.Digest)}, dgst)
414421
}
415422

416423
func testBuildMobyFromLocalImage(t *testing.T, sb integration.Sandbox) {

vendor/github.com/moby/buildkit/client/graph.go

+2-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)