Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: set default context builder if not specified #3676

Merged
merged 2 commits into from
Nov 9, 2022

Conversation

crazy-max
Copy link
Member

@crazy-max crazy-max commented Jun 15, 2022

- What I did

if build subcommand has changed to a builder alias (buildx),
user would expect docker build to always create a local docker
image (default context builder). this is for better backward
compatibility in case where a user could switch to a docker container
builder with docker buildx --use foo which does not --load by default.
also makes sure that an arbitrary builder name is not being set in the
command line or in the environment before setting the default context.

- How I did it

- How to verify it

Default builder:

$ docker buildx ls
NAME/NODE     DRIVER/ENDPOINT STATUS                 BUILDKIT PLATFORMS
default *     docker
  default     default         running                20.10.16 linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

$ docker image ls
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

$ docker build -t foo -<<EOF
FROM busybox
RUN echo "hello world"
EOF
#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 73B done
#1 DONE 0.1s
...
#7 exporting to image
#7 exporting layers 0.0s done
#7 writing image sha256:ee2ed9777638b584951486ec450f8959a8a69a59f9f1f55e0320a79d5cf4d462 done
#7 naming to docker.io/library/foo done
#7 DONE 0.1s

$ docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
foo          latest    ee2ed9777638   5 seconds ago   1.24MB

Create and use docker-container builder:

$ docker buildx create --name foo --use --bootstrap

$ docker buildx ls
NAME/NODE     DRIVER/ENDPOINT             STATUS                 BUILDKIT PLATFORMS
foo *         docker-container
  foo0        unix:///var/run/docker.sock running                v0.10.3  linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
default       docker
  default     default                     running                20.10.16 linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

$ docker image ls
REPOSITORY      TAG               IMAGE ID       CREATED       SIZE
moby/buildkit   buildx-stable-1   a2c9241854f2   5 weeks ago   142MB

# specify container builder
$ docker build --builder foo -t foo -<<EOF
FROM busybox
RUN echo "hello world"
EOF
WARNING: No output specified with docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load
...
#6 [2/2] RUN echo "hello world"
#6 0.106 hello world
#6 DONE 0.1s

# image not loaded as expected
$ docker image ls
REPOSITORY      TAG               IMAGE ID       CREATED       SIZE
moby/buildkit   buildx-stable-1   a2c9241854f2   5 weeks ago   142MB

# now building without specifying a builder should build from default builder and load the image
$ docker build -t foo -<<EOF
FROM busybox
RUN echo "hello world"
EOF

$ docker image ls
REPOSITORY      TAG               IMAGE ID       CREATED         SIZE
foo             latest            ee2ed9777638   5 minutes ago   1.24MB
moby/buildkit   buildx-stable-1   a2c9241854f2   5 weeks ago     142MB

- Description for the changelog

build: set default context builder if not specified

cc @tonistiigi @jedevc

- A picture of a cute animal (not mandatory but encouraged)

Signed-off-by: CrazyMax crazy-max@users.noreply.github.com

@codecov-commenter
Copy link

codecov-commenter commented Jun 15, 2022

Codecov Report

Merging #3676 (b9a1276) into master (3dfef76) will increase coverage by 0.03%.
The diff coverage is 60.97%.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3676      +/-   ##
==========================================
+ Coverage   58.81%   58.84%   +0.03%     
==========================================
  Files         286      286              
  Lines       24640    24664      +24     
==========================================
+ Hits        14491    14514      +23     
- Misses       9265     9266       +1     
  Partials      884      884              

@jedevc
Copy link
Contributor

jedevc commented Jun 15, 2022

I'm not sure, does this work across multiple contexts? e.g. on dd4l, the desktop-linux docker driver is used, while the default docker driver is in a different context.

So always forcing to the default builder might not be the right call here, since the context we're in might not always have one of that name? I'm not super familiar with using multiple contexts, so I'm not 100% sure.

@crazy-max
Copy link
Member Author

Good point, we might trigger this error if using default. Will switch to use the default context.

@crazy-max crazy-max changed the title build: set default builder name if not specified build: set default context builder if not specified Jun 15, 2022
@sudo-bmitch
Copy link
Contributor

So this means docker buildx use now only applies to docker buildx commands, and not docker build? Seems reasonable.

The other option I was thinking of involved changing the default flags when running docker build for a docker-container driver to mirror the backwards compatible defaults. Effectively requiring docker build --load=false if you didn't want the compatible behavior.

