Wie erhalte ich die Liste der abhängigen untergeordneten Bilder in Docker?

121

Ich versuche ein Bild zu entfernen und erhalte:

# 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

Dies ist die Docker-Version:

# 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

Es gibt jedoch keine zusätzlichen Informationen:

# 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

Wie kann ich das bekommen abhängigen Kinderbilder erhalten? es angeblich hat?

Es gibt keine laufenden oder gestoppten Container mit dieser Image-ID.

Nicocesar
quelle
8
Ich muss mich fragen, warum das Docker-Team keine native Möglichkeit bietet, dies zu tun.
Amalgovinus

Antworten:

54

Kurze Antwort: Hier ist ein Python3-Skript , das abhängige Docker-Bilder auflistet.

Lange Antwort: Sie können die Bild-ID und die übergeordnete ID für alle nach dem betreffenden Bild erstellten Bilder wie folgt anzeigen:

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

Sie sollten in der Lage sein, nach Bildern mit der übergeordneten ID zu suchen, die mit f50f9524513f beginnen, und dann nach untergeordneten Bildern von suchen diesen usw. zu . Aber das .Parent ist nicht das, was Sie denken. In den meisten Fällen müssten Sie docker images --alloben angeben , damit dies funktioniert. Dann erhalten Sie auch Bild-IDs für alle Zwischenebenen.

Hier ist ein eingeschränkteres Python3-Skript, mit dem Sie die Docker-Ausgabe analysieren und nach der Liste der Bilder suchen können:

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

Wenn Sie dies speichern, können desc.pySie es wie folgt aufrufen:

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

Oder verwenden Sie einfach das Wesentliche oben , das das Gleiche tut.

Aryeh Leib Taurog
quelle
2
Was ist, wenn keiner von ihnen mit den erwarteten Zeichen beginnt? Zeigt das einen möglichen Fehler an? Ich bin auf Docker für Mac Beta, FWIW, also würde mich das nicht überraschen.
Neverfox
Entweder handelt es sich um einen Fehler, oder es bedeutet, dass das betreffende Bild keine Kinder hat.
Aryeh Leib Taurog
2
Dies beantwortet die ursprüngliche Frage nicht wirklich. Dies zeigt, was nach dem betreffenden Bild erstellt wurde, was möglicherweise von dem Bild abhängt, das das Poster löschen wollte. Die Antwort von Simon Brady reicht aus, zumindest für kleine Stichproben.
Pinguincoder
2
@penguincoder dafür ist das Python-Skript gedacht.
Aryeh Leib Taurog
Wie bei @neverfox hat diese Antwort bei mir nicht funktioniert. Die Antwort von Simon Brady unten hat jedoch funktioniert.
Mark
90

Wenn Sie nicht viele Bilder haben, gibt es immer den Brute-Force-Ansatz:

for i in $(docker images -q)
do
    docker history $i | grep -q f50f9524513f && echo $i
done | sort -u
Simon Brady
quelle
1
Ich denke, das ist die "beste" Lösung. Sie können dies ein wenig erweitern und ein bisschen klarer machen, was echo $1passiert, indem Sie das auf das hässlichere (aber immer noch brutale) ändern docker images | grep $i(tragbarer in Docker-Versionen als die Verwendung von --filterFlags für die Image -ID )
Jon V
15

Installieren Sie dockviz und folgen Sie den Zweigen der Image-ID in der Baumansicht:

go get github.com/justone/dockviz
$(go env GOPATH)/bin/dockviz images --tree -l
mmoya
quelle
besser zuerst zu tun sudo apt-get update ; sudo apt-get install golang-go; export GOPATH=$HOME/.go.
Loretoparisi
3
Ist auf macOS überbrew install dockviz
rcoup
Vorsicht bei der Verwendung von Ubuntu. Normalerweise werden veraltete Repositories für unterwegs verwendet
Qohelet
7

Ich habe eine Übersicht mit einem Shell-Skript erstellt, um den Nachkommenbaum eines Docker-Bildes auszudrucken, falls jemand an einer Bash-Lösung interessiert sein sollte:

#!/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" ""
Michal Linhard
quelle
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - Aus dem Rückblick
Juan Cruz Soler
Ich hatte gerade Probleme beim Formatieren des Codes, also gab ich auf, danke, dass Sie dies getan haben Jan
Michal Linhard
2

Dies ist, was ich getan habe, um mein endgültiges "Image" zu erhalten (Ebene, wirklich - was mich abschreckte, als ich gerade in Docker-Builds bin).

Ich bekam die ganze Nachricht "... kann nicht gezwungen werden ...". Mir wurde klar, dass ich die Bilder, die ich nicht benötigte, nicht löschen konnte, da es sich nicht wirklich um unabhängige Bilder handelt, die mit 'Docker Commit' erstellt wurden. Mein Problem war, dass ich mehrere Bilder (oder Ebenen) zwischen dem Basisbild und meinem endgültigen Bild hatte. Beim Versuch, aufzuräumen, bin ich auf den Fehler / die Warnung bezüglich des Kindes und des Elternteils gestoßen.

  1. Ich habe das endgültige Bild (oder die Ebene, wenn Sie so wollen) in einen Tarball exportiert.
  2. Ich habe dann alle Bilder gelöscht, die ich wollte, einschließlich meines Finales - ich habe es in einem Tarball gespeichert, also habe ich nur experimentiert, obwohl ich nicht sicher war, ob ich es verwenden könnte.
  3. Ich rannte dann docker image load -i FinalImage.tar.gz. Die Ausgabe war so etwas wie:

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

