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.
-
The
COPY . .command added 150MB of files to Layer 1. -
The
RUN chowncommand 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.
There are no comments.