如何找到Docker映像的基础映像

lymnna71  于 2023-02-03  发布在  Docker
关注(0)|答案(4)|浏览(218)

我有一个Docker图像,我想找出它是从哪个图像创建的。当然有多个层,但我想找出最后一个图像(在docker文件中的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

这是我收到的错误消息

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".
rekjcdws

rekjcdws1#

简单的方法是使用

docker image history deno

上面的命令将给予如下输出

然后查看IMAGE列,获取刚好位于第一个<missing>上方的映像ID a24bb4013296
那就做
对于Linux

docker image ls | grep a24bb4013296

适用于Windows

docker image ls | findstr a24bb4013296

这将为您提供基础映像名称

50few1ms

50few1ms2#

这些信息实际上并不存在,一个图像包含其父级的图层,但是没有一种简单的方法可以将图层摘要反向转换回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 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

如果我们检查这些图像,并将它们与docker image inspect输出的maven图像中的图层进行比较,我们可以确认openjdkdebian中的图层存在于原始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层的严格子集,因此我们可以得出结论,openjdkdebian映像至少都在maven映像的祖先路径中。
我们可以进一步推断,最后3层最有可能来自maven图像本身(或者,可能是某个未知图像)。

警告,当您本地没有图像时

当然,以上方法之所以有效,是因为我手头正好有所有的图片,所以,你要么需要图片,要么可以通过图层摘要找到它们。
您仍然可以使用Docker Hub等注册中心或您自己的私人存储库中提供的信息来解决这个问题。
对于官方图像,docker-library/repo-info包含官方图像的历史信息,包括过去几年中编目的各种标签的层摘要。例如,您可以将其用作层信息源。
如果你能把它想象成一个图层摘要的数据库,你至少可以推断出这些官方图片的祖先。

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

需要注意的一个重要警告是,当你在本地检查一个图像的层摘要时,你得到的是层的 * 内容 * 摘要。如果你在注册表清单中查看层摘要(就像docker-library/repo-info项目中出现的),你得到的是压缩的 * 分发 * 摘要,并且不能将层摘要与内容进行比较。
因此,您只能比较摘要local <--> localremote <--> remote

示例,使用远程映像

假设我想做同样的事情,但是我想关联远程存储库中的图像并找到它的基,我们可以通过查看远程清单中的层来做同样的事情。
您可以找到如何针对特定注册表执行此操作的参考,如this answer for dockerhub中所述。
使用上例中的相同图像,我们会发现 * distribution * 层摘要也以相同的方式匹配。

$ 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图像的此属性来确定从中派生图像的基础图像。

twh00eeo

twh00eeo3#

您可以使用此答案中建议的方法:https://stackoverflow.com/a/53841690/3691891
首先,拉动chenzj/dfimage

docker pull chenzj/dfimage

获取映像的ID:

docker images | grep <IMAGE_NAME> | awk '{print $3}'

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

docker run -v /var/run/docker.sock:/var/run/docker.sock --rm chenzj/dfimage <IMAGE_ID>

如果您觉得这太难,只需提取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"

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

$ ./docker-get-dockerfile.sh alpine
FROM alpine:latest
ADD file:fe64057fbb83dccb960efabbf1cd8777920ef279a7fa8dbca0a8801c651bdf7c in /
CMD ["/bin/sh"]
s3fp2yjn

s3fp2yjn4#

docker run image:tag cat /etc/*release*

用上面的命令从那个图像运行一个docker容器(用你的图像名称和标签改变“image:tag”)。你的容器将打印你需要回答你的问题的细节。

相关问题