Overview



When building Docker images, it's common for the size to unintentionally increase. Most of the time, this is due to unnecessarily created layers. This article shares my optimization experience of how to check the 'genealogy' of an image using the docker history command and thus lighten the actual image.

By using this command, you can accurately identify what is making your image heavy and create more efficient images.


docker history: Checking the Genealogy of an Image

The docker history command shows how a specific image was built and its composition history. You can see which layers the commands in the Dockerfile created, as well as the time and size of each layer.

The basic usage is very simple.

docker history [options] <image_name:tag>

For example, the command to check the history of the local my-app:latest image is as follows.

docker history my-app:latest

The output will show the layers of the image in order from the most recent (top layer) to the base (oldest) image.

IMAGE          CREATED         CREATED BY                                      SIZE
a6215f271958   5 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>      7 weeks ago     /bin/sh -c #(nop) ADD file:f28242cf608f6...   7.81MB
  • CREATED BY: The Dockerfile command that created this layer

  • SIZE: The size occupied by that layer

Useful Tip: View Entire Command with --no-trunc

The default output of docker history truncates the command in the CREATED BY column if it is too long. When you use the --no-trunc option, you can view the entire command without truncation, which is essential for accurate analysis.

docker history --no-trunc my-app:latest

Why Layer Analysis is Important: Real Optimization Experience



The fundamental principle is that Docker images create one layer for each command in the Dockerfile. Each layer is a 'change' built upon the previous layer.

The problem arises when layers are unnecessarily divided, causing a significant increase in image size.

Case Study: The Pitfall of COPY and RUN chown

When writing a Dockerfile, it's common to copy project files to the container (COPY) and then change the ownership of those files to a specific user (e.g., appuser) using RUN chown.

Inefficient Method: 2 Layers

Initially, the Dockerfile was written as follows.

# 1. Copy files initially (copied as root ownership)
COPY . .

# 2. Change ownership (executed as a separate command)
RUN chown -R appuser:appgroup /app

When checking the history of the built image using docker history, I found that two layers had been created.

IMAGE          CREATED BY                                        SIZE
<layer_id_2>   /bin/sh -c chown -R appuser:appgroup /app        150MB  <-- (Problem!)
<layer_id_1>   /bin/sh -c #(nop) COPY dir:abc in /app           150MB

A serious problem occurs here.

  1. The COPY . . command added 150MB of files to Layer 1.

  2. The RUN chown command copies the 150MB files from Layer 1 unchanged and only changes the ownership information to save it as Layer 2.

Even though the file contents are identical, one is stored in Layer 1 as root ownership and the other in Layer 2 as appuser ownership. As a result, these two layers make the total image size 300MB (150MB + 150MB).

Efficient Method: 1 Layer

This issue can be easily resolved by using the --chown flag with the COPY command.

# 1. Copy while specifying ownership
COPY --chown=appuser:appgroup . .

After modifying the Dockerfile in this way, I checked again using docker history.

IMAGE          CREATED BY                                             SIZE
<layer_id_1>   /bin/sh -c #(nop) COPY --chown=appuser... dir:abc     150MB

Only one layer was created, and the total size of the image was reduced to 150MB. By simply merging two lines of commands into one, the image size was nearly halved.


Conclusion

docker history is not just a tool for viewing the creation history of an image; it is a core analytical tool for image optimization.

After modifying the Dockerfile, it's a good practice to habitually run docker history --no-trunc to check whether the layers were created as intended and to see if there are any layers that unnecessarily occupy space. This small habit can accumulate to create lightweight and efficient images.