2022-12-22

Overview

Docker images are a powerful tool for packaging and deploying applications, but it can be difficult to understand the differences between two images. In this blog, we will demonstrate how to compare two images of a Node.js application using several popular tools. We will use docker inspect to view the low-level details of an image, container-diff to compare files and configuration changes, and dive to visualize the layers of an image. Through this comparison, we will learn how to identify the differences between two images and understand how those differences may impact the performance, security and size of the images. This will help us to understand how to select the best image for our use case, and how to troubleshoot issues.

Docker Inspect

Firstly, we can use docker inspect to check the low-level details of an image.

The docker inspect command is used to view low-level details of a Docker image. When you run docker inspect on an image, it returns a JSON object that contains information about the image, including metadata, config, history, and the layer's filesystems. Here are a few examples of the information that you can get from running docker inspect on an image:

# single stage build
➜  test1000 git:(main) ✗ docker inspect 8c5368c4b334
[
    {
        "Id": "sha256:8c5368c4b3343455c851ba28c2712c344ef9221b76903789024774d9bfb36f46",
        "RepoTags": [
            "davidzhangw/coffee:v2"
        ],
        "RepoDigests": [
            "davidzhangw/coffee@sha256:5d8784dcbcf2196910b8b2e1d1650217aec5b1b262831b50df99aa9d31d8fb26"
        ],
        "Parent": "",
        "Comment": "buildkit.dockerfile.v0",
        "Created": "2023-01-12T03:58:47.156540625Z",
        "Container": "",
        "ContainerConfig": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": null,
            "Cmd": null,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "DockerVersion": "",
        "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",
                "NODE_VERSION=19.4.0",
                "YARN_VERSION=1.22.19"
            ],
            "Cmd": [
                "npm",
                "run",
                "start"
            ],
            "ArgsEscaped": true,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "/app",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 1998434757,
        "VirtualSize": 1998434757,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/lxw5ya6tvive6tluustvn53za/diff:/var/lib/docker/overlay2/pofdzxu8szk50mfkp2e6opo34/diff:/var/lib/docker/overlay2/g8e0iuznahft9976n38v95my6/diff:/var/lib/docker/overlay2/p48ndp1tsmpxxsmtt0ks4hnht/diff:/var/lib/docker/overlay2/88mblz57wfcfsxp6t1ghety3c/diff:/var/lib/docker/overlay2/b13186853ac88f9ab23b6b4ef28f50afd30c9d2505d76a6dc66998cb19af0142/diff:/var/lib/docker/overlay2/bad42c6df0a4e63e6c00b18a4c29fb59894040c2884d090a5f0b9f7a0ea667fb/diff:/var/lib/docker/overlay2/b4b0bc3d9289c5d2874884c6cdda952bb3274dff3173fff7abad891593b4ff29/diff:/var/lib/docker/overlay2/82092b666d220f3dea0fcca899acec4ccd1fe1b362e1c74466f35f2161b28f47/diff",
                "MergedDir": "/var/lib/docker/overlay2/v492rnnl73t0vhb3c8b497rec/merged",
                "UpperDir": "/var/lib/docker/overlay2/v492rnnl73t0vhb3c8b497rec/diff",
                "WorkDir": "/var/lib/docker/overlay2/v492rnnl73t0vhb3c8b497rec/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:8e012198eea15b2554b07014081c85fec4967a1b9cc4b65bd9a4bce3ae1c0c88",
                "sha256:a49d675cd49c631e995be8fa05ffffc412bba04820ebdaf654e92f317120923c",
                "sha256:887a67b27874c174f149eacb3eff9f11999767cdf731a410a9d333933247b46d",
                "sha256:6d0edcc4175ba7264c14e60bef68919164af84d72bc1a4f9f99acacb42f25d83",
                "sha256:44ac598f28410ce3ece1ab2cd349cf781defb75c6730aec009dada21457bb991",
                "sha256:99df869b10b55218bca6421f0d52f737b7944a210a08b0627df455ff9b4085f3",
                "sha256:24262d08a858d3d458989039a85619f3a558be7d98f19deddb564357a1d800a2",
                "sha256:6904210f6073486388c2dfedada7e7113ea0854bf35274dd7ad589f7cfba7967",
                "sha256:0cf1fdea0d82dd6f58393c39d37d1b576db0b54712b95eba8bace4a56b34e2b9",
                "sha256:175344ff0f2bb74487c29590eeb3de1e245b7896ac6d7a468372a3851b790bd8"
            ]
        },
        "Metadata": {
            "LastTagTime": "2023-01-12T03:58:51.680480585Z"
        }
    }
]

