Skip to content

Understanding Image Layering Concept with Dockerfile

Docker container is a runnable instance of an image, which is actually made by writing a readable/writable layer on top of some read-only layers.

The parent image used to create another image from a Dockerfile is read-only. When we execute instructions on this parent image, new layers keep adding up. These layers are created when we run docker build command.

The instructions RUN, COPY, ADD mostly contribute to the addition of layers in a Docker build.

Each layer is read-only except the last one - this is added to the image for generating a runnable container. This last layer is called "container layer". All changes made to the container, like making new files, installing applications, etc. are done in this thin layer.

Let's understand this layering using an example:

Consider the Dockerfile given below:

FROM ubuntu:latest
RUN mkdir -p /hello/hello
COPY hello.txt /hello/hello
RUN chmod 600 /hello/hello/hello.txt

Layer ID

Each instruction the Dockerfile generates a layer. Each of this layer has a randomly generated unique ID. This ID can be seen at the time of build. See the image below:

Docker layers during Build

To view all these layers once an image is built from a Dockerfile, we can use docker history command.

Docker history

To see more information about the Docker image and the layers use docker inspect command as such:

# docker inspect testimage:latest

[
    {
        "Id": "sha256:c5701e02ed095ae7cabaef9fcef009d1f272206ff707deca13a680e024db7f02",
        "RepoTags": [
            "testimage:latest"
        ],
        "RepoDigests": [],
        "Parent": "sha256:694569c6db07ecef432cee1a9a4a6d45f2fd1f6be16814bf59e101bed966e612",
        "Comment": "",
        "Created": "2019-06-03T23:47:01.026463541Z",
        "Container": "ac8873a003cb9ed972b4675f8d27181b99112e7530a5803ff89780e3ecc18b1c",
        "ContainerConfig": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "chmod 600 /home/hello/hello.txt"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:694569c6db07ecef432cee1a9a4a6d45f2fd1f6be16814bf59e101bed966e612",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "DockerVersion": "18.03.1-ce",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/bash"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:694569c6db07ecef432cee1a9a4a6d45f2fd1f6be16814bf59e101bed966e612",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 222876395,
        "VirtualSize": 222876395,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/86a76eac21ae67f6d78e59076107a121e6dfb9cc922e68e1be975fc97e711eb1/diff:/var/lib/docker/overlay2/0604b502d31eff670769257ba3411fca09fbe2eab03343660ba557024915a1e6/diff:/var/lib/docker/overlay2/16af32e079fbc252ea5de044628285d5c3a34fc8441602a762729482666b2431/diff:/var/lib/docker/overlay2/732c4ab0164f92664ce831b4a830251132bf17cbcb7d093334a7a367b1a665e5/diff:/var/lib/docker/overlay2/c8a69709e5093c6eefa317f015cbf1422a446b2fe5d3f3d52a7e0d8af8dc6a28/diff:/var/lib/docker/overlay2/c93b36ec3a753592518727a2ea4547ab4e53d58489b9fae0838b2806e9c18346/diff:/var/lib/docker/overlay2/e67589599c2a5ed3bd74a269f3effaa52f94975fd811a866f1fe2bbcb2edabe4/diff",
                "MergedDir": "/var/lib/docker/overlay2/31c68adcd824f155d23de4197b3d0b8776b079c307c1e4c0f2f8bbc73807adc0/merged",
                "UpperDir": "/var/lib/docker/overlay2/31c68adcd824f155d23de4197b3d0b8776b079c307c1e4c0f2f8bbc73807adc0/diff",
                "WorkDir": "/var/lib/docker/overlay2/31c68adcd824f155d23de4197b3d0b8776b079c307c1e4c0f2f8bbc73807adc0/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:05b0f7f2a81723fd647744a7340477ef9619f5ddeba3f2ca039dac3dd143cd59",
                "sha256:0c3819952093832ffd8865bf72bc17f2f5475795cffe97e2b4c4ff36e638c244",
                "sha256:14fa4a9494bf9e61f83a1bb96cd9e963ab0cbbdaf8ed91ff5eec5196c5bf7b12",
                "sha256:b33859b66bfd3ad176ccf3be8dbd52d6b9823de8cc26688f2efeb76a0ea24a78",
                "sha256:4622c8e1bdc0716e185fa3b338fa415dfdad3724336315de0bebd173a6ceaf05",
                "sha256:6427efc3a0d7bae1fe315b844703580b2095073dcdf54a6ed9c7b1c0d982d9b0",
                "sha256:59cd898074ac7765bacd76a11724b8d666ed8e9c14e7806dfb20a486102f6f1e",
                "sha256:ad24f18512fddb8794612f7ec5955d06dcee93641d02932d809f0640263b8e79"
            ]
        },
        "Metadata": {
            "LastTagTime": "2019-06-04T05:17:01.430558997+05:30"
        }
    }
]

