Showing Differences Between Two Docker Images – 显示两个Docker镜像之间的差异

最后修改: 2022年 7月 22日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

As more and more applications are deployed using Docker, it’s essential that we understand some basic principles of its ecosystem. While the available tooling makes it easy to package and deploy applications, at some point, we may need to troubleshoot some aspects of our deployment.

随着越来越多的应用程序使用Docker进行部署,我们有必要了解其生态系统的一些基本原则。虽然现有的工具使打包和部署应用程序变得容易,但在某些时候,我们可能需要对部署的某些方面进行故障排除

One of the more common tasks with debugging deployments is examining and comparing images. In this tutorial, we’ll look at the structure of Docker images and how to see the differences between the two images.

调试部署的一个比较常见的任务是检查和比较镜像。在本教程中,我们将研究Docker镜像的结构以及如何查看两个镜像之间的差异。

2. About Docker Images

2.关于Docker图像

As some background, Docker images are the instructions for how to create a container. We can think of them as the complete set of files and directories required to run an application inside a container. This includes the operating system, 3rd party libraries, and our application code.

作为一些背景,Docker图像是如何创建一个容器的说明。我们可以将其视为在容器内运行应用程序所需的一整套文件和目录。这包括操作系统、第三方库和我们的应用程序代码。

Under the hood, these images are essentially just tar files. When building the images, we are creating different layers within it. Each layer is a collection of files and directories.

在引擎盖下,这些图像本质上只是tar文件。在构建图像时,我们正在其中创建不同的层。每个层都是一个文件和目录的集合。

Typically, we start with an existing image and add to it. For example, to build a Spring Boot application as an image, we’d start with an existing OpenJDK Docker image. This contains the operating system and JDK files required to run any Java application. From there, we’d add our own Java files, usually the application’s fat jar, along with any required 3rd party libraries.

通常情况下,我们从一个现有的镜像开始,然后向其添加。例如,要将Spring Boot 应用程序构建为一个映像,我们将从现有的OpenJDK Docker 映像开始。它包含运行任何Java应用程序所需的操作系统和JDK文件。在这里,我们将添加自己的Java文件,通常是应用程序的fat jar,以及任何所需的第三方库。

At the end of the build, we have a single image containing all the files necessary to run our application. Next, we’ll look at how to examine a single image.

在构建结束时,我们有一个单一的镜像,包含运行我们的应用程序所需的所有文件。接下来,我们将看看如何检查单个镜像。

3. Examining a Docker Image

3.检查Docker镜像

There are a few different ways to examine an image. Let’s start by finding all the images in our local repo:

有几种不同的方法来检查一个图像。让我们从找到本地 repo 中的所有图像开始。

$ docker image ls
spring-petclinic    2.7.0-SNAPSHOT    0f9d2d05687b   2 months ago    266MB
spring-petclinic    2.6.0-SNAPSHOT    1d79d5bd7779   3 months ago    265MB

With the list of available images, we can now look at a specific one.

有了可用的图像列表,我们现在可以查看一个特定的图像。

The first thing we can do is run the inspect command:

我们可以做的第一件事是运行inspect命令。

$ docker inspect 0f9d2d05687b
[
    {
        "Id": "sha256:0f9d2d05687b8c816cbf54f63cf7e5aa7144d28e1996d468bfaf555a3882610a",
        "RepoTags": [
            "spring-petclinic:2.7.0-SNAPSHOT"
        ],
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 266141567,
        "VirtualSize": 266141567,
        ...
    }
]

This command gives us lots of details about the image, including when it was created, the different layers inside it, and more.

这个命令给我们提供了很多关于图像的细节,包括它是什么时候创建的,里面的不同图层,等等。

It doesn’t, however, tell us much about the contents inside. For that, we must first save the image to the file system:

然而,它并没有告诉我们很多关于里面的内容。为此,我们必须首先将图像保存到文件系统中。

$ docker save 0f9d2d05687b > 0f9d2d05687b.tar

This command will save the image as a tar file. Now we can use the familiar tar command to examine it:

这个命令将把图像保存为一个tar文件。现在我们可以使用熟悉的tar命令来检查它。

