Reading Time: 4 minutes

5 tips to reduce Docker image size

Docker images can quickly weight 1 or more GB.  Although the gigabyte price is decreasing, keeping your Docker images light will bring some benefits. This post will give you 5 tips to help reduce your Docker images size and why focusing on it is important.

Update: Docker 1.13 introduced a new –squash option to squash the image layers (experimental): https://docs.docker.com/engine/reference/commandline/build/#/squash-an-images-layers—squash-experimental-only (thanks @SISheogorath).

Why is the image size so important?

Reducing Docker final image size will eventually lead to:
  • Reduced build time
  • Reduced disk usage
  • Reduced download time
  • Better security due to smaller footprint
  • Faster deployments

 

What is a layer?

To reduce an image size, it’s important to understand what a layer is.
Every Docker image is composed of multiple intermediate images (layers) which form the final image. This layers stack allows Docker to reuse images when a similar instruction is found.

Each Dockerfile instruction creates a layer at build time:

 

Docker layers - 5 tips to reduce Docker image size

Overview of image layers

Let’s build this image:

To see the intermediate layers of an image, type the following command:

You can see below that each layer have a size and a command associated to create it. The final image built from this Dockerfile contains 3 layers plus all Ubuntu image layers.

 

Although this can be somehow difficult to understand, this structure is very important as it allows Docker to cache layers to make the builds much faster. When building an image, the Docker daemon will check if the intermediate image (layer created by the instruction) already exists in its cache to reuse it. If the intermediate layer is not found or has changed, the Docker daemon will pull or rebuild it.

How to reduce image size

As we just saw, the layers play an important role in the final image size. To reduce the final size, we have to focus on the intermediate layers.
Although some of them cannot be reduced (especially the one you start from), we can use a few tips to help reduce the final image size.

Group commands in ONE instruction when possible (do not perform multiple installs in multiple RUN instructions)

Installing packages

Separate instructions

To illustrate this statement, let’s build an image with two separate RUN instructions which install curl and mysql-client packages:


Single instruction
Now, let’s gather the two instructions in only one:

Let’s build our image again:

Although the size difference is not so significant, you can expect better results when installing multiple packages.

Removing packages

Separate instructions

Let’s see another interesting example in which we remove a temporary package in a separate instruction:

You can see here that the curl package is immediately removed after being installed, in a separate instruction. Let’s see the final image size:
Single instruction
This time, let’s combine these instructions into one line:

You can see that the size of the image has slighltly reduced. Again, the difference is not very significant here because we only remove one package.

Why is there a difference?

As we saw earlier, the Docker daemon creates an image for each instruction to execute the associated command. In the separates instructions example, the superposition of all these images creates the final one. Because of this strategy, the mysql-client package is still part of the final image (in the third layer actually) although being removed further.

Docker layers - removing packages in separate instructions

Removing packages in separate instructions

Docker layers - removing packages in a single instruction

Removing packages in a single instruction

Do not install packages recommendations (-–no-install-recommends) when installing packages

Remove  no longer needed packages or files, in the SAME instruction if possible

Packages example:

In this example, the package curl is only needed to retrieve an install file. Since it is not needed anymore, it can be removed (in the SAME instruction).

Files example:

Start with a smaller base image

Do you need every Ubuntu (or other base images) packages? If not, you should consider starting with a smaller base image like Alpine () which will likely become the base image for all official Docker images (Jenkins, Maven). This base image weights around 5MB whereas Ubuntu one is about 188MB. You can see a great comparison of Docker base images here: https://www.brianchristner.io/docker-image-base-os-size-comparison/.

Inspecting images from DockerHub

To easily inspect a DockerHub image, you can use the MicroBadger service:https://microbadger.com/

MicroBadger - Ubuntu layers - 5 tips to reduce Docker image size

MicroBadger – Ubuntu layers

TL;DR

  1. Group commands in ONE instruction when possible
  2. Do not install packages recommendations (–no-install-recommends)
  3. Remove  no longer needed packages or files, in the SAME instruction
  4. Clean apt-cache after packages installs
  5. Start with a smaller base image: Alpine

 

If you are too busy (or lazy) to focus on reducing your image size, here is a tool you could consider: https://github.com/jwilder/docker-squash.