Dockerで依存する子イメージのリストを取得するにはどうすればよいですか?


123

画像を削除しようとすると、次のエラーが発生します。

# 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バージョンです:

# 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の実行中または停止中のコンテナはありません。


9
なぜDockerチームはこれを行うためのネイティブな方法を提供できないのか疑問に思っていますか?
アマルゴビナス2018

回答:


54

短い答え: 依存するDockerイメージをリストするpython3スクリプトは次のとおりです。

長い答え: 問題の画像の後に作成されたすべての画像の画像IDと親IDは、次のように表示できます。

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

親IDがf50f9524513fで始まる画像を検索してから、それらの子画像などを検索できるはずです。 しかし、そうで .Parent はありません。なので、ほとんどの場合docker images --all、それを機能させるために上記を指定する必要があります。そうすると、すべての中間レイヤーの画像IDも取得されます。

以下は、Docker出力を解析し、検索を行って画像のリストを生成する、より限定的なpython3スクリプトです。

#!/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 )

または、上記の要点を使用して、同じことを行います。


2
どれも期待文字で始まっていない場合はどうなりますか?これはバグの可能性を示していますか?私はDocker for Macベータ版、FWIWを使用しているので、驚かないでしょう。
neverfox

これはバグか、問題の画像に子がないことを意味します。
Aryeh Leib Taurog

2
これは本当に元の質問に答えるものではありません。これは、問題の画像の後に作成されたものを示します。これは、ポスターが削除しようとした画像に依存する場合としない場合があります。Simon Bradyの答えは、画像のサンプルサイズが少なくとも小さい場合に役立ちます。
ペンギンコーダー2017

2
@penguincoderは、Pythonスクリプトの目的です。
Aryeh Leib Taurog 2017

@neverfoxのように、この答えは私にはうまくいきませんでした。ただし、以下のSimon Bradyの回答は機能しました。
マーク

91

画像が大量にない場合、ブルートフォースアプローチが常に存在します。

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

1
これが「最良の」ソリューションだと思います。これを少し拡張して、何が何であるかをよりecho $1醜いものに変更することで、より明確にすることができます(ただし、ブルートフォーシーです)docker images | grep $i(Docker バージョンで--filterは、イメージIDのフラグを使用するよりも移植性が高くなります)
Jon V

15

dockvizをインストールし、ツリービューのイメージIDからブランチをたどります。

go get github.com/justone/dockviz
$(go env GOPATH)/bin/dockviz images --tree -l

sudo apt-get update ; sudo apt-get install golang-go; export GOPATH=$HOME/.go最初に行うことをお勧めします。
loretoparisi 2017

3
macOSで利用可能brew install dockviz
rcoup

Ubuntuを使用する場合は注意が必要です。通常、goの古いリポジトリを使用しています
Qohelet

7

誰もがbashソリューションに興味があれば、Dockerイメージの子孫ツリーを出力するシェルスクリプトの要旨を作成しました。

#!/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" ""

このリンクで質問に答えることができますが、回答の重要な部分をここに含め、参照用のリンクを提供することをお勧めします。リンクされたページが変更されると、リンクのみの回答が無効になる可能性があります。- レビューから
フアンクルスソレール

私はあきらめたので、私はちょうど、この日行うためのおかげでトラブルコードをフォーマットしていた
ミハルLinhard

2

これは、最終的な「イメージ」を保持するために行ったものです(レイヤー、本当に-これは、Dockerビルドを開始しているので、私を捨てたものです)。

「...強制できません...」というメッセージ全体が表示されていました。「docker commit」で作成された独立したイメージではないため、不要なイメージを削除できないことに気付きました。私の問題は、ベースイメージとファイナルの間にいくつかのイメージ(またはレイヤー)があり、クリーンアップしようとしたところ、子と親に関するエラー/警告が発生したことです。

  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

良い答えですが、ロードは「docker save」から作成されたイメージでのみ使用されることになっています。「
docker

2

slushyMichael Hoffmanの回答に基づいて、大量の画像がない場合は、次のシェル関数を使用できます。

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]++'

2

以下は、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で要旨として利用できるようにしました


1

親イメージに依存する子イメージのリストを取得する簡単な方法を次に示します。

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ですが、「画像には依存する子画像があります」と表示されています。これはabcdefghijkl、がに依存している子であることを示してい123456789012ます。最初docker rmi abcdefghijklに必要なのは、次にできますdocker rmi 123456789012

現在、依存する子画像のチェーンがある可能性があるため、最後の子を見つけるために繰り返し続ける必要がある場合があります。


0

Dockerの以下のディレクトリを介して、親子関係に関係なくDockerイメージを削除できます

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

このディレクトリにはDockerイメージがあり、必要なものを削除できます。


私はdocker APIを使用してポータブルコマンドを作成しようとしています。これは、デバイスマッパーとdockerエンジン(たとえば、docker swarmとは異なります)がこれを非ポータブルソリューションにすることを前提としています。他のプロセス(dockerデーモンを含む)がファイルシステムを使用しているときに、ファイルシステム内のファイルを削除することも危険です。
nicocesar 2016

macosのどこにありますか?
アンソニーコング

1
*警告 "これにより、将来的にコンテナの削除とプルで複数のエラーが発生する可能性があります/var/lib/docker
。dirsを

0

どうですか:

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)

子画像のIDをsha256:プレフィックス付きで出力します。
名前を追加する次のものも持っていました:

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

  • ID= 画像の完全なIDを取得します
  • IMAGES= この画像がリストされているすべての子画像を取得します Image
  • echo... 重複を削除し、結果をエコーし​​ます

私はGo形式の条件文が好きですが、このユースケースのフィルターとしてはより良いでしょう。
ingyhere

0

私はこれを作り直して、子供とそのrepoタグを再帰的に見つけ、彼らがしていることを印刷します:

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- *を削除することを忘れないでください。


-6

私も同じ問題に直面していました。問題を解決するための以下の手順は許可されていません。

実行中のすべてのコンテナを停止します

docker stop $(docker ps -aq) すべてのコンテナーを削除する

docker rm $(docker ps -aq) すべての画像を削除

docker rmi $(docker images -q)


この回答は質問者の要件を満たしていません。
Ankur Loriya

人々が潜在的にコピー&ペーストして有害なことをする可能性のあるものへのコメントを停止してください。
nicocesar 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.