Come ottenere l'elenco delle immagini figlio dipendenti in Docker?


123

Sto cercando di rimuovere un'immagine e ottengo:

# 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

Questa è la versione 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

ma non ci sono informazioni aggiuntive:

# 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

Come posso ottenere le immagini di figlio a carico che afferma di avere?

non ci sono contenitori in esecuzione o arrestati con quell'ID immagine.


9
Mi chiedo perché il team di Docker non può fornire un modo nativo per farlo?
Amalgovinus

Risposte:


54

Risposta breve: ecco uno script python3 che elenca le immagini docker dipendenti.

Risposta lunga: puoi vedere l'ID immagine e l'ID genitore per tutte le immagini create dopo l'immagine in questione con quanto segue:

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

Dovresti essere in grado di cercare immagini con ID genitore che inizia con f50f9524513f, quindi cercare immagini figlio di quelle , ecc. Ma .Parent non è quello che pensi. , quindi nella maggior parte dei casi dovresti specificare docker images --allsopra per farlo funzionare, quindi otterrai anche gli ID immagine per tutti i livelli intermedi.

Ecco uno script python3 più limitato per analizzare l'output del docker ed eseguire la ricerca per generare l'elenco delle immagini:

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

Se lo salvi come desc.pypuoi invocarlo come segue:

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

O usa semplicemente l'essenza sopra , che fa la stessa cosa.


2
E se nessuno di loro inizia con i personaggi attesi? Questo indica un possibile bug? Sono su Docker per Mac beta, FWIW, quindi non mi sorprenderebbe.
neverfox

O è un bug o significa che l'immagine in questione non ha figli.
Aryeh Leib Taurog

2
Questo non risponde realmente alla domanda originale. Questo mostra ciò che è stato creato dopo l'immagine in questione, che può dipendere o meno dall'immagine che il poster stava cercando di eliminare. La risposta di Simon Brady fa il trucco, per almeno piccole dimensioni campione di immagini.
penguincoder

2
@penguincoder è a questo che serve lo script python.
Aryeh Leib Taurog

Come @neverfox, questa risposta non ha funzionato per me. La risposta di Simon Brady di seguito ha funzionato, però.
Marco

91

Se non hai un numero enorme di immagini, c'è sempre l'approccio della forza bruta:

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

1
Penso che questa sia la soluzione "migliore". Puoi espandere questo un po 'e rendere un po' più chiaro cosa sia cambiando il echo $1più brutto (ma ancora brute-forcy) docker images | grep $i(più portabile nelle versioni docker rispetto all'utilizzo dei --filterflag per l'ID immagine)
Jon V

15

Installa dockviz e segui i rami dall'id immagine nella vista ad albero:

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

meglio fare sudo apt-get update ; sudo apt-get install golang-go; export GOPATH=$HOME/.goprima.
loretoparisi

3
È disponibile su macOS tramitebrew install dockviz
rcoup

Attento, quando usi Ubuntu. Di solito utilizza repository obsoleti per go
Qohelet il

7

Ho creato un gist con script di shell per stampare l'albero discendente di un'immagine docker, se qualcuno fosse interessato alla soluzione 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" ""

Sebbene questo collegamento possa rispondere alla domanda, è meglio includere le parti essenziali della risposta qui e fornire il collegamento come riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia. - Dalla recensione
Juan Cruz Soler

Ho appena avuto problemi a formattare il codice, quindi ho rinunciato, grazie per aver fatto questo Jan
Michal Linhard

2

Questo è quello che ho fatto per preservare la mia "immagine" finale (livello, davvero - che è ciò che mi ha sconcertato, dato che sto entrando nelle build docker).

Stavo ricevendo l'intero messaggio "... non si può forzare ...". Mi sono reso conto che non potevo eliminare le immagini di cui non avevo bisogno perché non sono immagini realmente indipendenti create da "docker commit". Il mio problema era che avevo diverse immagini (o livelli) tra l'immagine di base e la mia finale, e solo cercando di ripulire è dove ho incontrato l'errore / avvertimento sul bambino e sul genitore.

  1. Ho esportato l'immagine finale (o il livello, se vuoi) in un tarball.
  2. Ho quindi cancellato tutte le immagini che volevo, inclusa la mia finale - l'ho salvata in un tarball quindi, anche se non ero sicuro di essere in grado di usarla, stavo solo sperimentando.
  3. Allora ho corso docker image load -i FinalImage.tar.gz. L'output era qualcosa del tipo:

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 immagine caricata: sha256: 82d4f8ef9ea1eab72d989455728762ed3c0fe35fd85acf9edc47b41dacfd6382

