Improve docker build speed

Nowadays we have powerfull machines which can compile large and heavy files in record time. However is not always the case when we have resources enough and we need to dedicate just a few for compiling our Docker images. That’s why in this post we are gonna cover a few topics to improve docker build speed, and make it faster.

Taking into consideration that every Docker image is based into layers which can be cache’d for later re-use them and decrease the build time, we need to remember that if we modify a layer in our Dockerfile, the consequent layers will need to be rebuilt again, increasing the time. That’s why we can have two approaches.

Writing the more dynamic layers at the end

To improve docker build speed, we need to make sure we can reuse the maximum number of layers cache’d, so the rebuild time will be the minimul. For example, if we need to install some dependencies or updates some packeges, the latest we do it, the better. Look at the following example:

FROM python:3.11

RUN pip install gunicorn
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
ENV PORT 8080

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app

In that case, we are installing a dependency, doing some steps, installing the requirements and then setting up an environment variable. Some of those layers will be rebuild without a real need to do so, like for example, the ENV PORT 8080 that’s a layer that will be rebuild. In this concrete case is only one and very light, but in bigger Dockerfiles it could mean much more.

A way to force more layers to be reused, could be moving the installation to the very end, right before executing CMD. In that way, we are making sure we are re-using most of the layers from time to time and saving time.

FROM python:3.11

COPY . /app
WORKDIR /app

RUN pip install gunicorn
RUN pip install -r requirements.txt
ENV PORT 8080

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app

Now we would be saving some compiling time.

Directory Caching

By doing directory caching, Docker is able to “remember” where something is located and use it in case it exists to build faster the image. It can bind a special layer in build time with your requirements and unmount it before the snapshot is made. This is often used to handle directories where tools like Linux software installers (apt, apk, dnf, etc) and language dependency managers (npm, bundler, pip, etc) are.

To use this feature, we need to make sure that we have buildkit enabled by running export DOCKER_BUILDKIT=1

Following the previous Dockerfile, if we add a new dependency to the requirements.txt file, it will need to download again all the dependecies, but why if we already have done that in a previous build? This inefficiency results from the builder seeing that we have made a change that impacts this layer and therefore completely re-creates the layer, so we lose that cache, even though we had it stored in the image layer.

In order to improve this situation and save time during compilation, we can mount the directory where pip typically saves the dependencies and mount it as a cache layer to make Docker look at that directory before downloading anything and only download the new dependencies. To do that we must add a little modification to the pip install line. But also we need to add a new line at the top of the file.

#syntax=docker/dockerfile:1

FROM python:3.11

COPY . /app
WORKDIR /app

RUN pip install gunicorn

RUN --mount=type=cache,target=/root/.cache pip install -r requirements.txt

ENV PORT 8080

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app

The first header line we added is needed to tell Docker we are going to use a newer version of the Dockerfile frontent, which provides us with access to BuildKit’s new features. However the second line is actually mounting a caching layer into the container at /root/.cache for the duration of this step to build. It will remove the content of the directory from the resulting image.

In this way, it will check in consecutive builds which dependencies are already installed to save us some time to download again the same.


Did you like what you read? Don’t forget to read more articles about Docker in our blog.

1 thought on “Improve docker build speed”

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top