Build Docker images with BuildKit
Let’s say it very clearly: If you are not using BuildKit to build your Docker images you are wasting your time!!!.
With BuildKit, the building process for Docker images can be reduced by ten times in some cases, because it turns that process out in something really incremental.
The release 18.09 of Docker [1] introduced a much-needed overhaul of the build architecture by integrating BuildKit [2], so if you are in a previous Docker release, I encourage you to upgrade as soon as possible, since the build process on those versions was a pain in the neck. No matter how many posts you read and followed to speed up the building process by caching Maven artifacts (in case of Java) or by splitting up your Dockerfile in thin tiers, those recipes just didn’t work, because Docker itself didn’t honor the caching of those tiers as they stated in its documentation; but that suddenly changed in Docker 18.09.
Apart from speeding the build process, BuildKit has a lot of additional features and it can be used as a standalone tool without Docker. The following are some of those features [2]:
- Automatic garbage collection
- Extendable frontend formats
- Concurrent dependency resolution
- Efficient instruction caching
- Build cache import/export
- Nested build job invocations
- Distributable workers
- Multiple output formats
- Pluggable architecture
- Execution without root privileges
It is worth mentioning that BuiltKit is only supported to build Linux containers [3].
Enable it for Docker
Let’s go to the point. How to activate it if you already have installed a Docker version higher than 18.09. The easiest way is setting the following environment variable:
$ DOCKER_BUILDKIT=1
But to enable a permanent solution, you should set the Docker daemon configuration
in /etc/docker/daemon.json
as follows:
{ "features": { "buildkit": true } }
After activating BuildKit you should notice a change in the output format (more colorful), but the most important aspect is speed, since caching is working once and for all:
$ docker build .
[+] Building 70.9s (34/59)
=> [runc 1/4] COPY hack/dockerfile/install/install.sh ./install.sh 14.0s
=> [frozen-images 3/4] RUN /download-frozen-image-v2.sh /build buildpa 24.9s
=> [containerd 4/5] RUN PREFIX=/build/ ./install.sh containerd 37.1s
=> [tini 2/5] COPY hack/dockerfile/install/install.sh ./install.sh 4.9s
=> [vndr 2/4] COPY hack/dockerfile/install/vndr.installer ./ 1.6s
=> [dockercli 2/4] COPY hack/dockerfile/install/dockercli.installer ./ 5.9s
=> [proxy 2/4] COPY hack/dockerfile/install/proxy.installer ./ 15.7s
=> [tomlv 2/4] COPY hack/dockerfile/install/tomlv.installer ./ 12.4s
=> [gometalinter 2/4] COPY hack/dockerfile/install/gometalinter.install 25.5s
=> [vndr 3/4] RUN PREFIX=/build/ ./install.sh vndr 33.2s
=> [tini 3/5] COPY hack/dockerfile/install/tini.installer ./ 6.1s
=> [dockercli 3/4] RUN PREFIX=/build/ ./install.sh dockercli 18.0s
=> [runc 2/4] COPY hack/dockerfile/install/runc.installer ./ 2.4s
=> [tini 4/5] RUN PREFIX=/build/ ./install.sh tini 11.6s
=> [runc 3/4] RUN PREFIX=/build/ ./install.sh runc 23.4s
=> [tomlv 3/4] RUN PREFIX=/build/ ./install.sh tomlv 9.7s
=> [proxy 3/4] RUN PREFIX=/build/ ./install.sh proxy 14.6s
=> [dev 2/23] RUN useradd --create-home --gid docker unprivilegeduser 5.1s
=> [gometalinter 3/4] RUN PREFIX=/build/ ./install.sh gometalinter 9.4s
=> [dev 3/23] RUN ln -sfv /go/src/github.com/docker/docker/.bashrc ~/.ba 4.3s
=> [dev 4/23] RUN echo source /usr/share/bash-completion/bash_completion 2.5s
=> [dev 5/23] RUN ln -s /usr/local/completion/bash/docker /etc/bash_comp 2.1s
Enable it for Docker Compose
To use BuildKit with Docker Compose [4] you need to install version 1.25.1 [5] or later.
To enable BuildKit just set the following environment variable:
$ COMPOSE_DOCKER_CLI_BUILD=1
Next steps
In this post we have seen how to activate BuildKit in your local environment, in a coming post I will write on how to take advantage of BuildKit in your CI pipelines, since it can be trickier when you do not have the rights to change the building environment.