Geladene Bild-ID: sha256: 82d4f8ef9ea1eab72d989455728762ed3c0fe35fd85acf9edc47b41dacfd6382

Wenn ich jetzt mit 'Docker-Bild ls' aufliste, habe ich nur das ursprüngliche Basisbild und das endgültige Bild, das ich zuvor auf einem Tarball gespeichert habe.

[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

Mein System ist jetzt "sauber". Ich habe nur die Bilder, die ich will. Ich habe sogar das Basis-Image ohne Probleme gelöscht.

[root@docker1 ~]# docker rmi 36540f359ca3
Untagged: centos:httpd
Untagged:     centos@sha256:c1010e2fe2b635822d99a096b1f4184becf5d1c98707cbccae00be663a9b9131
Deleted: sha256:36540f359ca3b021d4b6a37815e9177b6c2bb3817598979ea55aee7ecc5c2c1f
Jerome Jordan
quelle
Gute Antwort, aber das Laden sollte nur für ein Bild verwendet werden, das mit "Docker Save" erstellt wurde. Die richtige Wiederherstellung für einen "Docker-Export" ist "Docker-Import"
Amalgovinus
2

Basierend auf den Antworten von Slushy und Michael Hoffman können Sie diese Shell-Funktion verwenden, wenn Sie nicht viele Bilder haben:

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}"
}

und nenne es dann mit

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

Hier ist eine Lösung, die auf der Python-API ( pip install docker) basiert und Nachkommen rekursiv zusammen mit ihren Tags (falls vorhanden) auflistet, wobei der Einzug entsprechend der Tiefe der Beziehung (Kinder, Enkelkinder usw.) erhöht wird:

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())

Beispiel:

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

Ich habe es als Zusammenfassung unter https://gist.github.com/simleo/10ad923f9d8a2fa410f7ec2d7e96ad57 zur Verfügung gestellt

simleo
quelle
1

Hier ist eine einfache Möglichkeit, eine Liste von untergeordneten Bildern abzurufen, die von einem übergeordneten Bild abhängig sind:

image_id=123456789012

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

Dadurch wird beispielsweise eine Liste mit IDs für untergeordnete / übergeordnete Bilder generiert (der Kürze halber abgeschnitten):

sha256:abcdefghijkl sha256:123456789012

Die linke Seite ist die untergeordnete Bild-ID, die rechte Seite ist die übergeordnete Bild-ID, die wir löschen möchten, aber es heißt "Bild hat abhängige untergeordnete Bilder". Dies sagt uns, dass dies abcdefghijkldas Kind ist, von dem abhängig ist 123456789012. Also müssen wir zuerst docker rmi abcdefghijkl, dann können Sie docker rmi 123456789012.

Jetzt kann es eine Kette von abhängigen untergeordneten Bildern geben, sodass Sie möglicherweise immer wieder wiederholen müssen, um das letzte Kind zu finden.

wisbucky
quelle
0

Sie können Docker-Bilder unabhängig von der Beziehung zwischen Eltern und Kind über das folgende Docker-Verzeichnis löschen

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

In diesem Verzeichnis finden Sie Docker-Bilder, mit denen Sie löschen können, was Sie möchten.

Jvn
quelle
Ich versuche, portable Befehle mithilfe der Docker-API zu erstellen, vorausgesetzt, Device Mapper und Docker-Engine (im Gegensatz zum Docker-Schwarm) machen dies zu einer nicht portablen Lösung. Es ist auch riskant, Dateien im Dateisystem zu löschen, während andere Prozesse (einschließlich des Docker-Daemons) diese verwenden könnten.
Nicocesar
Wo ist es auf Macos?
Anthony Kong
1
* WARNUNG "Dies kann in Zukunft zu mehreren Fehlern beim Löschen und Ziehen von Containern führen. Löschen Sie Verzeichnisse niemals /var/lib/dockerdirekt von Hand
vladkras
0

Wie wäre es mit:

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)

Es werden die untergeordneten Bild-IDs mit dem sha256:Präfix gedruckt .
Ich hatte auch folgendes, das die Namen anfügt:

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

  • ID= Ruft die vollständige ID des Bildes ab
  • IMAGES= Ruft alle untergeordneten Bilder ab, für die dieses Bild als aufgeführt ist Image
  • echo... Entfernt Duplikate und gibt die Ergebnisse wieder
Justin
quelle
Ich mag die Go-Format-Bedingungen, aber vielleicht sind sie besser als Filter für diesen Anwendungsfall.
Ingyhere
0

Ich habe mir das ausgedacht, um rekursiv Kinder und ihre Repo-Tags zu finden und auszudrucken, was sie tun:

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
}

Vergessen Sie nicht, / tmp / dii- * zu löschen, wenn Ihr Host nicht sicher ist.

android.weasel
quelle
-6

Ich stand auch vor dem gleichen Problem. Im Folgenden finden Sie die folgenden Schritte, um das Problem zu beheben.

Stoppen Sie alle laufenden Container

Docker Stop $ (Docker ps -aq) Entfernen Sie alle Container

Docker rm $ (Docker ps -aq) Entfernen Sie alle Bilder

Docker rmi $ (Docker-Bilder -q)

Ram Pasupula
quelle
Diese Antwort entspricht nicht den Anforderungen des Fragestellers.
Ankur Loriya
Bitte hören Sie auf, Dinge zu kommentieren, die möglicherweise kopiert und eingefügt werden könnten, und schädliche Dinge zu tun.
Nicocesar