24 November 2020
How to speed up your Docker image build?
Docker became one of the core technologies the software development industry is using. At The Software House, both development and deployment are based on Docker. Let’s be honest – we cannot imagine working without it anymore. However, Docker can also become a problem, especially when your image build time reaches some serious values. Let’s see how you can speed up your Docker image build in a few simple steps.
Build time matters
Let’s start with a simple introduction for those who are not using Docker yet. In order to be able to either develop or run a dockerized app, we need to build an image first. The more dependencies our app has (things required for it to work), the longer it takes. For development, we usually need to build that image once and then update it with every bigger change (for example, when we need to install something on an image operating system level or when we update the version of a base image – let’s say a Node.js image). Well, it might sound like not a big deal. But it actually is…
Imagine that we have a CI/CD setup. Every pull request needs to build a current version of an image (based on pull request code) to run tests on it. What’s more, we also need to have a current production-ready image build for deployment.
So in fact, by reducing build time, we’re speeding up the whole process – faster CI, faster deployments.
A simple change we missed out on…
This is our express boilerplate development Dockerfile.
Its default build time is pretty good:
docker build --no-cache -f ./docker/dev/Dockerfile . 0.17s user 0.15s system 0% cpu 1:12.05 total
But we have been missing one thing. We’re using the old Docker builder. 🙂
With Docker 18.09 ,a new builder was released. It’s called Buildkit. It is not used by default, so most of us are still using the old one. The thing is, Buildkit is much faster, even for such simple images!
DOCKER_BUILDKIT=1 docker build --no-cache -f ./docker/dev/Dockerfile . 0.24s user 0.16s system 0% cpu 54.268 total
The difference is about 18 seconds on an image that builds in the 70s. That’s a lot, almost 33%!
💡 Hungry for more hacks?
How to use Buildkit?
As I mentioned, Buildkit is not enabled by default. If we want to use it for a single build, then we need to add the DOCKER_BUILDKIT environment variable and set it to 1 before running the Docker command.
DOCKER_BUILDKIT=1 Docker build
Of course, there is an option to activate it as a default builder. In order to do that, we need to change our Docker engine configuration. Usually, it is in /etc/docker/daemon.json. Just open it with an editor of your choice and add:
{ "features": { "buildkit": true } }
It also works with docker-compose. However, for that, we need to set one more variable – COMPOSE_DOCKER_CLI_BUILD to 1.
COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose build --no-cache
So where’s the catch?
There is one thing you need to be aware of when using Buildkit. Some CI systems integrated with Docker might not work properly with it because it is using some experimental features underneath.
A good example is Bitbucket Pipelines (our default choice in terms of CI). So in order to run Buildkit there, we need to use our own custom docker-in-docker image to have access to new features.
But I’m sure this is just a matter of time before Atlassian updates its own tool, so we just need to wait for that a bit!
If you'd like to know how Docker and other tools can streamline your DevOps
👋 Be sure to say hi to us – one of the biggest DevOps teams in Poland.
We’d gladly review your case for free to see if we can assist your project. 98% of CTOs recommend out professionals.