这些信息实际上并不存在。镜像包含其父级的层,但是很难通过反向层摘要来还原 FROM
指令,除非你恰好拥有(或能够找到)包含这些层的镜像。
如果你手头有父镜像(或者能够找到它们),你可以通过对比层推断出你的镜像用于其 FROM
指令的镜像(或祖先)。
理论示例
假设你的镜像 FOO
包含层 1 2 3 4 5 6
。如果你的系统中有另一个镜像 BAR
包含层 1 2 3
,那么你可以推断出镜像 BAR
是镜像 FOO
的祖先--也就是说,在其层次结构中的某个时刻使用了 FROM BAR
。
进一步假设你有另一个镜像 BAZ
,其中包含层 1 2 3 4 5
。你可以推断出镜像 BAZ
具有镜像 BAR
在其祖先中,并且镜像 FOO
继承自镜像 BAZ
(因此间接继承自 BAR
)。
从这些信息中,你可以推断出这些镜像的 Dockerfile 大致如下:
FROM scratch
COPY ./one /
COPY ./two /
COPY ./three /
FROM BAR
RUN echo "this makes layer 4" > /four
RUN echo "this makes layer 5" > /five
FROM BAZ
RUN echo "this makes layer 6" > /six
通过查看每个镜像的 docker image history
命令,您可以获得确切的命令。
但是,请记住 Docker 标签是可变的;维护人员会创建新镜像并将标签移动到这些镜像上。因此,如果您今天使用 FROM python:3.8.1
构建了一个镜像,则它不会包含与几周前使用相同的 FROM
行构建镜像时相同的层。您需要 SHA256 摘要以确保您使用的是完全相同的镜像。
实际例子,本地镜像
现在我们了解了识别镜像及其基础的理论知识,让我们通过一个实际例子来实践一下。
注意:由于我使用的标签会随时间而变化(参见上述关于标签可变性的说明),因此我将使用 SHA256 摘要来拉取图像,以便可以由此答案的观众再现它。
假设我们有一个特定的镜像,我们想找到它的基础镜像。我们将在此处使用官方的 maven
镜像。
首先,我们将查看其层次结构。
IMAGE="docker.io/maven@sha256:55f1c145a04e01706233d68fe0b6b20bf76f765ab32f3fe6e29c8ef933917af6"
docker pull $IMAGE
docker image inspect $IMAGE | jq -r '.[].RootFS.Layers[]'
这将输出图层:
sha256:6e06900bc10223217b4c78081a857866f674c462e4f90593b01894da56df336d
sha256:eda2f4da9b1e70500ac340d40ee039ef3877e8be13b9a24cd345406bf6693412
sha256:6bdb7b3c3e226bdfaa911ba72a95fca13c3979cd150061d570cf569e93037ce6
sha256:ce217e530345060ca0973807a3288560e1e15cf1a4eeec44d6aa594a926c92dc
sha256:f256c980a7d17a00f57fd42a19f6323fcc2341fa46eba128def04824cafa5afa
sha256:446b1af848de2dcb92bbd229ca6ecaabf2f48dab323c19f90d02622e09a8fa67
sha256:10652cf89eaeb5b5d8e0875a6b1867b5cf92c509a9555d3f57d87fab605115a3
sha256:d9a4cf86bf01eb170242ca3b0ce456159fd3fddc9c4d4256208a9d19bae096ca
现在,我们可以尝试查找具有这些层的(严格)子集的其他图像。假设你手头上已经有这些图像,你可以通过交叉引用磁盘上已有的图像的层来找到它们,例如使用docker image inspect
。
在这种情况下,我恰巧知道这些图像是什么,并且已经拥有了它们(如果你没有这些图像,稍后我将讨论可能需要采取的步骤),因此我们将拉取这些图像并查看这些层。
如果您想跟随操作:
OPENJDK='docker.io/openjdk@sha256:fe6a46a26ff7d6c31b258e07b3d53f0c42fe68f55f646cc39d60d0b17cbc827b'
DEBIAN='docker.io/debian@sha256:088be7d6017ad3ae98325f47707112e1f61687c371be1865e55d5e5531ca97fd'
docker pull $OPENJDK
docker pull $DEBIAN
如果我们检查这些镜像并将它们与使用
docker image inspect
命令查看
maven
镜像的输出中看到的层进行比较,我们可以确认
openjdk
和
debian
的层存在于我们原始的
maven
镜像中。
$ docker image inspect $DEBIAN | jq -r '.[].RootFS.Layers[]'
sha256:6e06900bc10223217b4c78081a857866f674c462e4f90593b01894da56df336d
$ docker image inspect $OPENJDK | jq -r '.[].RootFS.Layers[]'
sha256:6e06900bc10223217b4c78081a857866f674c462e4f90593b01894da56df336d
sha256:eda2f4da9b1e70500ac340d40ee039ef3877e8be13b9a24cd345406bf6693412
sha256:6bdb7b3c3e226bdfaa911ba72a95fca13c3979cd150061d570cf569e93037ce6
sha256:ce217e530345060ca0973807a3288560e1e15cf1a4eeec44d6aa594a926c92dc
如前所述,由于这5层是maven镜像的8层严格子集,因此我们可以得出结论:openjdk
和debian
镜像至少都在maven
镜像的祖先路径中。
我们还可以推断出,最后3层很可能来自maven
镜像本身(或者可能来自某个未知的镜像)。
注意事项:当您没有本地镜像时
当然,上述内容仅适用于我手头恰好有所有镜像的情况。因此,您需要拥有这些镜像或能够通过层摘要定位它们。
对于像Docker Hub或您自己的私有存储库之类的注册表中可能可用的信息,您仍然可以通过该信息找出答案。
对于官方镜像,docker-library/repo-info 包含了关于官方镜像的历史信息,包括目录中各种标记的层摘要。例如,您可以将其用作层信息源。
如果您将其想象为层摘要数据库,则至少可以推断出这些官方镜像的祖先。
“分发”(远程)摘要与“内容”(本地)摘要
需要注意的一个重要细节是,当您在本地检查图像以获取其层摘要时,您会得到层的内容摘要。如果您在注册表清单中查看层摘要(例如出现在docker-library/repo-info项目中),则会获得压缩的分发摘要,并且无法将层摘要与内容进行比较。
因此,您只能进行local <--> local
OR remote <--> remote
的摘要比较。
示例:使用远程镜像
假设我想执行相同的操作,但我想将远程仓库中的映像与其基础关联起来。我们可以通过查看远程清单中的层来完成相同的操作。
您可以找到有关如何为您特定的注册表执行此操作的参考,如此答案中对dockerhub的描述所述。
使用上述示例中的相同镜像,我们将发现分发层摘要也以相同的方式匹配。
$ get-remote-layers $IMAGE
sha256:6fcf2156bc23db75595b822b865fbc962ed6f4521dec8cae509e66742a6a5ad3
sha256:96fde6667c188c81fcddee021ccbb3e054ebe83350fd4609e17a3d37f0ec7f9d
sha256:74d17759dd2a1b51afc740fadd96f655260689a2087308e40d1865a0098c5fae
sha256:bbe8ebb5d0a64d265558901c7c6c66e1d09f664da57cdb2e5f69ba52a7109d31
sha256:b2edaadd7dd62cfe7f551b902244ee67b84bc5c0b6538b9480ac9ca97a0a4986
sha256:0fca65d33e353bdfdd5edd8d4c8ab5efde52c078bd25e2dcf454f995e5420725
sha256:d6d771d0512387eee1e419a965b929a9a3b0365cf1935b3719d60bf9feffcf63
sha256:dee8cd26669373102db07820072127c46bbfdad340a586ee9dfe60ae933eac2b
$ get-remote-layers $DEBIAN
sha256:6fcf2156bc23db75595b822b865fbc962ed6f4521dec8cae509e66742a6a5ad3
$ get-remote-layers $OPENJDK
sha256:6fcf2156bc23db75595b822b865fbc962ed6f4521dec8cae509e66742a6a5ad3
sha256:96fde6667c188c81fcddee021ccbb3e054ebe83350fd4609e17a3d37f0ec7f9d
sha256:74d17759dd2a1b51afc740fadd96f655260689a2087308e40d1865a0098c5fae
sha256:bbe8ebb5d0a64d265558901c7c6c66e1d09f664da57cdb2e5f69ba52a7109d31
在仓库中使用分发摘要有个限制,就是你只能比较相同清单模式版本的摘要。所以,如果一个镜像是使用清单v1推送的,那么再次使用清单v2推送时它将具有不同的摘要。
太长不想读?
镜像包含其祖先镜像的层。因此,如果镜像A包含镜像B的一个严格子集,那么你知道镜像B是镜像A的后代。
你可以利用Docker镜像的这个属性来确定你的镜像从哪些基础镜像派生而来。