Jak uzyskać listę zależnych obrazów podrzędnych w Dockerze?

123

Próbuję usunąć obraz i otrzymuję:

# 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

To jest wersja dockera:

# 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

ale nie ma dodatkowych informacji:

# 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

Jak mogę uzyskać obrazy dziecka na utrzymaniu, które twierdzi, że ma?

nie ma uruchomionych ani zatrzymanych kontenerów z tym identyfikatorem obrazu.

nikocezar
źródło
9
Muszę się zastanawiać, dlaczego zespół Dockera nie może zapewnić tego natywnego sposobu?
Amalgovinus,

Odpowiedzi:

54

Krótka odpowiedź: Oto skrypt python3, który wyświetla zależne obrazy dockera .

Długa odpowiedź: możesz zobaczyć identyfikator obrazu i identyfikator nadrzędny dla wszystkich obrazów utworzonych po obrazie, o którym mowa, za pomocą następujących elementów:

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

Powinieneś być w stanie spojrzeć na zdjęcia z macierzystej id zaczynających się f50f9524513f, a następnie szukać zdjęć potomnych tych , itp .. Ale .Parent nie jest to, co myślisz. , więc w większości przypadków będziesz musiał określić docker images --allpowyżej, aby to zadziałało, wtedy otrzymasz również identyfikatory obrazów dla wszystkich warstw pośrednich.

Oto bardziej ograniczony skrypt Python3, który analizuje dane wyjściowe dockera i przeprowadza wyszukiwanie w celu wygenerowania listy obrazów:

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

Jeśli zapiszesz to, ponieważ desc.pymożesz wywołać to w następujący sposób:

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

Lub po prostu skorzystaj z powyższego streszczenia , co robi to samo.

Aryeh Leib Taurog
źródło
2
A jeśli żaden z nich nie zacznie od oczekiwanych postaci? Czy to wskazuje na możliwy błąd? Jestem na Docker for Mac beta, FWIW, więc nie zdziwiłoby mnie to.
neverfox
Albo jest to błąd, albo oznacza, że ​​dany obraz nie ma żadnych dzieci.
Aryeh Leib Taurog
2
To tak naprawdę nie odpowiada na pierwotne pytanie. Pokazuje to, co zostało utworzone po danym obrazie, co może, ale nie musi, zależeć od obrazu, który plakat próbował usunąć. Odpowiedź Simona Brady'ego załatwia sprawę, przynajmniej w przypadku małych próbek obrazów.
penguincoder
2
@penguincoder do tego służy skrypt Pythona.
Aryeh Leib Taurog
Podobnie jak @neverfox, ta odpowiedź nie działa dla mnie. Jednak poniższa odpowiedź Simona Brady'ego zadziałała.
Mark
91

Jeśli nie masz dużej liczby obrazów, zawsze istnieje podejście brutalnej siły:

for i in $(docker images -q)
do
    docker history $i | grep -q f50f9524513f && echo $i
done | sort -u
Simon Brady
źródło
1
Myślę, że to „najlepsze” rozwiązanie. Możesz to trochę rozszerzyć i wyjaśnić, co jest, zmieniając na echo $1brzydsze (ale nadal brutalne) docker images | grep $i(bardziej przenośne w wersjach dockerowych niż używanie --filterflag dla identyfikatora obrazu)
Jon V
15

Zainstaluj dockviz i podążaj za gałęziami z identyfikatora obrazu w widoku drzewa:

go get github.com/justone/dockviz
$(go env GOPATH)/bin/dockviz images --tree -l
mmoya
źródło
lepiej zrobić sudo apt-get update ; sudo apt-get install golang-go; export GOPATH=$HOME/.gonajpierw.
loretoparisi
3
Jest dostępny na macOS przezbrew install dockviz
rcoup
Ostrożnie, używając Ubuntu. Zwykle używa przestarzałych repozytoriów do go
Qohelet
7

Stworzyłem sedno ze skryptem powłoki, aby wydrukować drzewo potomne obrazu dockera, gdyby ktoś był zainteresowany rozwiązaniem 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" ""
Michał Linhard
źródło
Chociaż ten link może odpowiedzieć na pytanie, lepiej jest zawrzeć tutaj zasadnicze części odpowiedzi i podać link do odniesienia. Odpowiedzi zawierające tylko łącze mogą stać się nieprawidłowe, jeśli połączona strona ulegnie zmianie. - Z recenzji
Juan Cruz Soler
Właśnie miałem problem ze sformatowaniem kodu, więc zrezygnowałem, dzięki za zrobienie tego Jan
Michał Linhard
2

To właśnie zrobiłem, aby zachować mój ostateczny „obraz” (tak naprawdę warstwa - co mnie zrzuciło, ponieważ właśnie zaczynam wchodzić w kompilacje Dockera).

Otrzymałem całą wiadomość „… nie można zmusić…”. Zdałem sobie sprawę, że nie mogę usunąć obrazów, których nie potrzebowałem, ponieważ nie są one tak naprawdę niezależnymi obrazami utworzonymi przez „docker commit”. Mój problem polegał na tym, że miałem kilka obrazów (lub warstw) między obrazem podstawowym a moim końcowym, a po prostu próbując wyczyścić, napotkałem błąd / ostrzeżenie dotyczące dziecka i rodzica.

  1. Wyeksportowałem ostateczny obraz (lub warstwę, jeśli wolisz) do tarballa.
  2. Następnie usunąłem wszystkie obrazy, które chciałem, w tym wersję ostateczną - zapisałem ją w tarballu, więc chociaż nie byłem pewien, czy będę w stanie go użyć, po prostu eksperymentowałem.
  3. Potem pobiegłem docker image load -i FinalImage.tar.gz. Wynik wyglądał mniej więcej tak:

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

