Docker tips & tricks: How to optimize the size of a Docker Image?

Tram Ho

When it comes to building Docker containers, we should always try to be able to create images of smaller sizes. Reducing your image size will help improve the security, efficiency, and maintainability of your containers.

In this article, I will share some methods that can help optimize our image size.

1. Choose the correct base image.

Choosing the right base image is the first and crucial step in building your docker image. Choosing the base image depends on a variety of conditions such as what type of application you want to run on the container? or the tools you need in the container to run your application, … There are two

  • Select the base image as close to your application needs as possible. For example when you need an environment to run the laravel app with composer. Instead of choosing the base image ubuntu then you should install laravel yourself, you should choose the base image as Docker available composer. This helps us to optimize build time. In addition, these base images have often been built by Docker as the most optimized base images. It’s hard for you to do better.
  • Unless your app asks your app to disallow it or an image isn’t available, always use an image built on top of alpine . Alpine Linux is a linux distro based on musl and BusyBox, developed with emphasis on simplicity, security and resource efficiency . In short, this is a lighter and more secure linux distro.The only downside of alpine is that it is very small, so you have to manually install the tools or libraries you need to use for your application, and sometimes it is quite a hassle.For example, instead of using FROM node:12 , try switching to using FROM node:12-alpine , you will see the size of the image decrease a lot. Images built on alpine are very lightweight, with nodejs being reduced from 900MB by default to only 70MB for alpine.

2. Optimize Layers.

The Docker image is built from a series of layers. Each statement in Dockerfile creates a read-only layer wrapped in the image generated by the above statement and continues to create a new image. The final image is a large onion with many layers. Even the container is actually a writable layer wrapped on top of the image.

The layers are not free . They take up space, and as the layers overlap more and more, your final image size increases. The reason is that the system will keep all changes between different Dockerfile directives. Therefore. Reducing the number of layers is the first thing to think about when you want to reduce the image size.

Each step in Dockerfile creates layers, however, steps with Dockerfile directives make changes to the current layer, creating new layers> 0 bytes. As of Docker 1.10, the COPY , ADD and RUN directives in Dockerfile will add a new layer to your image as they will change the file system. Directives like WORDIR , CMD or EXPOSE , … will create empty layers with size = 0 bytes.

For example, we have the following simple Dockerfile:

Then, we perform a build image from Dpckerfile treen: docker build -t layer:example .

After the image has been created, you can see all the layers created with the docker history <image> command

Next, instead of using the three RUN directives above, we can rewrite the above Dockerfile to:

Then, we perform a build image from Dpckerfile treen: docker build -t layer:example.01 . and see the layers created:

3. Use multi-stage builds.

Multi-stage build is a new feature introduced in Docker v17.05. Multi-stage build is useful when you want to optimize your Dockerfile while keeping it both readable and mantain easy.

When the program is built by you and that program only needs to run one or more executable files, configuration. The files in that program require the installation of environments, packages, and modules very difficult and complex. It also takes a pretty high amount of space, which may make your Images heavier. However, with multi-stage build you can perform those installations in stages with full environment, and then copy the required files to a stage based on lighter, but sufficient images to execute / run your application. friend.

For example, to build Dockerfile for a simple Laravel application, we would do the following:

  • Step 1: Composer
    • Use a composer base image
    • Copy the files needed for “composer install”
    • Run “composer install”
    • Copy remaining files
    • Run “composer dump-autoload”

  • Step 2: NPM
    • Use the base image using NodeJs
    • Cop files are required for “npm install”.
    • Run “npm install”.
    • Copy files needed for the frontend build.
    • Build

  • Step 3: Application
    • Use the base image of php-fpm
    • Copy files that were built from previous steps
    • Deploy your application

4. Remove or not use unnecessary packages or files.

” When building containers to run in production, any unused packages, or packages included for debugging purposes, need to be removed. ”

Here are a few tips to help you do that:

Don’t install debug tools like vim / curl / …

One common case is that developers install tools like vim and curl in their Dockerfile so they can more easily debug their apps. However, unless your application depends on them, don’t install those dependencies. Doing so is against the purpose of using a compact base image.

But if not installed, how can I debug?

The answer is that you always have Dockerfile with all the tools you need in staging environment. Then, when you bring them to production on a production environment, remove all those tools =)))

Use .dockerignore files

The directory on the host that contains Dockerfile is called build context. When building all the files / folders in the build context are sent to the docker server. If the build context has a file that weighs several G that is not used in the image, it is also sent to the server and this not only increases the size of the image, but also wastes time building the image significantly. Therefore, when you want to remove one or several files / folders, you need to create a file called .dockerignore , its role is like .gitignore , and the syntax is similar.

For example :

Use --no-install-recommends in apt-get install

Use -- no-install-recommends on your apt-get install -y . This can help you significantly reduce the size by avoiding the installation of packages that your application doesn’t need at all, but is encouraged to install them with packages.

Alternatively, use the --no-cache on the apk add to allow no local index storage, helping to reduce the size of your image.

Add rm -rf /var/lib/apt/lists/* to the same layer as apt-get installs

Add rm -rf /var/lib/apt/lists/* at the end after installing with apt-get -y install for cleanup. Similar to yum install , add yum clean all .

Also, for example if you install wget or curl to download some packages, remember to combine them all in one RUN directive. Then at the end of the RUN directive layer, use apt-get remove curl or wget when you no longer need them. This works for any package that you just need temporarily.

Conclusion

Through some of the methods I just shared above, I hope you can build the docker image with the most optimal size and bring many benefits in the process of using your image.

Thank you for watching my post!

Share the news now

Source : Viblo