Once this and --link are fixed, I'll be happy to give them a test.

@crazy-max
Copy link
Member Author

So this means docker buildx use now only applies to docker buildx commands, and not docker build? Seems reasonable.

Yes that's it

The other option I was thinking of involved changing the default flags when running docker build for a docker-container driver to mirror the backwards compatible defaults.

This can be tricky as user might want to push its image which would not work as multi-exporters are not currently supported with BuildKit: moby/buildkit#1555

@jedevc
Copy link
Contributor

jedevc commented Jun 16, 2022

Will switch to use the default context.

Seems like the right behavior now! 🎉

@thaJeztah
Copy link
Member

Hmmm.. bit on the fence; so IIRC, the intent was to make docker build a full alias for docker buildx build, and provide all the enhancements that buildx added. From that perspective, I'd expect that if a custom builder was set to be the active builder, docker build to also use that builder.

However, if a container-builder is the active builder, and no useful output was given (neither --push, --load or --output), then the result is definitely confusing.

Wondering if we can do something with that information (no output given), and use --load as a default if none was set? 🤔

@crazy-max
Copy link
Member Author

As discussed on Slack, I think it still makes sense to use the default context for docker build to keep the same experience as 20.10.

However, if a container-builder is the active builder, and no useful output was given (neither --push, --load or --output), then the result is definitely confusing.

Don't think this is an issue as users can still use buildx build to rely on their current builder as they use to currently.

Wondering if we can do something with that information (no output given), and use --load as a default if none was set? 🤔

--load is dockerd specific and adding specific flags might not be ideal/future proof with buildx I think. Also loading for every build might not be expected if someone doesn't want to output anything like if you have a stage that just run tests for your project or linting, vendor validation, etc...

Let me know if you have the same or other concerns and how we can improve that.

@sudo-bmitch
Copy link
Contributor

However, if a container-builder is the active builder, and no useful output was given (neither --push, --load or --output), then the result is definitely confusing.

My bigger concern is when running something like a Makefile from a cloned git repo, the docker build inside that Makefile should work on all the machines where it's run, without customizing the flags for each environment.

@thaJeztah
Copy link
Member

--load is dockerd specific and adding specific flags might not be ideal/future proof with buildx I think. Also loading for every build might not be expected if someone doesn't want to output anything like if you have a stage that just run tests for your project or linting, vendor validation, etc...

This still feels as a very specific use-case, and it's odd that this was chosen to be the default, and not an opt-in (more below).

to keep the same experience as 20.10.

So, it depends how you ran it in 20.10. If I didn't opt-in to use buildx (and thus not into the advanced features), then the default builder would be used;

With the built-in BuildKit client (on 20.10);

DOCKER_BUILDKIT=1 docker build -t foo -<<'EOF'
FROM busybox
RUN echo hello
EOF
[+] Building 4.7s (6/6) FINISHED
 => [internal] load build definition from Dockerfile                                                                                                                                                   0.3s
 => => transferring dockerfile: 70B                                                                                                                                                                    0.1s
 => [internal] load .dockerignore                                                                                                                                                                      0.2s
 => => transferring context: 2B                                                                                                                                                                        0.0s
 => [internal] load metadata for docker.io/library/busybox:latest                                                                                                                                      0.0s
 => CACHED [1/2] FROM docker.io/library/busybox                                                                                                                                                        0.0s
 => [2/2] RUN echo hello                                                                                                                                                                               3.9s
 => exporting to image                                                                                                                                                                                 0.3s
 => => exporting layers                                                                                                                                                                                0.2s
 => => writing image sha256:66ed75cd29b095e1bdcee7720f7960cdcdedae33f6b322c3d2e57e3f24e17ee2                                                                                                           0.0s
 => => naming to docker.io/library/foo