$ tar tvf 0f9d2d05687b.tar
drwxr-xr-x  0 0      0           0 Dec 31  1979 02805fa4a4f35efdcf3804bc1218af1bc22d28ee521cc944cab5cac5dbe5abfe/
-rw-r--r--  0 0      0           3 Dec 31  1979 02805fa4a4f35efdcf3804bc1218af1bc22d28ee521cc944cab5cac5dbe5abfe/VERSION
-rw-r--r--  0 0      0         477 Dec 31  1979 02805fa4a4f35efdcf3804bc1218af1bc22d28ee521cc944cab5cac5dbe5abfe/json
-rw-r--r--  0 0      0        1024 Dec 31  1979 02805fa4a4f35efdcf3804bc1218af1bc22d28ee521cc944cab5cac5dbe5abfe/layer.tar
drwxr-xr-x  0 0      0           0 Dec 31  1979 0f915e8772f0e40420852f1e2929e4ae9408327cbda6c546c71cca7c3e2f094a/
-rw-r--r--  0 0      0           3 Dec 31  1979 0f915e8772f0e40420852f1e2929e4ae9408327cbda6c546c71cca7c3e2f094a/VERSION
-rw-r--r--  0 0      0         477 Dec 31  1979 0f915e8772f0e40420852f1e2929e4ae9408327cbda6c546c71cca7c3e2f094a/json
-rw-r--r--  0 0      0     3622400 Dec 31  1979 0f915e8772f0e40420852f1e2929e4ae9408327cbda6c546c71cca7c3e2f094a/layer.tar

The tar command can list and extract specific files from the image, depending on what information we are looking for.

tar命令可以从图像中列出并提取特定的文件,这取决于我们正在寻找什么信息。

4. Showing Diffs Between Two Docker Images

4.显示两个Docker镜像之间的差异

So far, we’ve looked at the structure of an image and how to inspect it. Next, let’s look at how we can compare two images and find their differences.

到目前为止,我们已经了解了图像的结构以及如何检查它。接下来,让我们看看如何比较两幅图像并找出它们的差异

Depending on what information we want to compare, there are different tools that can help. As we saw above, the built-in image command can give us the size and date information.

根据我们想要比较的信息,有不同的工具可以帮助我们。正如我们上面看到的,内置的image命令可以给我们提供尺寸和日期信息。

But if we want to compare the contents of two images, we need to use a third-party tool. Below, we’ll look at a couple of them.

但如果我们想比较两张图片的内容,我们需要使用第三方工具。下面,我们就来看看其中的几个。

4.1. Container Diff

4.1.容器差异

One such tool is Google’s container-diff. Despite its name, it can compare various aspects of two images and provide a nicely formatted report.

其中一个工具是Google的容器-diff。尽管它的名字是这样的,但它可以比较两张图片的各个方面,并提供一个格式良好的报告。

For example, let’s compare the two Spring pet clinic images from the earlier example:

例如,让我们比较一下前面例子中的两张Spring宠物诊所图片。

$ /usr/local/bin/container-diff diff \
daemon://spring-petclinic:2.6.0-SNAPSHOT \
daemon://spring-petclinic:2.7.0-SNAPSHOT \
--type=file

This gives us the differences in the files of each image.

这给我们提供了每个图像的文件的差异。

The output is generally broken into three sections. First, it tells which files exist in the first image, but not in the second:

输出通常分为三个部分。首先,它告诉人们哪些文件存在于第一幅图像中,但不在第二幅图像中。

/workspace/BOOT-INF/lib/byte-buddy-1.12.10.jar                                                    3.7M
/workspace/BOOT-INF/lib/classgraph-4.8.139.jar                                                    551.7K
/workspace/BOOT-INF/lib/ehcache-3.10.0.jar                                                        1.7M
/workspace/BOOT-INF/lib/h2-2.1.212.jar                                                            2.4M
/workspace/BOOT-INF/lib/hibernate-core-5.6.9.Final.jar                                            7.1M
/workspace/BOOT-INF/lib/jackson-annotations-2.13.3.jar                                            73.9K

Next, it tells us which files exist in the second image, but not in the first:

接下来,它告诉我们哪些文件存在于第二幅图像中,而不是第一幅图像中。

