From 4d8e45782b4749804c8d4cb5067a64dafccef15f Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Thu, 27 Jan 2022 19:30:06 +0100 Subject: [PATCH] builder: fallback to legacy Signed-off-by: CrazyMax --- cli/command/image/build.go | 4 +- cmd/docker/builder.go | 90 +++++++++++++++++++++----------------- docs/deprecated.md | 16 +++++++ e2e/image/build_test.go | 2 +- 4 files changed, 69 insertions(+), 43 deletions(-) diff --git a/cli/command/image/build.go b/cli/command/image/build.go index e5f77f60f4..4ff64ec9ca 100644 --- a/cli/command/image/build.go +++ b/cli/command/image/build.go @@ -184,8 +184,8 @@ func runBuild(dockerCli command.Cli, options buildOptions) error { remote string ) - if !options.quiet { - _, _ = fmt.Fprint(dockerCli.Err(), `WARNING: The legacy builder is in use and will build your image in an inefficient way. + if !options.quiet && dockerCli.ServerInfo().OSType != "windows" { + _, _ = fmt.Fprint(dockerCli.Err(), `DEPRECATED: The legacy builder is deprecated and will be removed in a future release. `) } diff --git a/cmd/docker/builder.go b/cmd/docker/builder.go index f9d6ed4479..c1e0e58e63 100644 --- a/cmd/docker/builder.go +++ b/cmd/docker/builder.go @@ -14,20 +14,19 @@ import ( const ( builderDefaultPlugin = "buildx" - builderDefaultInstallMsg = `To install buildx, see - https://docs.docker.com/go/buildx. You can also fallback to the - legacy builder by setting DOCKER_BUILDKIT=0` - - builderErrorMsg = "ERROR: Missing builder component %s." + builderDefaultInstallMsg = `To install buildx, see https://docs.docker.com/go/buildx/` + builderErrorMsg = `%s: Required builder component %s is missing or broken.` ) type builderError struct { + warn bool builder string err error } -func newBuilderError(builder string, err error) error { +func newBuilderError(warn bool, builder string, err error) error { return &builderError{ + warn: warn, builder: builder, err: err, } @@ -35,7 +34,11 @@ func newBuilderError(builder string, err error) error { func (e *builderError) Error() string { var errorMsg bytes.Buffer - errorMsg.WriteString(fmt.Sprintf(builderErrorMsg, e.builder)) + if e.warn { + errorMsg.WriteString(fmt.Sprintf(builderErrorMsg, "WARNING", e.builder)) + } else { + errorMsg.WriteString(fmt.Sprintf(builderErrorMsg, "ERROR", e.builder)) + } if e.builder == builderDefaultPlugin { errorMsg.WriteString(" ") errorMsg.WriteString(builderDefaultInstallMsg) @@ -50,17 +53,19 @@ func (e *builderError) Unwrap() error { return e.err } -func processBuilder(dockerCli command.Cli, cmd *cobra.Command, args, osArgs []string) ([]string, []string, error) { +func processBuilder(dockerCli command.Cli, cmd *cobra.Command, args, osargs []string) ([]string, []string, error) { // check DOCKER_BUILDKIT env var is present and // if not assume we want to use a builder + var enforcedBuilder bool if v, ok := os.LookupEnv("DOCKER_BUILDKIT"); ok { enabled, err := strconv.ParseBool(v) if err != nil { - return args, osArgs, errors.Wrap(err, "DOCKER_BUILDKIT environment variable expects boolean value") + return args, osargs, errors.Wrap(err, "DOCKER_BUILDKIT environment variable expects boolean value") } if !enabled { - return args, osArgs, nil + return args, osargs, nil } + enforcedBuilder = true } // if a builder alias is defined, use it instead @@ -76,38 +81,13 @@ func processBuilder(dockerCli command.Cli, cmd *cobra.Command, args, osArgs []st // wcow build command must use the legacy builder for buildx // if not opt-in through a builder alias if !isAlias && dockerCli.ServerInfo().OSType == "windows" { - return args, osArgs, nil - } - - // builder aliases - aliases := [][2][]string{ - { - {"builder"}, - {builderAlias}, - }, - { - {"build"}, - {builderAlias, "build"}, - }, - { - {"image", "build"}, - {builderAlias, "build"}, - }, + return args, osargs, nil } // are we using a cmd that should be forwarded to the builder? - var forwarded bool - for _, al := range aliases { - var didChange bool - args, didChange = command.StringSliceReplaceAt(args, al[0], al[1], 0) - if didChange { - forwarded = true - osArgs, _ = command.StringSliceReplaceAt(osArgs, al[0], al[1], -1) - break - } - } + fwargs, fwosargs, forwarded := forwardBuilder(builderAlias, args, osargs) if !forwarded { - return args, osArgs, nil + return args, osargs, nil } // check plugin is available if cmd forwarded @@ -116,8 +96,38 @@ func processBuilder(dockerCli command.Cli, cmd *cobra.Command, args, osArgs []st perr = plugin.Err } if perr != nil { - return args, osArgs, newBuilderError(builderAlias, perr) + // if builder enforced with DOCKER_BUILDKIT=1, cmd fails if plugin missing or broken + if enforcedBuilder { + return fwargs, fwosargs, newBuilderError(false, builderAlias, perr) + } + // otherwise, display warning and continue + _, _ = fmt.Fprintln(dockerCli.Err(), newBuilderError(true, builderAlias, perr).Error()) + return args, osargs, nil } - return args, osArgs, nil + return fwargs, fwosargs, nil +} + +func forwardBuilder(alias string, args, osargs []string) ([]string, []string, bool) { + aliases := [][2][]string{ + { + {"builder"}, + {alias}, + }, + { + {"build"}, + {alias, "build"}, + }, + { + {"image", "build"}, + {alias, "build"}, + }, + } + for _, al := range aliases { + if fwargs, changed := command.StringSliceReplaceAt(args, al[0], al[1], 0); changed { + fwosargs, _ := command.StringSliceReplaceAt(osargs, al[0], al[1], -1) + return fwargs, fwosargs, true + } + } + return args, osargs, false } diff --git a/docs/deprecated.md b/docs/deprecated.md index 53ee3cc04e..8594ba4276 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -50,6 +50,7 @@ The table below provides an overview of the current status of deprecated feature Status | Feature | Deprecated | Remove -----------|------------------------------------------------------------------------------------------------------------------------------------|------------|------------ +Deprecated | [Legacy builder fallback](#legacy-builder-fallback) | v21.xx | - Removed | [Support for encrypted TLS private keys](#support-for-encrypted-tls-private-keys) | v20.10 | v21.xx Deprecated | [Kubernetes stack and context support](#kubernetes-stack-and-context-support) | v20.10 | - Deprecated | [Pulling images from non-compliant image registries](#pulling-images-from-non-compliant-image-registries) | v20.10 | - @@ -99,6 +100,21 @@ Removed | [`--api-enable-cors` flag on `dockerd`](#--api-enable-cors-flag-on- Removed | [`--run` flag on `docker commit`](#--run-flag-on-docker-commit) | v0.10 | v1.13 Removed | [Three arguments form in `docker import`](#three-arguments-form-in-docker-import) | v0.6.7 | v1.12 +### Legacy builder fallback + +**Deprecated in Release: v21.xx** + +BuildKit implementation code and linked build flags have been removed in the CLI +and are now forwarded to [Buildx](https://docs.docker.com/buildx/working-with-buildx/) +builder component. + +If Buildx plugin is missing or broken, build command will fall back to the +legacy builder. This fallback mechanism will be removed in a future release and +user prompted to install the Buildx plugin. + +User can always fall back to the legacy builder with `DOCKER_BUILDKIT=0` but +`DOCKER_BUILDKIT=1` will always require Buildx. + ### Support for encrypted TLS private keys **Deprecated in Release: v20.10** diff --git a/e2e/image/build_test.go b/e2e/image/build_test.go index ce92c6a509..1d9eb64925 100644 --- a/e2e/image/build_test.go +++ b/e2e/image/build_test.go @@ -37,7 +37,7 @@ func TestBuildFromContextDirectoryWithTag(t *testing.T) { withWorkingDir(dir)) defer icmd.RunCommand("docker", "image", "rm", "myimage") - result.Assert(t, icmd.Expected{Err: "WARNING: The legacy builder is in use and will build your image in an inefficient way."}) + result.Assert(t, icmd.Expected{Err: "DEPRECATED: The legacy builder is deprecated and will be removed in a future release."}) output.Assert(t, result.Stdout(), map[int]func(string) error{ 0: output.Prefix("Sending build context to Docker daemon"), 1: output.Suffix("Step 1/4 : FROM registry:5000/alpine:3.6"),