From 183a73abae1142f05d5636fadb93466680d19649 Mon Sep 17 00:00:00 2001 From: Justin Chadwell Date: Fri, 19 May 2023 10:49:36 +0100 Subject: [PATCH] build: docker exporter should instead use oci with containerd Signed-off-by: Justin Chadwell --- build/build.go | 20 ++++++++++++-------- util/dockerutil/client.go | 17 +++++++++++++++++ util/dockerutil/features.go | 5 +++++ 3 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 util/dockerutil/features.go diff --git a/build/build.go b/build/build.go index 4fd3cb11..ee077a46 100644 --- a/build/build.go +++ b/build/build.go @@ -363,7 +363,7 @@ func toRepoOnly(in string) (string, error) { return strings.Join(out, ","), nil } -func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Options, bopts gateway.BuildOpts, configDir string, pw progress.Writer, dl dockerLoadCallback) (solveOpt *client.SolveOpt, release func(), err error) { +func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Options, bopts gateway.BuildOpts, configDir string, pw progress.Writer, docker *dockerutil.Client) (solveOpt *client.SolveOpt, release func(), err error) { nodeDriver := node.Driver defers := make([]func(), 0, 2) releaseF := func() { @@ -531,14 +531,22 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op return nil, nil, notSupported(nodeDriver, driver.OCIExporter) } if e.Type == "docker" { - if len(opt.Platforms) > 1 || len(attests) > 0 { + features := docker.Features(ctx, e.Attrs["context"]) + if features[dockerutil.OCIImporter] && e.Output == nil { + // rely on oci importer if available (which supports + // multi-platform images), otherwise fall back to docker + opt.Exports[i].Type = "oci" + } else if len(opt.Platforms) > 1 || len(attests) > 0 { + if e.Output != nil { + return nil, nil, errors.Errorf("docker exporter does not support exporting manifest lists, use the oci exporter instead") + } return nil, nil, errors.Errorf("docker exporter does not currently support exporting manifest lists") } if e.Output == nil { if nodeDriver.IsMobyDriver() { e.Type = "image" } else { - w, cancel, err := dl(e.Attrs["context"]) + w, cancel, err := docker.LoadImage(ctx, e.Attrs["context"], pw) if err != nil { return nil, nil, err } @@ -733,9 +741,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s hasMobyDriver = true } opt.Platforms = np.platforms - so, release, err := toSolveOpt(ctx, node, multiDriver, opt, np.bopts, configDir, w, func(name string) (io.WriteCloser, func(), error) { - return docker.LoadImage(ctx, name, w) - }) + so, release, err := toSolveOpt(ctx, node, multiDriver, opt, np.bopts, configDir, w, docker) if err != nil { return nil, err } @@ -1543,8 +1549,6 @@ func notSupported(d driver.Driver, f driver.Feature) error { return errors.Errorf("%s feature is currently not supported for %s driver. Please switch to a different driver (eg. \"docker buildx create --use\")", f, d.Factory().Name()) } -type dockerLoadCallback func(name string) (io.WriteCloser, func(), error) - func noDefaultLoad() bool { v, ok := os.LookupEnv("BUILDX_NO_DEFAULT_LOAD") if !ok { diff --git a/util/dockerutil/client.go b/util/dockerutil/client.go index 04b09ede..c415e0dd 100644 --- a/util/dockerutil/client.go +++ b/util/dockerutil/client.go @@ -63,6 +63,23 @@ func (c *Client) LoadImage(ctx context.Context, name string, status progress.Wri }, nil } +func (c *Client) Features(ctx context.Context, name string) map[Feature]bool { + features := make(map[Feature]bool) + if dapi, err := c.API(name); err == nil { + if info, err := dapi.Info(ctx); err == nil { + for _, v := range info.DriverStatus { + switch v[0] { + case "driver-type": + if v[1] == "io.containerd.snapshotter.v1" { + features[OCIImporter] = true + } + } + } + } + } + return features +} + type waitingWriter struct { *io.PipeWriter f func() diff --git a/util/dockerutil/features.go b/util/dockerutil/features.go new file mode 100644 index 00000000..5d621b0b --- /dev/null +++ b/util/dockerutil/features.go @@ -0,0 +1,5 @@ +package dockerutil + +type Feature string + +const OCIImporter Feature = "OCI importer"