From 82bb527d5b71ddde81057e2e1a9d4f7e37069001 Mon Sep 17 00:00:00 2001 From: Eric Stroczynski Date: Wed, 6 Oct 2021 15:21:23 -0700 Subject: [PATCH] feat(publish): optionally use 'docker buildx build' for multi-arch Signed-off-by: Eric Stroczynski --- README.md | 10 +++- pkg/bundle/publish/catalog_images.go | 60 ++++++++++++++++++----- pkg/bundle/publish/catalog_images_test.go | 4 -- pkg/bundle/publish/options.go | 16 +++--- 4 files changed, 65 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 8d17ef6f7..46701e3c4 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,14 @@ Bundle management is a two part process: 1. Bundle Creation (Internet Connected) 1. Bundle Publishing (Disconnected) -## Requirements +## Required dependencies -- [`docker buildx`][docker-buildx] (called by `publish`) +- [`podman`][podman] (only required if not building multi-arch images, see below) + +## Multi-arch catalog images + +[`docker buildx`][docker-buildx] is required to build multi-arch catalog images; +`docker buildx build` is invoked by `publish` when `--buildx-platforms` is set. ## Usage @@ -73,3 +78,4 @@ TODO: link to the following once a release is cut. [config-spec]:pkg/config/v1alpha1/config_types.go [go]:https://golang.org/dl/ [docker-buildx]:https://docs.docker.com/buildx/working-with-buildx/ +[podman]:https://podman.io/getting-started/ diff --git a/pkg/bundle/publish/catalog_images.go b/pkg/bundle/publish/catalog_images.go index 9f48f2c05..3220241ea 100644 --- a/pkg/bundle/publish/catalog_images.go +++ b/pkg/bundle/publish/catalog_images.go @@ -9,7 +9,6 @@ import ( "os/exec" "path" "path/filepath" - "strconv" "strings" "github.com/RedHatGov/bundle/pkg/operator" @@ -164,32 +163,69 @@ func (o *Options) buildCatalogImage(ctx context.Context, ref reference.DockerIma logrus.Infof("Building rendered catalog image: %s", ref.Exact()) + if len(o.BuildxPlatforms) == 0 { + err = o.buildPodman(ctx, ref, dir, dockerfile) + } else { + err = o.buildDockerBuildx(ctx, ref, dir, dockerfile) + } + return err +} + +func (o *Options) buildDockerBuildx(ctx context.Context, ref reference.DockerImageReference, dir, dockerfile string) error { + exactRef := ref.Exact() + + args := []string{ + "build", "buildx", + "-t", exactRef, + "-f", dockerfile, + "--platform", strings.Join(o.BuildxPlatforms, ","), + "--push", + dir, + } + cmd := exec.CommandContext(ctx, "docker", args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := runDebug(cmd); err != nil { + return err + } + + return nil +} + +func (o *Options) buildPodman(ctx context.Context, ref reference.DockerImageReference, dir, dockerfile string) error { + exactRef := ref.Exact() + bargs := []string{ "build", - "-t", ref.Exact(), + "-t", exactRef, "-f", dockerfile, - // TODO: NO MULTIARCH SUPPORT... YET. - //"--platform", strings.Join(o.CatalogPlatforms, ","), dir, } bcmd := exec.CommandContext(ctx, "podman", bargs...) bcmd.Stdout = os.Stdout bcmd.Stderr = os.Stderr - err = bcmd.Run() - if err != nil { - logrus.Error(bcmd.Stderr) + if err := runDebug(bcmd); err != nil { return err } - logrus.Debugf("command: %s", strings.Join(bcmd.Args, " ")) pargs := []string{ "push", - ref.Exact(), - fmt.Sprintf("--tls-verify=%s", strconv.FormatBool(!o.SkipTLS)), + exactRef, + } + if o.SkipTLS { + pargs = append(pargs, "--tls-verify=false") } pcmd := exec.CommandContext(ctx, "podman", pargs...) - logrus.Info(pcmd) pcmd.Stdout = os.Stdout pcmd.Stderr = os.Stderr - return pcmd.Run() + if err := runDebug(pcmd); err != nil { + return err + } + + return nil +} + +func runDebug(cmd *exec.Cmd) error { + logrus.Debugf("command: %s", strings.Join(cmd.Args, " ")) + return cmd.Run() } diff --git a/pkg/bundle/publish/catalog_images_test.go b/pkg/bundle/publish/catalog_images_test.go index ddae06de4..b8c5db463 100644 --- a/pkg/bundle/publish/catalog_images_test.go +++ b/pkg/bundle/publish/catalog_images_test.go @@ -65,10 +65,6 @@ func Test_buildCatalogImage(t *testing.T) { SkipTLS: true, }, ArchivePath: tt.fields.archivePath, - CatalogPlatforms: []string{ - "linux/amd64", - "linux/arm64", - }, } ref := reference.DockerImageReference{ diff --git a/pkg/bundle/publish/options.go b/pkg/bundle/publish/options.go index 626e0cca8..9a23ab58b 100644 --- a/pkg/bundle/publish/options.go +++ b/pkg/bundle/publish/options.go @@ -11,18 +11,20 @@ import ( type Options struct { *cli.RootOptions - ArchivePath string - ToMirror string - CatalogPlatforms []string -} + ArchivePath string + ToMirror string -var defaultPlatforms = []string{"linux/amd64"} + BuildxPlatforms []string +} func (o *Options) BindFlags(fs *pflag.FlagSet) { fs.StringVar(&o.ArchivePath, "archive", "", "The archive file path.") fs.StringVar(&o.ToMirror, "to-mirror", "", "The URL to the destination mirror registry") - fs.StringSliceVar(&o.CatalogPlatforms, "catalog-platforms", defaultPlatforms, "Platforms to build a catalog manifest list for. "+ - "This list does NOT filter operator bundle manifest list platforms within the catalog") + fs.StringSliceVar(&o.BuildxPlatforms, "buildx-platforms", nil, + "If set, the command will invoke 'docker buildx build' to build a catalog manifest list "+ + "for the specified platforms, ex. linux/amd64, instead of 'podman build' for the host platform. "+ + "The 'buildx' plugin and accompanying configuration MUST be installed on the build host. "+ + "This list does NOT filter operator bundle manifest list platforms within the catalog") } // ValidatePaths validate the existence of paths from user flags