确切地说,这些信息并不真正存在。图像将包含其父级的图层,但没有简单方法可以将图层摘要反转回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 的信息可能如下所示:
# Dockerfile of image BAR
FROM scratch
# layers 1 2 and 3
COPY ./one /
COPY ./two /
COPY ./three /
# Dockerfile of Image BAZ
FROM BAR
RUN echo "this makes layer 4" > /four
RUN echo "this makes layer 5" > /five
# Dockerfile of image FOO
FROM BAZ
RUN echo "this makes layer 6" > /six
您可以通过查看每张图片的 docker image history 来获得确切的命令。
这里要记住的重要一点是,docker 标签是可变的;维护人员制作新图像并将标签移动到这些图像。因此,如果您今天使用FROM python:3.8.1 构建了一个图像,它不会包含与几周前使用相同的FROM 行构建的图像相同的层。您需要 SHA256 摘要以确保您使用的是完全相同相同的图像。
实际示例,本地图像
现在我们了解了识别图像及其基础背后的理论,让我们通过一个真实的示例来实践它。
注意:因为我使用的标签会随着时间而改变(参见上面的 RE:标签可变性),我将使用 SHA256 摘要来提取此示例中的图像,以便此答案的查看者可以复制它。
假设我们有一个特定的图像,我们想找到它的基础。我们将在这里使用官方的maven 图片。
首先,我们来看看它的层次。
# maven:3.6-jdk-11-slim at time of writing, on my platform
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:11.0.10-jdk-slim at time of writing, on my platform
OPENJDK='docker.io/openjdk@sha256:fe6a46a26ff7d6c31b258e07b3d53f0c42fe68f55f646cc39d60d0b17cbc827b'
# debian:buster-20210329-slim at time of writing on my platform
DEBIAN='docker.io/debian@sha256:088be7d6017ad3ae98325f47707112e1f61687c371be1865e55d5e5531ca97fd'
docker pull $OPENJDK
docker pull $DEBIAN
如果我们检查这些图像并将它们与我们在maven 图像的docker image inspect 的输出中看到的层进行比较,我们可以确认来自openjdk 和debian 的层存在于我们的原始@ 987654355@图片。
$ 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 项目中显示的内容),您将获得压缩的 distribution 摘要,并且无法比较层摘要有内容。
因此您可以比较摘要 local <--> local OR remote <--> remote。
示例,使用远程图像
假设我想做同样的事情,但我想在远程存储库中关联图像并找到它的基础。我们可以通过查看远程清单中的层来做同样的事情。
您可以找到参考如何为您的特定注册表执行此操作,如 this answer for 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
关于存储库中分发摘要的另一个警告是,您只能比较相同 manifest schema version 的摘要。因此,如果图像是使用 manifest v1 推送的,则不会再使用 manifest v2 推送相同的摘要。
TL;DR
图像包含其祖先图像的层。因此,如果图像 A 包含图像 B 层的严格子集,则您知道图像 B 是图像 A 的后代。
您可以使用 Docker 映像的此属性来确定派生映像的基础映像。