如何找出 docker 镜像的基础镜像

HHH*_*HHH 26 docker

我有一个 docker 镜像,我想知道它是从哪个镜像创建的。当然有多个层,但我想找出最后一个图像(该图像的dockerfile中的FROM语句)?

我尝试使用docker image historydocker image inspect但在那里找不到此信息。

我尝试使用以下命令,但它给了我一条错误消息

alias dfimage="sudo docker run -v /var/run/docker.sock:/var/run/docker.sock --rm xyz/mm:9e945ff"
dfimage febae8978318
Run Code Online (Sandbox Code Playgroud)

这是我收到的错误消息

container_linux.go:235: starting container process caused "exec: \"febae8978318\": executable file not found in $PATH"
/usr/bin/docker-current: Error response from daemon: oci runtime error: container_linux.go:235: starting container process caused "exec: \"febae8978318\": executable file not found in $PATH".
Run Code Online (Sandbox Code Playgroud)

syt*_*ech 21

确切地说,这些信息实际上并不存在。图像将包含其父级的图层,但没有简单的方法可以将图层摘要反转回语句FROM,除非您碰巧拥有(或能够找出)包含这些图层的图像。

如果您手头有父图像(或可以找到它们),则可以通过交叉引用图层来推断您的图像用于其 FROM 语句(或祖先)的图像。

理论例子

假设您的图像FOO包含图层1 2 3 4 5 6BAR如果您的系统上有另一个包含图层的图像1 2 3,您可以推断该图像BAR是图像的祖先FOO- IE,该图像将在其层次结构中的某个点FROM BAR使用。

进一步假设您有另一个图像,BAZ其中包含图层1 2 3 4 5。您可以推断该 image在其祖先中BAZ具有 image并且该 image继承自 image (因此间接继承自)。BARFOOBAZBAR

由此,您可以推断出这些图像的 dockerfile 的信息可能如下所示:

# Dockerfile of image BAR
FROM scratch
# layers 1 2 and 3
COPY ./one /
COPY ./two /
COPY ./three /
Run Code Online (Sandbox Code Playgroud)
# Dockerfile of Image BAZ
FROM BAR
RUN echo "this makes layer 4" > /four
RUN echo "this makes layer 5" > /five
Run Code Online (Sandbox Code Playgroud)
# Dockerfile of image FOO
FROM BAZ
RUN echo "this makes layer 6" > /six
Run Code Online (Sandbox Code Playgroud)

您可以通过查看docker image history每个图像来获取确切的命令。

然而,这里要记住的一件重要的事情是 docker 标签是可变的;维护人员制作新图像并将标签移至这些图像。因此,如果您FROM python:3.8.1今天构建了一个图像,它将不会包含与FROM几周前使用同一行构建的图像相同的图层。您需要 SHA256 摘要来确保您使用的是完全相同的图像。

实际示例,本地图像

现在我们已经了解了识别图像及其基础背后的理论,让我们用一个现实世界的例子来实践它。

注意:因为我使用的标签会随着时间的推移而改变(请参阅上面的 RE:标签可变性),所以我将使用 SHA256 摘要来提取本示例中的图像,以便本答案的查看者可以复制它。

假设我们有一个特定的图像,我们想要找到它的基础。我们将在这里使用官方maven图片。

首先,我们来看看它的层次。

# Dockerfile of image BAR
FROM scratch
# layers 1 2 and 3
COPY ./one /
COPY ./two /
COPY ./three /
Run Code Online (Sandbox Code Playgroud)

这将输出层:

sha256:6e06900bc10223217b4c78081a857866f674c462e4f90593b01894da56df336d
sha256:eda2f4da9b1e70500ac340d40ee039ef3877e8be13b9a24cd345406bf6693412
sha256:6bdb7b3c3e226bdfaa911ba72a95fca13c3979cd150061d570cf569e93037ce6
sha256:ce217e530345060ca0973807a3288560e1e15cf1a4eeec44d6aa594a926c92dc
sha256:f256c980a7d17a00f57fd42a19f6323fcc2341fa46eba128def04824cafa5afa
sha256:446b1af848de2dcb92bbd229ca6ecaabf2f48dab323c19f90d02622e09a8fa67
sha256:10652cf89eaeb5b5d8e0875a6b1867b5cf92c509a9555d3f57d87fab605115a3
sha256:d9a4cf86bf01eb170242ca3b0ce456159fd3fddc9c4d4256208a9d19bae096ca
Run Code Online (Sandbox Code Playgroud)

现在,从这里,我们可以尝试找到具有这些层的(严格)子集的其他图像。假设您手头docker image inspect图像,您可以通过交叉引用磁盘上的图像层来找到它们,例如使用.

在这种情况下,我只是碰巧知道这些图像是什么并且手头有它们(稍后我将讨论如果你手头没有图像你可能会做什么),所以我们将继续提取这些图像图像并查看图层。

如果您想跟随:

# Dockerfile of Image BAZ
FROM BAR
RUN echo "this makes layer 4" > /four
RUN echo "this makes layer 5" > /five
Run Code Online (Sandbox Code Playgroud)