These entries have been deleted from spring-petclinic:2.6.0-SNAPSHOT:
FILE                                                                        SIZE
/workspace/BOOT-INF/lib/byte-buddy-1.11.22.jar                              3.5M
/workspace/BOOT-INF/lib/classgraph-4.8.115.jar                              525.4K
/workspace/BOOT-INF/lib/ehcache-3.9.9.jar                                   1.7M
/workspace/BOOT-INF/lib/h2-1.4.200.jar                                      2.2M
/workspace/BOOT-INF/lib/hibernate-core-5.6.7.Final.jar                      7.1M
/workspace/BOOT-INF/lib/jackson-annotations-2.13.2.jar                      73.9K

In this case, the two sections combined can tell us very quickly how the dependencies have changed between each version of the application.

在这种情况下,这两个部分结合起来可以非常迅速地告诉我们每个版本的应用程序之间的依赖关系有什么变化。

And finally, the last section tells which files exist in both, but are different:

最后,最后一节告诉大家哪些文件存在于两者中,但又是不同的。

These entries have been changed between spring-petclinic:2.6.0-SNAPSHOT and spring-petclinic:2.7.0-SNAPSHOT:
FILE                                                                                                 SIZE1        SIZE2
/layers/config/metadata.toml                                                                         16.6K        1.9K
/workspace/META-INF/maven/org.springframework.samples/spring-petclinic/pom.xml                       13.3K        13.3K
/workspace/BOOT-INF/classes/org/springframework/samples/petclinic/owner/OwnerController.class        7.8K         7.7K
/workspace/org/springframework/boot/loader/ExecutableArchiveLauncher.class                           6.6K         7.5K
/workspace/org/springframework/boot/loader/JarLauncher.class                                         3.9K         2.5K
/workspace/BOOT-INF/classpath.idx                                                                    3.2K         3.2K
/workspace/org/springframework/boot/loader/data/RandomAccessDataFile$FileAccess.class                3.2K         3.2K
/workspace/BOOT-INF/classes/db/h2/data.sql                                                           2.8K         3K
/workspace/org/springframework/boot/loader/data/RandomAccessDataFile$DataInputStream.class           2.6K         2.7K

This section makes it very easy to identify any specific classes and properties files that have changed between the two versions.

这一部分可以非常容易地识别两个版本之间任何特定的类和属性文件的变化。

4.2. Dive

4.2.潜水

Another great open source tool for inspecting Docker images is dive. Inspecting images with dive gives us a more traditional view of its contents because it understands how to examine each layer inside the image. This allows it to present each image using a traditional file system tree:

另一个用于检查Docker镜像的优秀开源工具是dive。使用dive检查图像时,我们可以对其内容有一个更传统的看法,因为它了解如何检查图像内的每一层。这使得它能够使用传统的文件系统树来展示每个图像。

dive single image view

Using the keyboard, we can navigate through each layer of the image and see exactly which files it added, modified, or removed.

使用键盘,我们可以浏览图像的每一层,准确地看到它添加、修改或删除了哪些文件。

While the dive tool does not natively support comparing images, we can manually do that by simply running it on two terminals side-by-side:

虽然dive工具本身不支持比较图像,但我们可以通过简单地在两个终端上并排运行来手动进行比较。

dive compare two docker images

In this manner, we can see which layers are the same (based on size), and for the different ones, we can see which files are different.

通过这种方式,我们可以看到哪些层是相同的(基于大小),对于不同的层,我们可以看到哪些文件是不同的。

5. Conclusion

5.总结

In this article, we looked at the structure of Docker images and saw various ways to inspect them. While the Docker client contains some tools for inspecting single images, comparing two images requires using a 3rd party tool.

在这篇文章中,我们研究了Docker镜像的结构,并看到了检查镜像的各种方法。虽然Docker客户端包含一些用于检查单个镜像的工具,但比较两个镜像需要使用第三方工具

Google’s container-diff is one option built specifically for comparing images. And while the dive utility is great for inspecting the layer of a single image, it can also be used to identify differences by simply running it against two images at the same time.

谷歌的container-diff是一个专门为比较图像而建立的选项。虽然dive工具对于检查单个图像的图层非常好,但它也可以通过简单地同时对两个图像运行来识别差异。