From 49059b9dcb05779c3fd956592954d2a7feb7b3aa Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 24 Aug 2022 20:03:45 +0300 Subject: [PATCH 1/2] Document Moby vs BuildKit differences --- build/building/multi-stage.md | 80 +++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/build/building/multi-stage.md b/build/building/multi-stage.md index d4fd77bb0a8a..d11bb3732a51 100644 --- a/build/building/multi-stage.md +++ b/build/building/multi-stage.md @@ -205,3 +205,83 @@ RUN g++ -o /binary source.cpp ## Version compatibility Multi-stage build syntax was introduced in Docker Engine 17.05. + +## Moby vs BuildKit engine differences + +- With Moby engine, all stages from the beginning of the Dockerfile up to the specified stage are executed, even if +some stages are not dependencies of the target stage. +- With BuildKit, only the transitive dependencies of the target stage are executed. + +For example, check the following Dockerfile: + +```dockerfile +# syntax=docker/dockerfile:1 +FROM ubuntu AS base +RUN echo "base" + +FROM base AS stage1 +RUN echo "stage1" + +FROM base AS stage2 +RUN echo "stage2" +``` + +- Output for BuildKit enabled: + +```console +$ DOCKER_BUILDKIT=1 docker build --no-cache -f Dockerfile --target stage2 . +``` +```console +[+] Building 0.4s (7/7) FINISHED + => [internal] load build definition from Dockerfile 0.0s + => => transferring dockerfile: 36B 0.0s + => [internal] load .dockerignore 0.0s + => => transferring context: 2B 0.0s + => [internal] load metadata for docker.io/library/ubuntu:latest 0.0s + => CACHED [base 1/2] FROM docker.io/library/ubuntu 0.0s + => [base 2/2] RUN echo "base" 0.1s + => [stage2 1/1] RUN echo "stage2" 0.2s + => exporting to image 0.0s + => => exporting layers 0.0s + => => writing image sha256:f55003b607cef37614f607f0728e6fd4d113a4bf7ef12210da338c716f2cfd15 0.0s +``` + +- Output for BuildKit disabled: + +```console +$ DOCKER_BUILDKIT=0 docker build --no-cache -f Dockerfile --target stage2 . +``` +```console +Sending build context to Docker daemon 219.1kB +Step 1/6 : FROM ubuntu AS base + ---> a7870fd478f4 +Step 2/6 : RUN echo "base" + ---> Running in e850d0e42eca +base +Removing intermediate container e850d0e42eca + ---> d9f69f23cac8 +Step 3/6 : FROM base AS stage1 + ---> d9f69f23cac8 +Step 4/6 : RUN echo "stage1" + ---> Running in 758ba6c1a9a3 +stage1 +Removing intermediate container 758ba6c1a9a3 + ---> 396baa55b8c3 +Step 5/6 : FROM base AS stage2 + ---> d9f69f23cac8 +Step 6/6 : RUN echo "stage2" + ---> Running in bbc025b93175 +stage2 +Removing intermediate container bbc025b93175 + ---> 09fc3770a9c4 +Successfully built 09fc3770a9c4 +``` + +`stage1` gets executed when BuildKit is disabled, even if `stage2` does not depend on it. + +BuildKit is not enabled by default on all platforms. For example, while it is enabled on macOS, it is +NOT on Linux. + +Docker multi-stage builds should always be run with +[BuildKit enabled](/develop/develop-images/build_enhancements/) +to avoid the problem described above. From 017cc3389f7ba4ad8b557d39084cbabeb55b4595 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Sat, 22 Oct 2022 15:46:54 +0300 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: David Karlsson <35727626+dvdksn@users.noreply.github.com> --- build/building/multi-stage.md | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/build/building/multi-stage.md b/build/building/multi-stage.md index d11bb3732a51..577113b6f2cd 100644 --- a/build/building/multi-stage.md +++ b/build/building/multi-stage.md @@ -206,13 +206,13 @@ RUN g++ -o /binary source.cpp Multi-stage build syntax was introduced in Docker Engine 17.05. -## Moby vs BuildKit engine differences +## Differences between legacy build and BuildKit -- With Moby engine, all stages from the beginning of the Dockerfile up to the specified stage are executed, even if -some stages are not dependencies of the target stage. -- With BuildKit, only the transitive dependencies of the target stage are executed. +The legacy Docker Engine builder processes all stages of a Dockerfile leading up to the selected `--target`. It will build a stage even if the selected target doesn't depend on that stage. -For example, check the following Dockerfile: +BuildKit only builds the stages that the target stage depends on. + +For example, given the following Dockerfile: ```dockerfile # syntax=docker/dockerfile:1 @@ -226,12 +226,10 @@ FROM base AS stage2 RUN echo "stage2" ``` -- Output for BuildKit enabled: +With BuildKit enabled, building the `stage2` target in this Dockerfile means only `base` and `stage2` are processed. There is no dependency on `stage1`, so it's skipped. ```console $ DOCKER_BUILDKIT=1 docker build --no-cache -f Dockerfile --target stage2 . -``` -```console [+] Building 0.4s (7/7) FINISHED => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 36B 0.0s @@ -246,12 +244,10 @@ $ DOCKER_BUILDKIT=1 docker build --no-cache -f Dockerfile --target stage2 . => => writing image sha256:f55003b607cef37614f607f0728e6fd4d113a4bf7ef12210da338c716f2cfd15 0.0s ``` -- Output for BuildKit disabled: +On the other hand, building the same target without BuildKit results in all stages being processed: ```console $ DOCKER_BUILDKIT=0 docker build --no-cache -f Dockerfile --target stage2 . -``` -```console Sending build context to Docker daemon 219.1kB Step 1/6 : FROM ubuntu AS base ---> a7870fd478f4 @@ -279,9 +275,8 @@ Successfully built 09fc3770a9c4 `stage1` gets executed when BuildKit is disabled, even if `stage2` does not depend on it. -BuildKit is not enabled by default on all platforms. For example, while it is enabled on macOS, it is -NOT on Linux. +BuildKit is enabled by default if you use Docker Desktop. -Docker multi-stage builds should always be run with +Always run multi-stage builds with [BuildKit enabled](/develop/develop-images/build_enhancements/) -to avoid the problem described above. +for better performance.