Container-diff

# multi-stage build
➜  test1000 git:(main) ✗ docker inspect b4a554029c8d
[
    {
        "Id": "sha256:b4a554029c8d40f0f537e70258e1ea4e65e7714d5f4d6efbcb01d2d218307e69",
        "RepoTags": [
            "davidzhangw/coffee:v3"
        ],
        "RepoDigests": [
            "davidzhangw/coffee@sha256:c069c18560f6a7f474ea0782a59052582e4c70979ddf00373a78842ee15f13b0"
        ],
        "Parent": "",
        "Comment": "buildkit.dockerfile.v0",
        "Created": "2023-01-20T09:48:06.929174555Z",
        "Container": "",
        "ContainerConfig": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": null,
            "Cmd": null,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "DockerVersion": "",
        "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",
                "NODE_VERSION=19.4.0",
                "YARN_VERSION=1.22.19"
            ],
            "Cmd": [
                "npm",
                "run",
                "start"
            ],
            "ArgsEscaped": true,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "/app",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 952727102,
        "VirtualSize": 952727102,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/ktmaji0naxpdssgksmdvty2qz/diff:/var/lib/docker/overlay2/ive3ckpnacx6xws0lkver3cpt/diff:/var/lib/docker/overlay2/k71s51gqnetpwigia8tk1gw31/diff:/var/lib/docker/overlay2/lkpceob4bzn7k3f1tloaqs947/diff:/var/lib/docker/overlay2/88mblz57wfcfsxp6t1ghety3c/diff:/var/lib/docker/overlay2/b13186853ac88f9ab23b6b4ef28f50afd30c9d2505d76a6dc66998cb19af0142/diff:/var/lib/docker/overlay2/bad42c6df0a4e63e6c00b18a4c29fb59894040c2884d090a5f0b9f7a0ea667fb/diff:/var/lib/docker/overlay2/b4b0bc3d9289c5d2874884c6cdda952bb3274dff3173fff7abad891593b4ff29/diff:/var/lib/docker/overlay2/82092b666d220f3dea0fcca899acec4ccd1fe1b362e1c74466f35f2161b28f47/diff",
                "MergedDir": "/var/lib/docker/overlay2/ff1osvxhtdl3evp6nkomb15lm/merged",
                "UpperDir": "/var/lib/docker/overlay2/ff1osvxhtdl3evp6nkomb15lm/diff",
                "WorkDir": "/var/lib/docker/overlay2/ff1osvxhtdl3evp6nkomb15lm/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:8e012198eea15b2554b07014081c85fec4967a1b9cc4b65bd9a4bce3ae1c0c88",
                "sha256:a49d675cd49c631e995be8fa05ffffc412bba04820ebdaf654e92f317120923c",
                "sha256:887a67b27874c174f149eacb3eff9f11999767cdf731a410a9d333933247b46d",
                "sha256:6d0edcc4175ba7264c14e60bef68919164af84d72bc1a4f9f99acacb42f25d83",
                "sha256:44ac598f28410ce3ece1ab2cd349cf781defb75c6730aec009dada21457bb991",
                "sha256:451ec394cf2cf0355952c5199855e3de0d446291bca48e0928435122a3286a0d",
                "sha256:2bb99a439a5a606aa1c5096d2d744d0da75e0f2e248df95d9c2878999641b989",
                "sha256:27ebabaecb857acccb1a7e34573e197c8633f8fa7ad6fbc48fee61b61544a593",
                "sha256:c60cbc4de8352216907ddd35330052f8d3b421504cb9e8a83a599175e3971249",
                "sha256:9c94ddf41eb611b1ac1f6403c001237d47cba4e688685ce003d556da973b0c07"
            ]
        },
        "Metadata": {
            "LastTagTime": "2023-01-20T09:48:11.007232668Z"
        }
    }
]

container-diff is a command-line tool that allows you to compare the differences between two Docker images. It can show you the changes in files, environment variables, and configuration between two images.

To compare two images, you can run the command container-diff diff <image1> <image2>. It will show the differences between the two images, indicating which files were added, modified, or deleted, as well as any changes to environment variables or configuration. The output is presented in a unified diff format, which is similar to the output of the diff command.

<aside> 👉 Please note that we use daemon to refer the local docker image.

</aside>

Please refer to Reference section to install container-diff.