Common ways to optimize Docker image size

Common ways to optimize Docker image size

The Docker images we usually build are usually large and take up a lot of disk space. With the large-scale deployment of containers, it will also waste precious bandwidth resources. This article will introduce several common methods to optimize the size of Docker images. Here we use the Redis image on the official Docker Hub for illustration.

Manual management

The method we can think of directly is to directly modify the official Redis image Dockerfile file, manually delete the components that are not needed after the container runs, and then rebuild a new image. This method is feasible in theory, but it is prone to errors and the effect is not particularly obvious. The main problem is that it cannot be synchronized with the official mirror in real time.

Multi-stage builds

Docker provides a multi-stage build feature since version 17.05 to solve this problem. This approach is achieved by discarding the intermediate layer and using the intermediate layer to provide information about how to create the final image and its contents. Only the components required for the containerized application need to be retained. The implementation at a higher level is as follows:

  • Using some images as a basis for building
  • Run the command as usual to build your application
  • Copy the required artifacts to a separate image

Distroless

After relying heavily on containerization technology, especially Docker, Google has long been aware of the drawbacks of using bloated images. So they provided their own solution to this problem, namely distroless images. Unlike typical Linux base images (which bundle a lot of software), when you dockerize your application on distroless, the final image only contains the application and its runtime dependencies. Standard software included in most Linux distributions, such as package managers and even shells, will be excluded. Similarly, to use Google's distroless image, you need to use the multi-stage build we mentioned above, as follows:

FROM redis:latest AS build 
ARG TIME_ZONE 
RUN mkdir -p /opt/etc && \ 
 cp -a --parents /lib/x86_64-linux-gnu/libm.so.* /opt && \ 
 cp -a --parents /lib/x86_64-linux-gnu/libdl.so.* /opt && \ 
 cp -a --parents /lib/x86_64-linux-gnu/libpthread.so.* /opt && \ 
 cp -a --parents /lib/x86_64-linux-gnu/libc.so.* /opt && \ 
 cp -a --parents /usr/local/bin/redis-server /opt && \ 
 cp -a --parents /usr/local/bin/redis-sentinel /opt && \ 
 cp /usr/share/zoneinfo/${TIME_ZONE:-UTC} /opt/etc/localtime 
 
FROM gcr.io/distroless/base 
COPY --from=build /opt / 
VOLUME /data 
WORKDIR /data 
ENTRYPOINT ["redis-server"]

Use redis:latest as the base image, keep some required binaries (redis-server binary and all related dependencies), and then use the distroless image as the basis for the final image to be built. Copy the contents of the opt directory to the image directory.

Then we just need to rebuild the image:

$ docker build -t redis:distroless .$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEredis distroless 7d50bd873bea 15 seconds ago 28.2MBredis latest 1319b1eaa0b7 3 days ago 104MB

We can see that the image size has been reduced from 104MB to 28.2MB, which greatly reduces the image size.

Note: Under Linux we can use the ldd tool to find the dependencies required by a specified binary file, such as $ ldd $(which redis-server) .

Using distroless images to reduce the size of Docker images is a very effective method, but this also has an obvious disadvantage: there is no shell program in the final image, which makes debugging Docker containers very difficult. Of course, this also reduces the risk of application attacks and makes it more secure. If we deploy the application to a Kubernetes cluster, we can use tools such as kubectl-debug to assist in debugging the application.

Alpine Linux

Another common way is to choose to build an application image based on Alpine Linux, which is a distribution that is particularly suitable for creating minimal Docker images. Apline Linux uses the smaller musl C library instead of glibc and links it statically, which means that programs compiled for musl will become relocatable binaries, eliminating the need to include shared objects, which can significantly reduce the size of the image.

The redis:alpine image is about 30MB. The disadvantage is that musl usually does not perform as well as glibc. Of course, there is another advantage. Compared with the above distroless, Alpine is a mature Linux distribution that provides basic shell access, making it easier to debug Docker container applications. You can also find Alpine versions of almost all popular software on Docker Hub, such as Redis, Nginx, MySQL, etc.

GNU Guix

Finally, we can use GNU Guix, a versatile package management tool that has a function for creating Docker images. Guix distinguishes between a package's runtime dependencies and its build dependencies, so a Docker image built with Guix will only contain explicitly specified programs, plus their runtime dependencies, just like the distroless approach. But unlike distroless, which requires you to check the runtime dependencies of the program yourself (and of course write a Dockerfile), Guix only requires you to run one command: $ guix pack -f docker redis .

The Redis image created by the command above is about 70MB in size, which is a significant reduction compared to the original image. Although it is slightly larger than the images created by the distroless and Alpine methods, using Guinx does provide some other advantages. For example, if you want your final image to include a shell for debugging like Alpine, you only need to specify it when packaging Guxi: $ guix pack -f docker redis bash . If you want to include other software, you can continue to add it later.

Guix's features mean that package builds are 100% reusable, so we can add Guix support to our CI/CD pipeline and make the build process very smooth.

Some people may think that Guix sounds cool, but they don’t want to download and install another tool just to build a smaller Docker image. Moreover, Guix only works under Linux. Many developers are still MacOS users, so it is troublesome to configure Guix. In fact, you don’t have to worry about this. Guix itself also has a Docker image on the Docker Hub, so it is not too complicated to use. You only need to use the simple $ docker run guix command.

In addition to Guix, it's worth mentioning that there's a package management tool called Nix, and everything mentioned about Guix is ​​equally valid and applicable to Nix.

The above are the details of the common ways to optimize the size of Docker images. For more information on optimizing the size of Docker images, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • How to reduce image size using Docker multi-stage build
  • Six ways to reduce the size of Docker images

<<:  Three ways to prevent MySQL from inserting duplicate data

>>:  Implement group by based on MySQL to get the latest data of each group

Recommend

Details of 7 kinds of component communication in Vue3

Table of contents 1. Vue3 component communication...

Mobile terminal adaptation makes px automatically converted to rem

Install postcss-pxtorem first: npm install postcs...

Detailed explanation of the difference between tags and elements in HTML

I believe that many friends who are new to web pag...

How to use Volume to transfer files between host and Docker container

I have previously written an article about file t...

Vue easily realizes watermark effect

Preface: Use watermark effect in vue project, you...

Mybatis mysql delete in operation can only delete the first data method

Bugs As shown in the figure, I started to copy th...

How to use Vue3 to achieve a magnifying glass effect example

Table of contents Preface 1. The significance of ...

Example of setting up a whitelist in Nginx using the geo module

Original configuration: http { ...... limit_conn_...

vue-admin-template dynamic routing implementation example

Provide login and obtain user information data in...

Native JS music player

This article example shares the specific code of ...

Detailed explanation of mysql backup and recovery

Preface: The previous articles introduced the usa...

React gets input value and submits 2 methods examples

Method 1: Use the target event attribute of the E...

A simple way to achieve scrolling effect with HTML tag marquee (must read)

The automatic scrolling effect of the page can be...

Linux 6 steps to change the default remote port number of ssh

The default ssh remote port in Linux is 22. Somet...