How to Improve Docker Image Size With Layers?



In this article, we will discuss various approaches and techniques for improving Docker image size with layers, including multi-stage builds, using minimal base images, and using base images with pre-installed packages or pre-built binaries. By following these best practices, we can create smaller and more efficient Docker images that are optimized for performance and scalability.

The size of Docker images with layers can be improved using a variety of methods as given below.

Methods

  • Using minimal base images

  • Using base images with pre-built binaries

  • Using multi-stage builds

  • Using base images with pre-installed packages

Let us discuss these methods with examples.

Using minimal base images

The overall size of the image can be decreased by selecting a base image that contains only the necessary libraries and dependencies. For instance, utilizing the alpine picture as the base image instead of a fully featured base image like Ubuntu can reduce the size of the final image.

Below is a step-by-step example of how to implement this −

Example

Step 1 − Create a new directory for your project and navigate to it −

$ mkdir directoryname 
$ cd directoryname

Step 2 − Create a file called ‘Dockerfile’ with the below content in this new directory −

FROM alpine:latest
RUN apk add --no-cache curl
CMD ["curl", "-s", "http://example.com"]

Step 3 − Build the image by running the following command in the terminal −

$ docker build -t alpine-curl

Step 4 − To view the final image size, run the following command in your terminal −

$ docker images

The final image size will be significantly smaller when using a minimal base image like alpine, as it contains only the necessary libraries and dependencies.

Output

REPOSITORY  TAG      IMAGE ID      CREATED         SIZE 
alpine-curl latest   eecb6a9f6ab7  3 minutes ago   5.56MB

In this example, the final image size is 5.56MB, which is much smaller compared to using a fully-featured base image like Ubuntu.

Using base images with pre-built binaries

Pre-built binary executables are included with some base images, which might be helpful for executing applications without having to construct them from scratch. To launch Node.js apps without having to create them from source code, for instance, the ‘node’ image provides pre-built versions of the ‘node’ and ‘npm’ executables.

Below is a step-by-step example of how to implement this −

Example

Step 1 − Create a new directory for your project and navigate to it −

$ mkdir directoryname 
$ cd directoryname

Step 2 − Create a file called ‘Dockerfile’ with the below content in this new directory −

FROM node:latest 
WORKDIR /app 
COPY . . 
RUN npm install 
CMD ["node", "index.js"]

Step 3 − Build the image by running the following command in the terminal −

$ docker build -t node-app .

Step 4 − To view the final image size, run the following command in your terminal −

$ docker images

Using base images with pre-built binaries can reduce the number of layers and the overall size of the image, as you don't have to build the executables from the source.

Output

REPOSITORY  TAG      IMAGE ID       CREATED        SIZE 
node-app    latest   c9f6a1be6ee1   3 minutes ago  961MB

In this example, the final image size is 961MB, which includes the pre-built versions of the node and npm executables.

Using multi-stage builds

With multi-stage builds, you can produce numerous intermediate images with various sets of layers by using various FROM commands in your Dockerfile. Only the layers required for the final application can then be used to build the final image, resulting in a decreased overall image size.

Below is a step-by-step example of how to implement this −

Example

Step 1 − Create a new directory for your project and navigate to it.

Step 2 − Create a file called ‘Dockerfile’ with the below content in this new directory −

FROM golang:latest as builder 
WORKDIR /app 
COPY . . 
RUN go build -o main . 
FROM alpine:latest 
RUN apk add --no-cache ca-certificates 
COPY --from=builder /app/main /app/main
CMD ["/app/main"]

Step 3 − Build the image by running the following command in the terminal −

$ docker build -t multi-stage-build .

Step 4 − To view the final image size, run the following command in your terminal −

$ docker images

Multi-stage builds allow you to create multiple intermediate images with different sets of layers and then only use the necessary layers to build the final image, resulting in a smaller overall image size.

Output

REPOSITORY           TAG      IMAGE ID       CREATED        SIZE 
multi-stage-build    latest   0d3b3c0e928f   4 minutes ago  5.57MB

In this example, the final image size is 5.57MB, which is significantly smaller compared to using a single-stage build with a fully-featured base image like golang.

Using base images with pre-installed packages

A set of pre-installed packages may be included with some base images, which can help minimize the number of layers and total size of the image. To create Go applications without having to manually install these packages, for instance, the golang image contains a variety of Go packages and libraries.

Below is a step-by-step example of how to implement this −

Example

Step 1 − Create a new directory for your project and navigate to it.

Step 2 − Create a file called ‘Dockerfile’ with the below content in this new directory −

FROM golang:latest 
WORKDIR /app 
COPY . . 
RUN go build -o main . 
CMD ["/app/main"]

Step 3 − Build the image by running the following command in the terminal −

$ docker build -t golang-app .

Step 4 − To view the final image size, run the following command in your terminal −

$ docker images

Using base images with pre-installed packages can reduce the number of layers and the overall size of the image, as you don't have to install the packages manually.

Output

REPOSITORY TAG     IMAGE ID      CREATED        SIZE 
golang-app latest  c45a0c0aec2c  4 minutes ago  824MB

In this example, the final image size is 824MB, which includes the pre-installed Go packages and libraries from the golang image.

Conclusion

In this article, we explored a number of methods for reducing the size of a Docker image using layers. We can produce smaller Docker images that are optimized for performance and efficiency by using multi-stage builds, picking a minimum base image, using a base image with pre-installed packages, and using a base image with pre-built binaries.


Advertisements