docker layer

Docker Layer | Importance Of Docker Layer In Dockerfile [2022]

If you have worked on docker and pulled an image from the docker hub or created an image from the docker file, you might have noticed that the image pull happens in multiple stages. In this blog post, I am going to talk about docker layers and will go over:

  • What are the keywords in dockerfile
  • what is the docker layer?
  • We will understand how to pull a docker image from dockerhub
  • we will go deep dive into a dockerfile and understand image layers.
  • Finally, we will understand the layers in the official nginx image.

To follow along, I assume you have prior knowledge of docker.

Keywords in dockerfile

Before understanding the docker layer, let’s first understand keywords in Dockerfile.

Docker consists of many keywords, and each keyword in docker represents a layer while creating a docker container. Please find some of the most used keywords in the dockerfile.

ADD copies the files from a source on the host into the container’s own filesystem at the set destination.
CMD can be used for executing a specific command within the container.
ENTRYPOINT sets a default application to be used every time a container is created with the image.
ENV sets environment variables.
EXPOSE associates a specific port to enable networking between the container and the outside world.
FROM defines the base image used to start the build process.
MAINTAINER defines a full name and email address of the image creator.
RUN is the central executing directive for Dockerfiles.
USER sets the UID (or username) which is to run the container.
VOLUME is used to enable access from the container to a directory on the host machine.
WORKDIR sets the path where the command, defined with CMD, is to be executed.
LABEL allows you to add a label to your docker image.

For a Dockerfile to function, all keywords are not required. A user can create a dockerfile using some keywords.

What is the docker layer?

The layer in a dockerfile is the intermediate image created when building an image. A Docker image built up from a series of layers. Each layer represents an instruction in the Dockerfile image. Instruction like COPY, DEL, and RUN create a layer in the dockerfile.

Now Let’s understand docker layers by pulling an image from dockerhub.

Understand the docker layer by example

In this session, we will pull a simple alpine image from the dockerhub, understand how to create a dockerfile, and understand the layer with the help of the dockerfile.

To follow along, make sure docker is installed in your system. If not, follow this link to install docker in your system. Let’s understand this with a simple example. pull an alpine: latest image from the docker hub

➜ docker run alpine:latest
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
540db60ca938: Pull complete
Digest: sha256:69e70a79f2d41ab5d637de98c1e0b055206ba40a8145e7bddb55ccc04e13cf8f
Status: Downloaded newer image for alpine:latest

verify if the image gets downloaded.

➜ docker images
REPOSITORY                    TAG       IMAGE ID       CREATED        SIZE
alpine                        latest    6dbb9cc54074   3 weeks ago    5.61MB

Now check the image history to get information about the layers present in the alpine image.

➜  ~ docker history alpine
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
6dbb9cc54074   3 weeks ago   /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>      3 weeks ago   /bin/sh -c #(nop) ADD file:8ec69d882e7f29f06…   5.61MB

Let’s go to the official alpine image in the docker hub Alpine image

docker layers

Click on the 3.15 tag, and it will take you to the GitHub Docker image file. I have pasted the same yaml file below as well.

FROM scratch
ADD alpine-minirootfs-3.13.5-x86_64.tar.gz /
CMD ["/bin/sh"]

Image overview

Let’s now understand how this dockerfile is written.

  • This dockerfile uses scratch as the base image.
  • In the next step, an alpine-minirootfs-3.13.5-x86_64.tar.gz tar file to the image root folder
  • And when the container starts, “/bin/sh” command ran.

Let’s understand this with a simple diagram.

alpine layers
  • The Above docker file contains basically 2 layers.
  • The first layer is from the base image itself. Here we are using a base image as a scratch. This is a scratch image, so it does not contain any layers.
  • So the first layer gets created when a tar file into the base image. When this operation completes, an intermediate docker container gets created.
  • In the Next step, a new layer gets added for the CMD, which runs in another new container.
  • The old image creates the final layer. Once a new layer is added to the container, the previous container gets deleted, and the final container will only be present.

Was this example pretty small is init? Now, let’s take a bigger dockerfile and debug the layer in that.

Understand docker layer by another example

Many companies use Nginx to load balance their workload. For this demo, let’s pull an Nginx image from the dockerhub.

➜ docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
f7ec5a41d630: Pull complete
aa1efa14b3bf: Pull complete
b78b95af9b17: Pull complete
c7d6bca2b8dc: Pull complete
cf16cd8e71e0: Pull complete
0241c68333ef: Pull complete
Digest: sha256:75a55d33ecc73c2a242450a9f1cc858499d468f077ea942867e662c247b5e412
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

Once the image gets successfully pulled, let’s verify the image history to get the layer details.

