如何验证两个Docker镜像的内容是否完全相同?

时间:2017-09-20 12:16:21

标签: docker dockerfile

我们如何确定两个Docker镜像具有完全相同的文件系统结构,并且相应文件的内容是否相同,与文件时间戳无关?

我尝试了图片ID,但是在使用相同的Dockerfile和干净的本地存储库构建时它们有所不同:我通过构建一个图像,清理本地存储库,然后触摸其中一个文件以更改其修改日期来进行此测试,然后构建第二个图像,它们的图像ID不匹配。我使用的是Docker 17.06(我相信的最新版本)。

由于

4 个答案:

答案 0 :(得分:3)

如果要比较图像内容,可以使用docker inspect <imageName>命令,可以查看RootFS部分

docker inspect redis

    "RootFS": {
        "Type": "layers",
        "Layers": [
            "sha256:eda7136a91b7b4ba57aee64509b42bda59e630afcb2b63482d1b3341bf6e2bbb",
            "sha256:c4c228cb4e20c84a0e268dda4ba36eea3c3b1e34c239126b6ee63de430720635",
            "sha256:e7ec07c2297f9507eeaccc02b0148dae0a3a473adec4ab8ec1cbaacde62928d9",
            "sha256:38e87cc81b6bed0c57f650d88ed8939aa71140b289a183ae158f1fa8e0de3ca8",
            "sha256:d0f537e75fa6bdad0df5f844c7854dc8f6631ff292eb53dc41e897bc453c3f11",
            "sha256:28caa9731d5da4265bad76fc67e6be12dfb2f5598c95a0c0d284a9a2443932bc"
        ]
    }

如果所有图层都相同,则图像包含相同的内容

答案 1 :(得分:3)

经过一些研究后,我想出了一个解决方案,根据我的测试,它是快速而干净的。

整体解决方案是:

  1. 通过docker create ...
  2. 为您的图片创建容器
  3. 通过docker export ...
  4. 将整个文件系统导出到tar存档
  5. 将存档目录名称,符号链接名称,符号链接内容,文件名和文件内容管道传输到哈希函数(例如,MD5)
  6. 比较不同图像的哈希值以验证其内容是否相等
  7. 就是这样。

    从技术上讲,这可以通过以下方式完成:

    1)创建文件md5docker,并赋予其执行权限,例如chmod +x md5docker

    #!/bin/sh
    dir=$(dirname "$0")
    docker create $1 | { read cid; docker export $cid | $dir/tarcat | md5; docker rm $cid > /dev/null; }
    

    2)创建文件tarcat,并赋予其执行权限,例如chmod +x tarcat

    #!/usr/bin/env python3
    # coding=utf-8
    
    if __name__ == '__main__':
        import sys
        import tarfile
        with tarfile.open(fileobj=sys.stdin.buffer, mode="r|*") as tar:
            for tarinfo in tar:
                if tarinfo.isfile():
                    print(tarinfo.name, flush=True)
                    with tar.extractfile(tarinfo) as file:
                        sys.stdout.buffer.write(file.read())
                elif tarinfo.isdir():
                    print(tarinfo.name, flush=True)
                elif tarinfo.issym() or tarinfo.islnk():
                    print(tarinfo.name, flush=True)
                    print(tarinfo.linkname, flush=True)
                else:
                    print("\33[0;31mIGNORING:\33[0m ", tarinfo.name, file=sys.stderr)
    

    3)现在调用./md5docker <image>,其中<image>是您的图片名称或ID,以计算图片整个文件系统的MD5哈希值。

    要验证两个图像是否具有相同的内容,只需检查它们的哈希值是否与步骤3中计算的相同。

    请注意,此解决方案仅考虑内容目录结构,常规文件内容和符号链接(软和硬)。如果您还需要更多内容,只需更改tarcat脚本,为您要包含的内容添加更多elif条款测试(请参阅Python's tarfile,并查找与此相对应的方法TarInfo.isXXX()需要的内容)。

    我在这个解决方案中看到的唯一限制是它对Python的依赖(我使用Python3,但它应该很容易适应Python2)。一个没有任何依赖的更好的解决方案,可能更快(嘿,这已经非常快),是用支持静态链接的语言编写tarcat脚本,这样一个独立的可执行文件就足够了(即,一个不需要任何外部依赖,但唯一的OS)。我把这作为C,Rust,OCaml,Haskell的未来练习,你选择。

    注意,如果MD5不符合您的需求,只需使用您的哈希实用程序替换第一个脚本中的md5

    希望这有助于任何人阅读。

答案 2 :(得分:1)

似乎没有一种标准的方法可以做到这一点。我能想到的最好的方法是使用Docker多级构建功能。 例如,我在这里比较apline和debian图像。在您的情况下,将图像名称设置为您要比较的图像名称

我基本上将每个图像中的所有文件复制到git存储库中,并在每次复制后提交。

FROM alpine as image1

FROM debian as image2

FROM ubuntu
RUN apt-get update && apt-get install -y git
RUN git config --global user.email "you@example.com" &&\
 git config --global user.name "Your Name"

RUN mkdir images
WORKDIR images
RUN git init

COPY --from=image1 / .
RUN git add . && git commit -m "image1"

COPY --from=image2 / .
RUN git add . && git commit -m "image2"

CMD tail > /dev/null

这将为您提供一个带有git存储库的图像,该存储库记录两个图像之间的差异。

docker build -t compare .
docker run -it compare bash

现在,如果您执行git log,您可以看到日志,并且可以使用git diff <commit1> <commit2>

比较两次提交

注意:如果图像构建在第二次提交时失败,这意味着图像是相同的,因为如果没有提交更改,git提交将失败。

答案 3 :(得分:0)

让我惊讶的是,docker并没有开箱即用。这是@mljrg技术的一种变体:

#!/bin/sh

docker create $1 | {
  read cid
  docker export $cid | tar Oxv 2>&1 | shasum -a 256
  docker rm $cid > /dev/null
}

它更短,根本不需要python依赖项或第二个脚本,我敢肯定有缺点,但是它对我完成的一些测试似乎很有效。