diff --git a/build/build.go b/build/build.go index f94bc9b6..a1449953 100644 --- a/build/build.go +++ b/build/build.go @@ -546,7 +546,7 @@ func toSolveOpt(ctx context.Context, d driver.Driver, multiDriver bool, opt Opti so.FrontendAttrs["force-network-mode"] = opt.NetworkMode case "", "default": default: - return nil, nil, errors.Errorf("network mode %q not supported by buildkit", opt.NetworkMode) + return nil, nil, errors.Errorf("network mode %q not supported by buildkit. You can define a custom network for your builder using the network driver-opt in buildx create.", opt.NetworkMode) } // setup extrahosts diff --git a/commands/bake.go b/commands/bake.go index 844dd476..2ec451b2 100644 --- a/commands/bake.go +++ b/commands/bake.go @@ -20,8 +20,8 @@ import ( type bakeOptions struct { files []string - printOnly bool overrides []string + printOnly bool commonOptions } @@ -200,10 +200,10 @@ func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command { flags := cmd.Flags() flags.StringArrayVarP(&options.files, "file", "f", []string{}, "Build definition file") + flags.BoolVar(&options.exportLoad, "load", false, "Shorthand for `--set=*.output=type=docker`") flags.BoolVar(&options.printOnly, "print", false, "Print the options without building") - flags.StringArrayVar(&options.overrides, "set", nil, "Override target value (e.g., `targetpattern.key=value`)") flags.BoolVar(&options.exportPush, "push", false, "Shorthand for `--set=*.output=type=registry`") - flags.BoolVar(&options.exportLoad, "load", false, "Shorthand for `--set=*.output=type=docker`") + flags.StringArrayVar(&options.overrides, "set", nil, "Override target value (e.g., `targetpattern.key=value`)") commonBuildFlags(&options.commonOptions, flags) diff --git a/commands/build.go b/commands/build.go index e224404d..041ab643 100644 --- a/commands/build.go +++ b/commands/build.go @@ -15,13 +15,14 @@ import ( "github.com/docker/buildx/util/tracing" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" - "github.com/docker/cli/opts" + dockeropts "github.com/docker/cli/opts" "github.com/docker/docker/pkg/ioutils" "github.com/docker/go-units" "github.com/moby/buildkit/client" "github.com/moby/buildkit/session/auth/authprovider" "github.com/moby/buildkit/util/appcontext" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/pflag" ) @@ -29,54 +30,36 @@ import ( const defaultTargetName = "default" type buildOptions struct { - commonOptions contextPath string dockerfileName string - tags []string - labels []string - buildArgs []string + allow []string + buildArgs []string cacheFrom []string cacheTo []string - target string - platforms []string - secrets []string - ssh []string - outputs []string - imageIDFile string extraHosts []string + imageIDFile string + labels []string networkMode string + outputs []string + platforms []string quiet bool - shmSize opts.MemBytes - ulimits *opts.UlimitOpt - - // unimplemented - squash bool - - allow []string - - // hidden - // untrusted bool - // memory opts.MemBytes - // memorySwap opts.MemSwapBytes - // shmSize opts.MemBytes - // cpuShares int64 - // cpuPeriod int64 - // cpuQuota int64 - // cpuSetCpus string - // cpuSetMems string - // cgroupParent string - // isolation string - // compress bool - // securityOpt []string + secrets []string + shmSize dockeropts.MemBytes + ssh []string + tags []string + target string + ulimits *dockeropts.UlimitOpt + commonOptions } type commonOptions struct { builder string + metadataFile string noCache *bool progress string pull *bool - metadataFile string + // golangci-lint#826 // nolint:structcheck exportPush bool @@ -85,9 +68,6 @@ type commonOptions struct { } func runBuild(dockerCli command.Cli, in buildOptions) (err error) { - if in.squash { - return errors.Errorf("squash currently not implemented") - } ctx := appcontext.Context() ctx, end, err := tracing.TraceCurrentCommand(ctx, "build") @@ -119,16 +99,16 @@ func runBuild(dockerCli command.Cli, in buildOptions) (err error) { DockerfilePath: in.dockerfileName, InStream: os.Stdin, }, - Tags: in.tags, - Labels: listToMap(in.labels, false), BuildArgs: listToMap(in.buildArgs, true), - Pull: pull, - NoCache: noCache, - Target: in.target, - ImageIDFile: in.imageIDFile, ExtraHosts: in.extraHosts, + ImageIDFile: in.imageIDFile, + Labels: listToMap(in.labels, false), NetworkMode: in.networkMode, + NoCache: noCache, + Pull: pull, ShmSize: in.shmSize, + Tags: in.tags, + Target: in.target, Ulimits: in.ulimits, } @@ -268,7 +248,7 @@ func buildTargets(ctx context.Context, dockerCli command.Cli, opts map[string]bu func newBuildOptions() buildOptions { ulimits := make(map[string]*units.Ulimit) return buildOptions{ - ulimits: opts.NewUlimitOpt(&ulimits), + ulimits: dockeropts.NewUlimitOpt(&ulimits), } } @@ -283,91 +263,116 @@ func buildCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { options.contextPath = args[0] options.builder = rootOpts.builder + cmd.Flags().VisitAll(checkWarnedFlags) return runBuild(dockerCli, options) }, } + var platformsDefault []string + if v := os.Getenv("DOCKER_DEFAULT_PLATFORM"); v != "" { + platformsDefault = []string{v} + } + flags := cmd.Flags() - flags.BoolVar(&options.exportPush, "push", false, "Shorthand for `--output=type=registry`") - flags.BoolVar(&options.exportLoad, "load", false, "Shorthand for `--output=type=docker`") + flags.StringSliceVar(&options.extraHosts, "add-host", []string{}, "Add a custom host-to-IP mapping (format: `host:ip`)") + flags.SetAnnotation("add-host", "docs.external.url", []string{"https://docs.docker.com/engine/reference/commandline/build/#add-entries-to-container-hosts-file---add-host"}) + + flags.StringSliceVar(&options.allow, "allow", []string{}, "Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`)") - flags.StringArrayVarP(&options.tags, "tag", "t", []string{}, "Name and optionally a tag (format: `name:tag`)") - flags.SetAnnotation("tag", "docs.external.url", []string{"https://docs.docker.com/engine/reference/commandline/build/#tag-an-image--t"}) flags.StringArrayVar(&options.buildArgs, "build-arg", []string{}, "Set build-time variables") flags.SetAnnotation("build-arg", "docs.external.url", []string{"https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables---build-arg"}) + flags.StringArrayVar(&options.cacheFrom, "cache-from", []string{}, "External cache sources (e.g., `user/app:cache`, `type=local,src=path/to/dir`)") + + flags.StringArrayVar(&options.cacheTo, "cache-to", []string{}, "Cache export destinations (e.g., `user/app:cache`, `type=local,dest=path/to/dir`)") + flags.StringVarP(&options.dockerfileName, "file", "f", "", "Name of the Dockerfile (default: `PATH/Dockerfile`)") flags.SetAnnotation("file", "docs.external.url", []string{"https://docs.docker.com/engine/reference/commandline/build/#specify-a-dockerfile--f"}) + flags.StringVar(&options.imageIDFile, "iidfile", "", "Write the image ID to the file") + flags.StringArrayVar(&options.labels, "label", []string{}, "Set metadata for an image") - flags.StringArrayVar(&options.cacheFrom, "cache-from", []string{}, "External cache sources (e.g., `user/app:cache`, `type=local,src=path/to/dir`)") - flags.StringArrayVar(&options.cacheTo, "cache-to", []string{}, "Cache export destinations (e.g., `user/app:cache`, `type=local,dest=path/to/dir`)") + flags.BoolVar(&options.exportLoad, "load", false, "Shorthand for `--output=type=docker`") - flags.StringVar(&options.target, "target", "", "Set the target build stage to build.") - flags.SetAnnotation("target", "docs.external.url", []string{"https://docs.docker.com/engine/reference/commandline/build/#specifying-target-build-stage---target"}) + flags.StringVar(&options.networkMode, "network", "default", "Set the networking mode for the RUN instructions during build") - flags.StringSliceVar(&options.allow, "allow", []string{}, "Allow extra privileged entitlement (e.g., `network.host`, `security.insecure`)") + flags.StringArrayVarP(&options.outputs, "output", "o", []string{}, "Output destination (format: `type=local,dest=path`)") + + flags.StringArrayVar(&options.platforms, "platform", platformsDefault, "Set target platform for build") + + flags.BoolVar(&options.exportPush, "push", false, "Shorthand for `--output=type=registry`") flags.BoolVarP(&options.quiet, "quiet", "q", false, "Suppress the build output and print image ID on success") - flags.StringVar(&options.networkMode, "network", "default", "Set the networking mode for the RUN instructions during build") - flags.StringSliceVar(&options.extraHosts, "add-host", []string{}, "Add a custom host-to-IP mapping (format: `host:ip`)") - flags.SetAnnotation("add-host", "docs.external.url", []string{"https://docs.docker.com/engine/reference/commandline/build/#add-entries-to-container-hosts-file---add-host"}) - flags.StringVar(&options.imageIDFile, "iidfile", "", "Write the image ID to the file") + + flags.StringArrayVar(&options.secrets, "secret", []string{}, "Secret file to expose to the build (format: `id=mysecret,src=/local/secret`)") + flags.Var(&options.shmSize, "shm-size", "Size of `/dev/shm`") - flags.Var(options.ulimits, "ulimit", "Ulimit options") - // not implemented - flags.BoolVar(&options.squash, "squash", false, "Squash newly built layers into a single new layer") - flags.MarkHidden("squash") + flags.StringArrayVar(&options.ssh, "ssh", []string{}, "SSH agent socket or keys to expose to the build (format: `default|[=|[,]]`)") + + flags.StringArrayVarP(&options.tags, "tag", "t", []string{}, "Name and optionally a tag (format: `name:tag`)") + flags.SetAnnotation("tag", "docs.external.url", []string{"https://docs.docker.com/engine/reference/commandline/build/#tag-an-image--t"}) + + flags.StringVar(&options.target, "target", "", "Set the target build stage to build.") + flags.SetAnnotation("target", "docs.external.url", []string{"https://docs.docker.com/engine/reference/commandline/build/#specifying-target-build-stage---target"}) + + flags.Var(options.ulimits, "ulimit", "Ulimit options") // hidden flags var ignore string var ignoreSlice []string var ignoreBool bool var ignoreInt int64 - flags.StringSliceVar(&ignoreSlice, "security-opt", []string{}, "Security options") - flags.MarkHidden("security-opt") + + flags.StringVar(&ignore, "cgroup-parent", "", "Optional parent cgroup for the container") + flags.MarkHidden("cgroup-parent") + //flags.SetAnnotation("cgroup-parent", "flag-warn", []string{"cgroup-parent is not implemented."}) + flags.BoolVar(&ignoreBool, "compress", false, "Compress the build context using gzip") flags.MarkHidden("compress") + + flags.StringVar(&ignore, "isolation", "", "Container isolation technology") + flags.MarkHidden("isolation") + flags.SetAnnotation("isolation", "flag-warn", []string{"isolation flag is deprecated with BuildKit."}) + + flags.StringSliceVar(&ignoreSlice, "security-opt", []string{}, "Security options") + flags.MarkHidden("security-opt") + flags.SetAnnotation("security-opt", "flag-warn", []string{`security-opt flag is deprecated. "RUN --security=insecure" should be used with BuildKit.`}) + + flags.BoolVar(&ignoreBool, "squash", false, "Squash newly built layers into a single new layer") + flags.MarkHidden("squash") + flags.SetAnnotation("squash", "flag-warn", []string{"experimental flag squash is removed with BuildKit. You should squash inside build using a multi-stage Dockerfile for efficiency."}) + flags.StringVarP(&ignore, "memory", "m", "", "Memory limit") flags.MarkHidden("memory") + flags.StringVar(&ignore, "memory-swap", "", "Swap limit equal to memory plus swap: `-1` to enable unlimited swap") flags.MarkHidden("memory-swap") + flags.Int64VarP(&ignoreInt, "cpu-shares", "c", 0, "CPU shares (relative weight)") flags.MarkHidden("cpu-shares") + flags.Int64Var(&ignoreInt, "cpu-period", 0, "Limit the CPU CFS (Completely Fair Scheduler) period") flags.MarkHidden("cpu-period") + flags.Int64Var(&ignoreInt, "cpu-quota", 0, "Limit the CPU CFS (Completely Fair Scheduler) quota") flags.MarkHidden("cpu-quota") + flags.StringVar(&ignore, "cpuset-cpus", "", "CPUs in which to allow execution (`0-3`, `0,1`)") flags.MarkHidden("cpuset-cpus") + flags.StringVar(&ignore, "cpuset-mems", "", "MEMs in which to allow execution (`0-3`, `0,1`)") flags.MarkHidden("cpuset-mems") - flags.StringVar(&ignore, "cgroup-parent", "", "Optional parent cgroup for the container") - flags.MarkHidden("cgroup-parent") - flags.StringVar(&ignore, "isolation", "", "Container isolation technology") - flags.MarkHidden("isolation") + flags.BoolVar(&ignoreBool, "rm", true, "Remove intermediate containers after a successful build") flags.MarkHidden("rm") + flags.BoolVar(&ignoreBool, "force-rm", false, "Always remove intermediate containers") flags.MarkHidden("force-rm") - platformsDefault := []string{} - if v := os.Getenv("DOCKER_DEFAULT_PLATFORM"); v != "" { - platformsDefault = []string{v} - } - flags.StringArrayVar(&options.platforms, "platform", platformsDefault, "Set target platform for build") - - flags.StringArrayVar(&options.secrets, "secret", []string{}, "Secret file to expose to the build (format: `id=mysecret,src=/local/secret`)") - - flags.StringArrayVar(&options.ssh, "ssh", []string{}, "SSH agent socket or keys to expose to the build (format: `default|[=|[,]]`)") - - flags.StringArrayVarP(&options.outputs, "output", "o", []string{}, "Output destination (format: `type=local,dest=path`)") - commonBuildFlags(&options.commonOptions, flags) - return cmd } @@ -378,6 +383,19 @@ func commonBuildFlags(options *commonOptions, flags *pflag.FlagSet) { flags.StringVar(&options.metadataFile, "metadata-file", "", "Write build result metadata to the file") } +func checkWarnedFlags(f *pflag.Flag) { + if !f.Changed { + return + } + for t, m := range f.Annotations { + switch t { + case "flag-warn": + logrus.Warn(m[0]) + break + } + } +} + func listToMap(values []string, defaultEnv bool) map[string]string { result := make(map[string]string, len(values)) for _, value := range values { diff --git a/commands/root.go b/commands/root.go index 761d4b7b..7191722d 100644 --- a/commands/root.go +++ b/commands/root.go @@ -12,7 +12,8 @@ import ( func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Command { cmd := &cobra.Command{ - Short: "Build with BuildKit", + Short: "Docker Buildx", + Long: `Extended build capabilities with BuildKit`, Use: name, } if isPlugin { diff --git a/docs/reference/buildx.md b/docs/reference/buildx.md index 7d006db0..e797d9e2 100644 --- a/docs/reference/buildx.md +++ b/docs/reference/buildx.md @@ -5,7 +5,7 @@ docker buildx [OPTIONS] COMMAND ``` -Build with BuildKit +Extended build capabilities with BuildKit ### Subcommands diff --git a/docs/reference/buildx_create.md b/docs/reference/buildx_create.md index 4b5abb54..7bb94eaf 100644 --- a/docs/reference/buildx_create.md +++ b/docs/reference/buildx_create.md @@ -131,11 +131,6 @@ Passes additional driver-specific options. Details for each driver: - `image=IMAGE` - Sets the container image to be used for running buildkit. - `network=NETMODE` - Sets the network mode for running the buildkit container. - `cgroup-parent=CGROUP` - Sets the cgroup parent of the buildkit container if docker is using the "cgroupfs" driver. Defaults to `/docker/buildx`. - - Example: - - ```console - --driver docker-container --driver-opt image=moby/buildkit:master,network=host - ``` - `kubernetes` - `image=IMAGE` - Sets the container image to be used for running buildkit. - `namespace=NS` - Sets the Kubernetes namespace. Defaults to the current namespace. @@ -150,6 +145,30 @@ Passes additional driver-specific options. Details for each driver: - `qemu.install=(true|false)` - Install QEMU emulation for multi platforms support. - `qemu.image=IMAGE` - Sets the QEMU emulation image. Defaults to `tonistiigi/binfmt:latest` +**Examples** + +#### Use a custom network + +```console +$ docker network create foonet +$ docker buildx create --name builder --driver docker-container --driver-opt network=foonet --use +$ docker buildx inspect --bootstrap +$ docker inspect buildx_buildkit_builder0 --format={{.NetworkSettings.Networks}} +map[foonet:0xc00018c0c0] +``` + +#### OpenTelemetry support + +To capture the trace to [Jaeger](https://github.com/jaegertracing/jaeger), set +`JAEGER_TRACE` environment variable to the collection address using the `driver-opt`: + +```console +$ docker run -d --name jaeger -p 6831:6831/udp -p 16686:16686 jaegertracing/all-in-one +$ docker buildx create --name builder --driver docker-container --driver-opt network=host --driver-opt env.JAEGER_TRACE=localhost:6831 --use +$ docker buildx inspect --bootstrap +# buildx command should be traced at http://127.0.0.1:16686/ +``` + ### Remove a node from a builder (--leave) The `--leave` flag changes the action of the command to remove a node from a