Do you want to visualize layers of Docker Image?

docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock  wagoodman/dive testimage

``` [● Layers]───────────────────────────────────────────────────────────────────────────── [Current Layer Contents]─────────────────────────────────────────────────────────────── Cmp Size Command Permission UID:GID Size Filetree 63 MB FROM e388568efdf7281 drwxr-xr-x 0:0 4.8 MB ├── bin 988 kB [ -z "$(apt-get indextargets)" ] -rwxr-xr-x 0:0 1.1 MB │ ├── bash 745 B set -xe && echo '#!/bin/sh' > /usr/sbin/policy-rc.d && echo 'exit 101' > -rwxr-xr-x 0:0 35 kB │ ├── bunzip2 7 B mkdir -p /run/systemd && echo 'docker' > /run/systemd/container -rwxr-xr-x 0:0 0 B │ ├── bzcat → bin/bunzip2 0 B mkdir -p /hello/hello -rwxrwxrwx 0:0 0 B │ ├── bzcmp → bzdiff 37 B #(nop) COPY file:666735678ded52c6f9e0693ca27b4dc3d466e3d79c585a58c3b9a91357 -rwxr-xr-x 0:0 2.1 kB │ ├── bzdiff 37 B chmod 600 /hello/hello/hello.txt -rwxrwxrwx 0:0 0 B │ ├── bzegrep → bzgrep -rwxr-xr-x 0:0 4.9 kB │ ├── bzexe [Layer Details]──────────────────────────────────────────────────────────────────────── -rwxrwxrwx 0:0 0 B │ ├── bzfgrep → bzgrep -rwxr-xr-x 0:0 3.6 kB │ ├── bzgrep Tags: (unavailable) -rwxr-xr-x 0:0 0 B │ ├── bzip2 → bin/bunzip2 Id: e388568efdf72814bd6439a80d822ce06b631689a82292a2b96382d020d63a4c -rwxr-xr-x 0:0 14 kB │ ├── bzip2recover Digest: sha256:43c67172d1d182ca5460fc962f8f053f33028e0a3a1d423e05d91b532429e73d -rwxrwxrwx 0:0 0 B │ ├── bzless → bzmore Command: -rwxr-xr-x 0:0 1.3 kB │ ├── bzmore

(nop) ADD file:08e718ed0796013f5957a1be7da3bef6225f3d82d8be0a86a7114e5caad50cbc in / -rwxr-xr-x 0:0 35 kB │ ├── cat

                                                                                    -rwxr-xr-x         0:0      64 kB  │   ├── chgrp

[Image Details]──────────────────────────────────────────────────────────────────────── -rwxr-xr-x 0:0 60 kB │ ├── chmod -rwxr-xr-x 0:0 68 kB │ ├── chown Total Image size: 64 MB -rwxr-xr-x 0:0 142 kB │ ├── cp Potential wasted space: 308 B -rwxr-xr-x 0:0 121 kB │ ├── dash Image efficiency score: 99 % -rwxr-xr-x 0:0 101 kB │ ├── date -rwxr-xr-x 0:0 76 kB │ ├── dd Count Total Space Path -rwxr-xr-x 0:0 85 kB │ ├── df 2 234 B /var/lib/dpkg/diversions -rwxr-xr-x 0:0 134 kB │ ├── dir 2 74 B /hello/hello/hello.txt -rwxr-xr-x 0:0 72 kB │ ├── dmesg -rwxrwxrwx 0:0 0 B │ ├── dnsdomainname → hostname -rwxrwxrwx 0:0 0 B │ ├── domainname → hostname -rwxr-xr-x 0:0 35 kB │ ├── echo -rwxr-xr-x 0:0 28 B │ ├── egrep -rwxr-xr-x 0:0 31 kB │ ├── false -rwxr-xr-x 0:0 28 B │ ├── fgrep -rwxr-xr-x 0:0 65 kB │ ├── findmnt -rwxr-xr-x 0:0 220 kB │ ├── grep -rwxr-xr-x 0:0 2.3 kB │ ├── gunzip -rwxr-xr-x 0:0 5.9 kB │ ├── gzexe -rwxr-xr-x 0:0 102 kB │ ├── gzip ```

Contributor

Prashansa Kulshrestha
Ajeet S Raina