如何validation两个Docker镜像的内容是否完全一致?

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

我尝试了图像标识符,但是从相同的Dockerfile和干净的本地存储库构build时,它们有所不同:我通过构build一个映像,清理本地存储库,然后触摸其中一个文件来更改其修改date,然后构build第二个图像,和他们的图像id不匹配。 我使用了Docker 17.06(我相信是最新版本)。

谢谢

经过一番研究,我想出了一个解决scheme,这个解决scheme在我的testing中是快速和干净

整体解决scheme是这样的:

  1. 通过docker create ...创build一个容器为您的图像docker create ...
  2. 通过docker export ...将其整个文件系统导出到tar归档文件中docker export ...
  3. 将存档目录名称,符号链接名称,符号链接内容,文件名称和文件内容pipe理到散列函数(例如MD5)
  4. 比较不同图像的散列值,以validation它们的内容是否相等

就是这样。

从技术上讲,可以这样做:

1)创build文件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)创buildtarcat文件,赋予它执行权限,例如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散列值。

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

请注意,此解决scheme仅考虑内容目录结构,常规文件内容和符号链接(软和硬)。 如果您需要更多,只需要通过添加更多的elif子句来testing您希望包含的内容来更改tarcat脚本(请参阅Python的tarfile ,并查找与所需内容对应的TarInfo.isXXX()方法)。

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

请注意,如果MD5不适合您的需求,只需将第一个脚本中的md5replace为您的哈希实用程序即可。

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

似乎没有这样做的标准方法。 我能想到的最好的方法是使用Docker多阶段构buildfunction。 例如,在这里我比较了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仓库,logging两个图像之间的差异。

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

现在,如果你做了一个git log你可以看到日志,你可以使用git diff <commit1> <commit2>来比较两个提交

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

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

docker inspect redis

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

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