However, if I opted-in to using buildx (docker buildx install) to get the advanced features, and if I switched the current builder to a container buidler, then a warning is printed (generated in buildx;

docker buildx install
docker build -t foo -<<'EOF'
FROM busybox
RUN echo hello
EOF
[+] Building 6.2s (5/5) FINISHED
 => [internal] load build definition from Dockerfile                                                                                                                                                   0.8s
 => => transferring dockerfile: 65B                                                                                                                                                                    0.1s
 => [internal] load .dockerignore                                                                                                                                                                      0.6s
 => => transferring context: 2B                                                                                                                                                                        0.1s
 => [internal] load metadata for docker.io/library/busybox:latest                                                                                                                                      3.7s
 => [1/2] FROM docker.io/library/busybox@sha256:3614ca5eacf0a3a1bcc361c939202a974b4902b9334ff36eb29ffe9011aaad83                                                                                       0.9s
 => => resolve docker.io/library/busybox@sha256:3614ca5eacf0a3a1bcc361c939202a974b4902b9334ff36eb29ffe9011aaad83                                                                                       0.0s
 => => sha256:19d511225f94f9b5cbf3836eb02b5273c01b95da50735742560e3e45b8c8bfcc 773.26kB / 773.26kB                                                                                                     0.4s
 => => extracting sha256:19d511225f94f9b5cbf3836eb02b5273c01b95da50735742560e3e45b8c8bfcc                                                                                                              0.3s
 => [2/2] RUN echo hello                                                                                                                                                                               0.4s
WARNING: No output specified for docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load

Overall, I prefer the latter over the earlier one (I even would've preferred it to be an error at the start - when dealing with ambiguous situations, it's better to produce an error to prevent people from using it, than not; an error can later turned into a feature, a "non-error" will result in a backward-incompatible change).

  • The above would only occur if; the current builder was changed to not be the default; this is not something that happens automatically, so this would've been caused by a user action
  • IMO, there can be only one "current" builder; if I use docker builder use <X> / docker buildx use <X>, I'd expect that builder to be used always (unless I override with --builder)
  • The docker build command has always been to build an image, with the expectation to have that image appear in docker image ls (docker build --help shows "Build an image from a Dockerfile")
  • BuildKit / buildx added additional features to docker build (--output, --push), which were opt-in
  • However, when a container-builder (or other driver) is used, that's not the case (output is now "optional") <-- this is the situation described here
  • AFAIK, the intent is still for docker build to be the canonical subcommand to perform a build
  • And (with buildx being the default client for build), for docker build to become more powerful with new features added that were not available in the old, built-in, BuildKit client.

Some options;

  1. Produce a WARNING (no output specified) - I think that's the current situation? (Ideally, we'd print that warning at the start of the build as well, so that the user is notified early)
  2. When invoking a build through docker build, produce an error but continue to allow it when invoked explicitly through docker buildx build. This would allow the user to explicitly opt-on to this advanced feature by invoking the build through docker buildx build
  3. When invoking a build through docker build, automatically set --load

Of the above;

  • both 2. and 3. would be a (breaking) change in behavior
  • 2. would have the advantage that it allows for this feature to be enabled in future (as described earlier).
  • 3. is the most "convenient" one, but effectively prevents us from ever allowing "no output as default".
  • Question is; do we want this as a default (depending on the driver) - even when invoked through docker buildx build? It feels inconsistent for the result of docker build to differ depending on what build happened to be used; if we prefer "explicit" over "implicit", I'd rather have an error (no output specified), an require an explicit --output=none (e.g.).

@tonistiigi
Copy link
Member

@thaJeztah If you insist, we could keep the old behavior of buildx install. When user types that, then they say that they want docker build and docker buildx build to always be identical. This way we have covered all the possible backward compatibility angles.

After buildx is default I think most of the appeal of buildx install is going away anyway and we can start to gradually sunset that command.

@thaJeztah
Copy link
Member

Ah, sorry, I meant to reply; I wasn't 100% sure what the proposal was 😅 ☺️

On 22.06 (buildx as default), I would consider that the equivalent as docker buildx install on older versions; buildx build is set up to replace build (with all the advantages/features that brings), which would mean;

docker builder create --use --name foo --driver=docker-container
echo "FROM alpine" | docker build -

...
WARNING: No output specified for docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load

If the proposal is to make that the behaviour, that sounds good to me (making it a hard error if no explicit output is set would still be my preference, but I realise that requires more changes).

Can we print the warning (both?) at the start (and at the end)?

@crazy-max
Copy link
Member Author

crazy-max commented Oct 25, 2022

As discussed, do not enforce the default context if a builder alias is set ("buildx install") so user keeps the same build experience.

cmd/docker/docker.go Outdated Show resolved Hide resolved
@crazy-max crazy-max force-pushed the build-default-builder branch 3 times, most recently from 7d44338 to b9a1276 Compare November 4, 2022 07:18
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants