如何在 Docker 中获得相关子图像的列表?

我试图移除一个图像,我得到:

# docker rmi f50f9524513f
Failed to remove image (f50f9524513f): Error response from daemon: conflict: unable to delete f50f9524513f (cannot be forced) - image has dependent child images

这是码头版本:

# docker version
Client:
Version:      1.10.3
API version:  1.22
Go version:   go1.5.3
Git commit:   20f81dd
Built:        Thu Mar 10 21:49:11 2016
OS/Arch:      linux/amd64


Server:
Version:      1.10.3
API version:  1.22
Go version:   go1.5.3
Git commit:   20f81dd
Built:        Thu Mar 10 21:49:11 2016
OS/Arch:      linux/amd64

但没有额外的信息:

# docker images --format="raw" | grep f50f9524513f -C3


repository: debian
tag: 8
image_id: f50f9524513f
created_at: 2016-03-01 18:51:14 +0000 UTC
virtual_size: 125.1 MB


repository: debian
tag: jessie
image_id: f50f9524513f
created_at: 2016-03-01 18:51:14 +0000 UTC
virtual_size: 125.1 MB

我怎样才能得到它声称拥有的 依赖性儿童图像

没有正在运行或已停止的具有该映像 ID 的容器。

109425 次浏览

简短的回答: 下面是一个 python3脚本 ,它列出了相关的 docker 映像。

长话短说: 您可以通过以下方法查看在有问题的图像之后创建的所有图像的图像 id 和父 ID:

docker inspect --format='\{\{.Id}} \{\{.Parent}}' \
$(docker images --filter since=f50f9524513f --quiet)

您应该能够查找以 f50f9524513f 开头的父 id 图像,然后查找 那些的子图像,等等。但是 .Parent 不是你想的那样。,所以在大多数情况下,您需要指定上面的 docker images --all使其工作,然后您将获得所有中间层的图像 ID 以及。

下面是一个更有限的 python3脚本,用于解析 docker 输出并进行搜索以生成图像列表:

#!/usr/bin/python3
import sys


def desc(image_ids, links):
if links:
link, *tail = links
if len(link) > 1:
image_id, parent_id = link
checkid = lambda i: parent_id.startswith(i)
if any(map(checkid, image_ids)):
return desc(image_ids | {image_id}, tail)
return desc(image_ids, tail)
return image_ids




def gen_links(lines):
parseid = lambda s: s.replace('sha256:', '')
for line in reversed(list(lines)):
yield list(map(parseid, line.split()))




if __name__ == '__main__':
image_ids = {sys.argv[1]}
links = gen_links(sys.stdin.readlines())
trunc = lambda s: s[:12]
print('\n'.join(map(trunc, desc(image_ids, links))))

如果将其保存为 desc.py,则可以按以下方式调用它:

docker images \
| fgrep -f <(docker inspect --format='\{\{.Id}} \{\{.Parent}}' \
$(docker images --all --quiet) \
| python3 desc.py f50f9524513f )

或者使用 以上要点,它也可以做同样的事情。

如果你没有大量的图片,总是可以使用暴力的方法:

for i in $(docker images -q)
do
docker history $i | grep -q f50f9524513f && echo $i
done | sort -u

您可以通过下面的 Docker 目录删除 Docker 图像,而不管其父子关系如何

/var/lib/docker/image/devicemapper/imagedb/content/sha256

在这个目录中,您可以找到 Docker 图像,因此您可以删除您想要的内容。

安装 Dockviz并跟随树视图中图像 id 中的分支:

dockviz images --tree -l

这是我为了保存我最后的“图像”(层,真的-这是什么抛出了我,因为我正在进入码头构建)。

我收到了“ ... 不能强迫...”的信息。我意识到我不能删除我不需要的图像,因为它们不是真正独立的图像创建的’停靠提交’。我的问题是,我有几个图像(或图层)之间的基础图像和我的最终,只是试图清理是我遇到的错误/警告有关的子女和父母。

  1. 我将最终的图像(或图层,如果您愿意的话)导出到一个 tarball 中。
  2. 然后,我删除了所有我想要的图片,包括我的期末考试-我把它保存到一个 tarball 中,所以,虽然我不确定我是否能够使用它,我只是在试验。
  3. 然后我运行 docker image load -i FinalImage.tar.gz,输出如下:

7d9b54235881: Loading layer [==================================================>]  167.1MB/167.1MB
c044b7095786: Loading layer [==================================================>]  20.89MB/20.89MB
fe94dbd0255e: Loading layer [==================================================>]  42.05MB/42.05MB
19abaa1dc0d4: Loading layer [==================================================>]  37.96MB/37.96MB
4865d7b6fdb2: Loading layer [==================================================>]  169.6MB/169.6MB
a0c115c7b87c: Loading layer [==================================================>]    132MB/132MB

加载的图像 ID: sha256:82d4f8ef9ea1eab72d989455728762ed3c0fe35fd85acf9edc47b41dacfd6382

现在,当我使用“ docker image ls”列表时,我只有原始的基础映像,以及之前保存到 tarball 中的最后一个映像。

[root@docker1 ~]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
httpd               import              82d4f8ef9ea1        3 days ago          747MB
centos              httpd               36540f359ca3        5 weeks ago         193MB

我的系统现在是“干净的”。我只有我想要的图像。 我甚至毫无问题地删除了基础图像。

[root@docker1 ~]# docker rmi 36540f359ca3
Untagged: centos:httpd
Untagged:     centos@sha256:c1010e2fe2b635822d99a096b1f4184becf5d1c98707cbccae00be663a9b9131
Deleted: sha256:36540f359ca3b021d4b6a37815e9177b6c2bb3817598979ea55aee7ecc5c2c1f

我已经创建了一个带 shell 脚本的 大意来打印一个 docker 映像的后代树,如果有人对 bash 解决方案感兴趣的话:

#!/bin/bash
parent_short_id=$1
parent_id=`docker inspect --format '\{\{.Id}}' $1`


get_kids() {
local parent_id=$1
docker inspect --format='ID \{\{.Id}} PAR \{\{.Parent}}' $(docker images -a -q) | grep "PAR ${parent_id}" | sed -E "s/ID ([^ ]*) PAR ([^ ]*)/\1/g"
}


print_kids() {
local parent_id=$1
local prefix=$2
local tags=`docker inspect --format='\{\{.RepoTags}}' ${parent_id}`
echo "${prefix}${parent_id} ${tags}"


local children=`get_kids "${parent_id}"`


for c in $children;
do
print_kids "$c" "$prefix  "
done
}


print_kids "$parent_id" ""

我也面临着同样的问题。下面的步骤可以解决这个问题。

停止所有正在运行的容器

码头停靠站 $(码头停靠站 ps-aq) 移走所有容器

码头工人 $(码头工人) 删除所有图像

Docker rmi $(docker images-q)

这个怎么样:

ID=$(docker inspect --format="\{\{.Id}}" "$1")
IMAGES=$(docker inspect --format="\{\{if eq \"$ID\" .Config.Image}}\{\{.Id}}\{\{end}}" $(docker images --filter since="$ID" -q))
echo $(printf "%s\n" "${IMAGES[@]}" | sort -u)

它将打印具有 sha256:前缀的子图像 ID。
我还有以下附加的名字:

IMAGES=$(docker inspect --format="\{\{if eq \"$ID\" .Config.Image}}\{\{.Id}}\{\{.RepoTags}}\{\{end}}" $(docker images --filter since="$ID" -q))

  • 获取图像的完整 id
  • 获取将此图像列为 Image的所有子图像
  • 删除重复并回显结果

我做了这个来递归查找孩子,他们的回购标签,并打印他们在做什么:

docker_img_tree() {
for i in $(docker image ls -qa) ; do
[ -f "/tmp/dii-$i"  ] || ( docker image inspect $i > /tmp/dii-$i)
if grep -qiE 'Parent.*'$1 /tmp/dii-$i ; then
echo "$2============= $i (par=$1)"
awk '/(Cmd|Repo).*\[/,/\]/' /tmp/dii-$i | sed "s/^/$2/"
docker_img_tree $i $2===
fi
done
}

如果主机不安全,不要忘记删除/tmp/dii-* 。

基于 雪泥Michael Hoffman的答案,如果你没有大量的图片,你可以使用这个 shell 函数:

docker_image_desc() {
for image in $(docker images --quiet --filter "since=${1}"); do
if [ $(docker history --quiet ${image} | grep ${1}) ]; then
docker_image_desc "${image}"
fi
done
echo "${1}"
}

然后称之为使用

docker_image_desc <image-id> | awk '!x[$0]++'

下面是一个基于 Python API (pip install docker)的解决方案,它递归地列出后代及其标记(如果有的话) ,并根据关系的深度(子女、孙辈等)增加缩进:

import argparse
import docker


def find_img(img_idx, id):
try:
return img_idx[id]
except KeyError:
for k, v in img_idx.items():
if k.rsplit(":", 1)[-1].startswith(id):
return v
raise RuntimeError("No image with ID: %s" % id)


def get_children(img_idx):
rval = {}
for img in img_idx.values():
p_id = img.attrs["Parent"]
rval.setdefault(p_id, set()).add(img.id)
return rval


def print_descendants(img_idx, children_map, img_id, indent=0):
children_ids = children_map.get(img_id, [])
for id in children_ids:
child = img_idx[id]
print(" " * indent, id, child.tags)
print_descendants(img_idx, children_map, id, indent=indent+2)


def main(args):
client = docker.from_env()
img_idx = {_.id: _ for _ in client.images.list(all=True)}
img = find_img(img_idx, args.id)
children_map = get_children(img_idx)
print_descendants(img_idx, children_map, img.id)


if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("id", metavar="IMAGE_ID")
main(parser.parse_args())

例如:

$ python find_dep_img.py 549afbf12931
sha256:913d0981fdc7d2d673f2c8135b7afd32ba5037755e89b00432d3460422ba99b9 []
sha256:0748dbc043b96ef9f88265c422e0267807f542e364b7a7fadf371ba5ee082b5d []
sha256:6669414d2a0cc31b241a1fbb00c0ca00fa4dc4fa65dffb532bac90d3943d6a0a []
sha256:a6441e7d9e92511608aad631f9abe8627033de41305c2edf7e03ee36f94f0817 ['foo/bar:latest']

我已经在 https://gist.github.com/simleo/10ad923f9d8a2fa410f7ec2d7e96ad57提供了一个要点

下面是一个获得依赖于父图像的子图像列表的简单方法:

image_id=123456789012


docker images -a -q --filter since=$image_id |
xargs docker inspect --format='\{\{.Id}} \{\{.Parent}}' |
grep $image_id

这将生成一个子/父图像 ID 列表,例如(为简洁起见,截断) :

sha256:abcdefghijkl sha256:123456789012

左边是子图像 ID,右边是我们试图删除的父图像 ID,但它表示“ image 有相关的子图像”。这告诉我们 abcdefghijkl是依赖于 123456789012的孩子。所以我们首先需要 docker rmi abcdefghijkl,然后你可以 docker rmi 123456789012

现在,可能有一连串相关的子图像,因此您可能必须不断重复才能找到最后一个子图像。