➜ docker history nginx
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
62d49f9bab67   3 weeks ago   /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B
<missing>      3 weeks ago   /bin/sh -c #(nop)  STOPSIGNAL SIGQUIT           0B
<missing>      3 weeks ago   /bin/sh -c #(nop)  EXPOSE 80                    0B
<missing>      3 weeks ago   /bin/sh -c #(nop)  ENTRYPOINT ["/docker-entr…   0B
<missing>      3 weeks ago   /bin/sh -c #(nop) COPY file:09a214a3e07c919a…   4.61kB
<missing>      3 weeks ago   /bin/sh -c #(nop) COPY file:0fd5fca330dcd6a7…   1.04kB
<missing>      3 weeks ago   /bin/sh -c #(nop) COPY file:0b866ff3fc1ef5b0…   1.96kB
<missing>      3 weeks ago   /bin/sh -c #(nop) COPY file:65504f71f5855ca0…   1.2kB
<missing>      3 weeks ago   /bin/sh -c set -x     && addgroup --system -…   63.9MB
<missing>      3 weeks ago   /bin/sh -c #(nop)  ENV PKG_RELEASE=1~buster     0B
<missing>      3 weeks ago   /bin/sh -c #(nop)  ENV NJS_VERSION=0.5.3        0B
<missing>      3 weeks ago   /bin/sh -c #(nop)  ENV NGINX_VERSION=1.19.10    0B
<missing>      3 weeks ago   /bin/sh -c #(nop)  LABEL maintainer=NGINX Do…   0B
<missing>      3 weeks ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>      3 weeks ago   /bin/sh -c #(nop) ADD file:c855b3c65f5ba94d5…   69.3MB

Now try to co-relate the image layer with the official docker file of Nginx.

The Nginx dockerfile looks like this:

#
# NOTE: THIS DOCKERFILE IS GENERATED VIA "update.sh"
#
# PLEASE DO NOT EDIT IT DIRECTLY.
#
FROM debian:buster-slim

LABEL maintainer="NGINX Docker Maintainers <[email protected]>"

ENV NGINX_VERSION   1.19.10
ENV NJS_VERSION     0.5.3
ENV PKG_RELEASE     1~buster

RUN set -x \
# create nginx user/group first, to be consistent throughout docker variants
 ..........
 ...........
# create a docker-entrypoint.d directory
    && mkdir /docker-entrypoint.d

COPY docker-entrypoint.sh /
COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d
COPY 20-envsubst-on-templates.sh /docker-entrypoint.d
COPY 30-tune-worker-processes.sh /docker-entrypoint.d
ENTRYPOINT ["/docker-entrypoint.sh"]

EXPOSE 80

STOPSIGNAL SIGQUIT

CMD ["nginx", "-g", "daemon off;"] 

In the Nginx image, debian:buster-slim is used as a base image. The debian:buster-slim dockerfile looks like this:

FROM scratch
ADD rootfs.tar.xz /
CMD ["bash"]

The Debian image is created from the scratch image, the rootfs file is added from the root directory, and finally, the start “bash” command runs.

So in the Nginx image, the first two layers have come from the base image.

<missing>      3 weeks ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>      3 weeks ago   /bin/sh -c #(nop) ADD file:c855b3c65f5ba94d5…   69.3MB

And after that, a new layer will be created for each subsequent operation.

CMD ["nginx" "-g" "daemon…   
STOPSIGNAL SIGQUIT           
EXPOSE 80                    
ENTRYPOINT ["/docker-entr…   
COPY file:09a214a3e07c919a…   
COPY file:0fd5fca330dcd6a7…   
COPY file:0b866ff3fc1ef5b0…   
COPY file:65504f71f5855ca0…   
RUN .... && addgroup --system -…  
ENV PKG_RELEASE=1~buster    
ENV NJS_VERSION=0.5.3        
ENV NGINX_VERSION=1.19.10    
LABEL maintainer=NGINX Do… 

Layer layout

I have created a diagram to explain the layers corresponding to the dockerfile. Refer to this diagram to understand the layers

nginx layer

Now we have a pretty good idea about the docker layers. The next question that should come to your mind will be why it is important to check for layers while creating a dockerfile.In the below session, we will try to understand why we should always look for layers while creating a dockerfile.

Importance of docker layer in dockerfile

While creating a dockerfile, our primary goal is to keep the image size as less as possible. A Docker image takes up more space for every layer you add to it. Therefore, the more layers the image has, the more space the image requires.

Let’s consider a scenario where you have created the below docker file

#
# NOTE: THIS DOCKERFILE IS GENERATED VIA "update.sh"
#
# PLEASE DO NOT EDIT IT DIRECTLY.
#
FROM debian:buster-slim

LABEL maintainer="XXX Docker Maintainers <[email protected]>"
RUN apt-get update
RUN apt-get install -y
RUN test-package

In the above dockerfile, we have 3 RUN commands, which will add three layers in the Dockerfile, leading to a bigger image size. To avoid such a scenario, we can rewrite our dockerfile as below:

#
# NOTE: THIS DOCKERFILE IS GENERATED VIA "update.sh"
#
# PLEASE DO NOT EDIT IT DIRECTLY.
#
FROM debian:buster-slim

LABEL maintainer="XXX Docker Maintainers <[email protected]>"
RUN apt-get update && apt-get install -y && test-package

In the above example, we have twisted the dockerfile to reduce the number layer, which unlimitedly leads to a smaller dockerfile.

Conclusion

Congratulations, I hope you now have a basic understanding of layers in docker. You have also learned how to check the layers from images pulled from dockerhub. We also understand the complex docker layer by taking the example of the official Nginx image, and finally, we understood the significance of docker layers.

Please let me know if you enjoyed this article in the comment box.

Happy learning.

More to read

docker base image

what all docker images are available

docker jupyter

docker vs docker-compose

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top