Identyfikator wczytanego obrazu: sha256: 82d4f8ef9ea1eab72d989455728762ed3c0fe35fd85acf9edc47b41dacfd6382

Teraz, kiedy wypisuję jako „docker image ls”, mam tylko oryginalny obraz podstawowy, a ostateczny obraz, który wcześniej zapisałem w archiwum.

[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

Mój system jest teraz „czysty”. Mam tylko te obrazy, które chcę. Nawet usunąłem obraz podstawowy bez problemu.

[root@docker1 ~]# docker rmi 36540f359ca3
Untagged: centos:httpd
Untagged:     centos@sha256:c1010e2fe2b635822d99a096b1f4184becf5d1c98707cbccae00be663a9b9131
Deleted: sha256:36540f359ca3b021d4b6a37815e9177b6c2bb3817598979ea55aee7ecc5c2c1f
Jerome Jordan
źródło
Dobra odpowiedź, ale ładowanie powinno być używane tylko na obrazie utworzonym z „docker save”. Prawidłowe przywracanie dla „eksportu
docker
2

Opierając się na odpowiedziach Slushy i Michaela Hoffmana , jeśli nie masz wielu obrazów, możesz użyć tej funkcji powłoki:

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

a następnie nazwij to używając

docker_image_desc <image-id> | awk '!x[$0]++'
Maxim Suslov
źródło
2

Oto rozwiązanie oparte na Python API ( pip install docker), które rekurencyjnie wyświetla potomków wraz z ich tagami (jeśli istnieją), zwiększając wcięcie zgodnie z głębokością relacji (dzieci, wnuki itp.):

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

Przykład:

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

Udostępniłem go jako podsumowanie na https://gist.github.com/simleo/10ad923f9d8a2fa410f7ec2d7e96ad57

simleo
źródło
1

Oto prosty sposób na uzyskanie listy obrazów podrzędnych zależnych od obrazu nadrzędnego:

image_id=123456789012

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

Spowoduje to wygenerowanie listy identyfikatorów obrazów podrzędnych / nadrzędnych, na przykład (skrócone dla zwięzłości):

sha256:abcdefghijkl sha256:123456789012

Lewa strona to identyfikator obrazu podrzędnego, prawa strona to identyfikator obrazu nadrzędnego, który próbujemy usunąć, ale mówi, że „obraz ma zależne obrazy podrzędne”. To mówi nam, że abcdefghijklto dziecko jest zależne 123456789012. Więc najpierw musimy docker rmi abcdefghijkl, a potem możesz docker rmi 123456789012.

Teraz może istnieć łańcuch zależnych obrazów dzieci, więc być może będziesz musiał powtarzać, aby znaleźć ostatnie dziecko.

wisbucky
źródło
0

Obrazy platformy Docker można usuwać niezależnie od relacji nadrzędnej i podrzędnej za pośrednictwem poniższego katalogu platformy Docker

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

W tym katalogu możesz znaleźć obrazy Dockera, dzięki czemu możesz usunąć to, co chcesz.

Jvn
źródło
Próbuję tworzyć przenośne polecenia przy użyciu interfejsu docker API, zakładając, że urządzenie mapper i silnik docker (w przeciwieństwie na przykład do docker swarm) sprawiają, że jest to nieprzenośne rozwiązanie. Ryzykowne jest również usuwanie plików w systemie plików, podczas gdy inny proces (w tym demon Dockera) może go używać.
nicocesar
gdzie to jest na macos?
Anthony Kong
1
* OSTRZEŻENIE "w przyszłości może to spowodować wiele błędów przy usuwaniu i /var/lib/docker
pobieraniu
0

Co powiesz na:

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)

Wyświetli identyfikator obrazu podrzędnego z sha256:przedrostkiem.
Miałem też następujące, które dołączają nazwy:

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

  • ID= Pobiera pełny identyfikator obrazu
  • IMAGES= Pobiera wszystkie obrazy podrzędne, które mają ten obraz wymieniony jako plik Image
  • echo... Usuwa duplikaty i wyświetla wyniki
Justin
źródło
Podoba mi się warunkowe w formacie Go, ale może są lepsze jako filtr w tym przypadku użycia.
ingyhere
0

Przygotowałem to, aby rekurencyjnie znaleźć dzieci, ich tagi repozytorium i wydrukować to, co robią:

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
}

Nie zapomnij usunąć / tmp / dii- *, jeśli twój host nie jest bezpieczny.

android.weasel
źródło
-5

Miałem też ten sam problem. Poniższe kroki rozwiązują problem.

Zatrzymaj wszystkie uruchomione kontenery

docker stop $ (docker ps -aq) Usuń wszystkie kontenery

docker rm $ (docker ps -aq) Usuń wszystkie obrazy

docker rmi $ (obrazy docker -q)

Ram Pasupula
źródło
ta odpowiedź nie spełnia wymagań osoby pytającej.
Ankur Loriya
Przestań komentować rzeczy, które ludzie mogą potencjalnie kopiować i wklejać oraz robić szkodliwe rzeczy.
nicocesar