1. Overview

Containerization technologies help us build and configure our deployment environments quickly and with lesser cost. Driving with the motto of “write once, deploy anywhere”, we use containerization to address the complexities of modern applications.

In this tutorial, we’ll dig deeper into the Docker Image Layers, which are the fundamental building blocks of containerization technology.

2. Image Layers

Docker images are created by connecting many read-only layers, which are stacked on top of each other to form a complete image. The platforms like Docker and Podman bring the layers together to portray them as a single unified object.

As an example, let’s pull a MySQL image from the registry and have a quick look:

# docker pull mysql
Using default tag: latest
latest: Pulling from library/mysql
492d84e496ea: Pull complete
bbe20050901c: Pull complete
e3a5e171c2f8: Pull complete
c3aceb7e4f48: Pull complete
269002e5cf58: Pull complete
d5abeb1bd18e: Pull complete
cbd79da5fab6: Pull complete
Digest: sha256:cdf3b62d78d1bbb1d2bd6716895a84014e00716177cbb7e90f6c6a37a21dc796
Status: Downloaded newer image for mysql:latest

Each line in the above snippet that ends with “Pull complete” represents the layers pulled from the registry to form an image. As we can see, there are seven layers for the MySQL image.

2.1. Image Layer Creation

Now let’s dive deeper to understand how the layers are built through a Dockerfile illustration.

Instructions like RUN, COPY, and ADD in the Dockerfile create the new layer, whilst others create only the intermediate layers. The former commands have an impact on the layer sizes, but the latter doesn’t.

Let’s build an image through a Dockerfile. We can reference the Dockerfile from this link. We use the docker build command to create the image through the Dockerfile:

# docker build -t layer-demo/latest .
Sending build context to Docker daemon  3.072kB
Step 1/8 : FROM ubuntu:latest
 ---> df5de72bdb3b
Step 2/8 : MAINTAINER baeldung.com
 ---> Running in 2c90e21f29e2
Removing intermediate container 2c90e21f29e2
 ---> 460d0651cc3d
Step 3/8 : ADD get_date.sh /root/get_date.sh
 ---> 492d1b205a94
Step 4/8 : RUN chmod 0644 /root/get_date.sh
 ---> Running in 08d04f1db0de
Removing intermediate container 08d04f1db0de
 ---> 480ba7f4bc50
Step 5/8 : RUN apt-get update
... output truncated ...
 ---> 28182a44db71
Step 6/8 : RUN apt-get -y install cron
... output truncated ...
 ---> 822f3eeca346
Step 7/8 : RUN crontab -l | { cat; echo "* * * * * bash /root/get_date.sh"; } | crontab -
 ---> Running in 635190dfb8d7
no crontab for root
Removing intermediate container 635190dfb8d7
 ---> 2822aac1f51b
Step 8/8 : CMD cron
 ---> Running in 876f0d5aca27
Removing intermediate container 876f0d5aca27
 ---> 5fc87be0f286
Successfully built 5fc87be0f286

What’s happening here? To create this image, we notice it requires eight steps, one for each instruction in the Dockerfile. Initially, the Ubuntu image [Image ID: df5de72bdb3b] is pulled from the registry:

  1. It spins the intermediate container [Container ID: 2c90e21f29e2] with the previous step’s image [Image ID: df5de72bdb3b].
  2. After that, the instruction is executed on the intermediate container [Container ID: 2c90e21f29e2].
  3. Subsequently, the intermediate container converts into an image [Image ID: 460d0651cc3d] through a commit, leading to the removal of the intermediate container [Container ID: 2c90e21f29e2].
  4. After removing the intermediate container, the image becomes a read-only layer. Then it goes to the execution of the next instruction in the Dockerfile.

However, the steps for the new layer’s creation remain the same as above. The intermediate layers cannot influence the image size, whilst the normal layers using RUN, ADD, and COPY are capable of increasing the size.

3. Layer Size

Typically, the size of the image is entirely determined by the layers associated with it. The docker history command shows the size of each layer associated with an image.

In the below example, the layers of size 0B represent an intermediate layer, while the RUN, COPY, and ADD instructions contribute to the image size:

# docker history layer-demo/latest
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
5fc87be0f286   8 hours ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "cron…   0B      
2822aac1f51b   8 hours ago   /bin/sh -c crontab -l | { cat; echo "* * * *…   208B
822f3eeca346   8 hours ago   /bin/sh -c apt-get -y install cron              987kB
28182a44db71   8 hours ago   /bin/sh -c apt-get update                       36MB
480ba7f4bc50   8 hours ago   /bin/sh -c chmod 0644 /root/get_date.sh         5B
492d1b205a94   8 hours ago   /bin/sh -c #(nop) ADD file:1f79f73be93042145…   5B
460d0651cc3d   8 hours ago   /bin/sh -c #(nop)  MAINTAINER baeldung.com      0B
df5de72bdb3b   4 weeks ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B
      4 weeks ago   /bin/sh -c #(nop) ADD file:396eeb65c8d737180…   77.8MB 

Now, let’s summate the size of all the layers, starting with the base image:

  • df5de72bdb3b – 77.800000 MB ## Step 1: Base Ubuntu Image
  • 492d1b205a94 – 0.000005 MB ## Step 3: ADD Instruction
  • 480ba7f4bc50 – 0.000005 MB ## Step 4: RUN Instruction
  • 28182a44db71 – 36.000000 MB ## Step 5: RUN Instruction
  • 822f3eeca346 – 0.987000 MB ## Step 6: RUN Instruction
  • 2822aac1f51b – 0.000208 MB ## Step 7: RUN Instruction

Adding all the above numbers together comes to 114.787 MB, which can be further rounded up to 115 MB. As we can see, the calculated sum exactly matches the layer-demo:latest image size from the docker image command:

# docker images 
REPOSITORY            TAG       IMAGE ID       CREATED       SIZE
layer-demo/latest     latest    5fc87be0f286   8 hours ago   115MB
ubuntu                latest    df5de72bdb3b   4 weeks ago   77.8MB

4. Dangling Images

Dangling images are image layers that are created during image formation. However, after image creation, these layers won’t have any relationship with any tagged images. So it’s safe to remove all those images as they consume unnecessary disk space.

To list out all the dangling images, we can use the docker image command with the dangling attribute set to true in the search filter:

# docker images --filter "dangling=true"

The command below shows the dangling images and then removes them subsequently:

# docker images --quiet --filter=dangling=true | xargs --no-run-if-empty docker rmi

5. Conclusion

In this article, we looked at Docker image layer concepts and creation of the layers. Furthermore, we also discussed the commands we can use to identify the list of layers associated with the image and the size of each layer.

Finally, we saw how the intermediate layers are created and learned that dangling images stay on our system if we don’t clear them frequently.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.