Ora, quando elenco con 'docker image ls', ho solo l'immagine di base originale e l'immagine finale che ho salvato in precedenza in un 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

Adesso il mio sistema è "pulito". Ho solo le immagini che voglio. Ho persino cancellato l'immagine di base senza problemi.

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

Buona risposta, ma il caricamento dovrebbe essere utilizzato solo su un'immagine creata da "docker save". Il ripristino corretto per una "esportazione finestra mobile" è "importazione finestra mobile"
Amalgovinus

2

Sulla base delle risposte di Slushy e Michael Hoffman , se non hai un sacco di immagini puoi usare questa funzione di 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}"
}

e poi chiamalo usando

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

2

Ecco una soluzione basata sull'API Python ( pip install docker) che elenca ricorsivamente i discendenti insieme ai loro tag (se presenti), aumentando il rientro in base alla profondità della relazione (figli, nipoti, ecc.):

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

Esempio:

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

L'ho reso disponibile come sintesi su https://gist.github.com/simleo/10ad923f9d8a2fa410f7ec2d7e96ad57


1

Ecco un modo semplice per ottenere un elenco di immagini figlio che dipendono da un'immagine genitore:

image_id=123456789012

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

Ciò genererà un elenco di ID immagini figlio / genitore, ad esempio (troncato per brevità):

sha256:abcdefghijkl sha256:123456789012

Il lato sinistro è l'ID dell'immagine del bambino, il lato destro è l'ID dell'immagine del genitore che stiamo cercando di eliminare, ma si dice "l'immagine ha immagini secondarie dipendenti". Questo ci dice che abcdefghijklè il bambino da cui dipende 123456789012. Quindi dobbiamo prima docker rmi abcdefghijkl, poi puoi docker rmi 123456789012.

Ora, potrebbe esserci una catena di immagini di figli dipendenti, quindi potrebbe essere necessario continuare a ripetere per trovare l'ultimo figlio.


0

È possibile eliminare le immagini Docker indipendentemente dalla relazione padre e figlio tramite la directory sottostante di Docker

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

In questa directory puoi trovare le immagini Docker, quindi puoi eliminare ciò che desideri.


Sto cercando di creare comandi portatili utilizzando l'API docker, supponendo che il mappatore del dispositivo e il motore docker (al contrario di docker swarm, ad esempio) rendano questa soluzione non portatile. Inoltre è rischioso eliminare i file nel filesystem mentre altri processi (incluso il demone docker) potrebbero usarlo.
nicocesar

dov'è su macos?
Anthony Kong

1
* ATTENZIONE "questo può causare più errori con l'eliminazione e l'estrazione di contenitori in futuro. Non eliminare mai le directory /var/lib/dockerdirettamente a mano
vladkras

0

Che ne dite di:

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)

Stamperà gli ID dell'immagine figlio, con il sha256:prefisso.
Avevo anche il seguente, che aggiunge i nomi:

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

  • ID= Ottiene l'id completo dell'immagine
  • IMAGES= Ottiene tutte le immagini figlio che hanno questa immagine elencata come Image
  • echo... Rimuove i duplicati ed effettua l'eco dei risultati

Mi piacciono i condizionali del formato Go, ma forse sono migliori come filtro per questo caso d'uso.
qui

0

Ho inventato questo per trovare ricorsivamente i bambini, i loro tag repo e stampare quello che stanno facendo:

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
}

Non dimenticare di eliminare / tmp / dii- * se il tuo host non è sicuro.


-5

Anch'io stavo affrontando lo stesso problema. Procedura indicata di seguito per risolvere il problema.

Arresta tutti i contenitori in esecuzione

docker stop $ (docker ps -aq) Rimuove tutti i contenitori

docker rm $ (docker ps -aq) Rimuove tutte le immagini

docker rmi $ (immagini docker -q)


questa risposta non soddisfa i requisiti dell'interrogante.
Ankur Loriya

Per favore smettila di commentare cose che le persone potrebbero potenzialmente copiare e incollare e fare cose dannose.
nicocesar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.