docker image inspect如果我们检查这些图像并将它们与我们在图像输出中看到的图层进行比较,我们可以确认原始图像中存在的maven图层。openjdkdebianmaven

# Dockerfile of image FOO
FROM BAZ
RUN echo "this makes layer 6" > /six
Run Code Online (Sandbox Code Playgroud)

如前所述,因为这 5 层是 Maven 图像的 8 层的严格子集,所以我们可以得出结论openjdkdebian图像至少都在maven图像的祖先路径中。

我们可以进一步推断,最后 3 层很可能来自maven图像本身(或者可能来自某些未知图像)。

当您本地没有图像时的注意事项

现在,当然,上述方法之所以有效,是因为我手头恰好有所有图像。因此,您要么需要图像,要么能够通过图层摘要找到它们。

您仍然可以使用 Docker Hub 等注册表或您自己的私有存储库中提供的信息来解决这个问题。

对于官方镜像,docker-library/repo-info包含有关官方镜像的历史信息,包括过去几年编目的各种标签的层摘要。例如,您可以使用它作为图层信息的来源。

如果您可以将其想象为层摘要数据库,那么您至少可以推断出这些官方图像的祖先。

“分发”(远程)摘要与“内容”(本地)摘要

需要注意的一个重要警告是,当您在本地检查图像的图层摘要时,您将获得图层的内容摘要。如果您正在查看注册表清单中的层摘要(如 docker-library/repo-info 项目中出现的内容),您将获得压缩的分发摘要,并且无法将层摘要与内容进行比较。

所以你只能比较摘要local <--> local 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
Run Code Online (Sandbox Code Playgroud)

关于存储库中的分发摘要的另一项警告是,您只能比较相同清单模式版本的摘要。因此,如果使用清单 v1 推送图像,则不会使用清单 v2 再次推送相同的摘要。

长话短说

图像包含其祖先图像的图层。因此,如果图像 A 包含图像 B 层的严格子集,则您知道图像 B 是图像 A 的后代。

您可以使用 Docker 映像的此属性来确定派生映像的基础映像。


Das*_*kar 13

简单的方法是使用

docker image history deno
Run Code Online (Sandbox Code Playgroud)

上面的命令会给你这样的输出

在此处输入图片说明

然后只需查看 IMAGE 列并获取a24bb4013296位于第一个上方的图像 ID<missing>

然后就做

对于 Linux

docker image ls | grep a24bb4013296
Run Code Online (Sandbox Code Playgroud)

对于 Windows

docker image ls | findstr a24bb4013296
Run Code Online (Sandbox Code Playgroud)

这将为您提供基本图像名称

在此处输入图片说明

  • 我认为要实现这一点,您需要自己构建图像。至少在 docker 1.10 之后,这些是从存储库拉取镜像时不会得到的中间层。请参阅/sf/answers/2471880421/ (10认同)
  • 是的,我刚刚尝试过,它全部显示为丢失 (3认同)
  • 为什么我在 IMAGE 列中看到缺失,如下所示: &lt;missing&gt; 9 个月前 (2认同)

Ark*_*zyk 9

您可以使用此答案中建议的方法:https : //stackoverflow.com/a/53841690/3691891

首先,拉chenzj/dfimage

docker pull chenzj/dfimage
Run Code Online (Sandbox Code Playgroud)

获取图像的 ID:

docker images | grep <IMAGE_NAME> | awk '{print $3}'
Run Code Online (Sandbox Code Playgroud)

替换<IMAGE_NAME>为您的图像名称。使用此 ID 作为参数来chenzj/dfimage

docker run -v /var/run/docker.sock:/var/run/docker.sock --rm chenzj/dfimage <IMAGE_ID>
Run Code Online (Sandbox Code Playgroud)

如果您觉得这太难了,只需拉取chenzj/dfimage图像,然后使用以下docker-get-dockerfile.sh脚本:

#!/usr/bin/env sh

if [ "$#" -lt 1 ]
then
    printf "Image name needed\n" >&2
    exit 1
fi

image_id="$(docker images | grep "^$1 " | awk '{print $3}')"
if [ -z "$image_id" ]
then
    printf "Image not found\n" >&2
    exit 2
fi

docker run -v /var/run/docker.sock:/var/run/docker.sock --rm chenzj/dfimage "$image_id"
Run Code Online (Sandbox Code Playgroud)

您需要传递图像名称作为参数。用法示例:

$ ./docker-get-dockerfile.sh alpine
FROM alpine:latest
ADD file:fe64057fbb83dccb960efabbf1cd8777920ef279a7fa8dbca0a8801c651bdf7c in /
CMD ["/bin/sh"]
Run Code Online (Sandbox Code Playgroud)

  • 这会将相关图像显示为基础图像。 (6认同)
  • 当我这样做时,它显示“FROM”作为我试图找到其基础的图像。我不太明白 - 来自我的形象 - 做了很多事情 - 中提琴,你有我的形象吗? (2认同)