Comment obtenir la liste des images enfants dépendantes dans Docker?

123

J'essaye de supprimer une image et j'obtiens:

# 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

Voici la version 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

mais il n'y a pas d'informations supplémentaires:

# 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

Comment puis-je obtenir les images d'enfants à charge qu'il prétend avoir?

il n'y a aucun conteneur en cours d'exécution ou arrêté avec cet identifiant d'image.

Nicocésar
la source
9
Je me demande pourquoi l'équipe docker ne peut pas fournir un moyen natif de le faire?
Amalgovinus

Réponses:

54

Réponse courte: Voici un script python3 qui répertorie les images docker dépendantes.

Réponse longue: Vous pouvez voir l'ID d'image et l'ID parent pour toutes les images créées après l'image en question avec les éléments suivants:

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

Vous devriez pouvoir rechercher des images avec un identifiant parent commençant par f50f9524513f, puis rechercher des images enfants de celles-ci , etc. Mais ce .Parent n'est pas ce que vous pensez. , donc dans la plupart des cas, vous devrez spécifier docker images --allci-dessus pour que cela fonctionne, vous obtiendrez également des identifiants d'image pour toutes les couches intermédiaires.

Voici un script python3 plus limité pour analyser la sortie du docker et effectuer la recherche pour générer la liste des images:

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

Si vous enregistrez ceci comme desc.pyvous pouvez l'invoquer comme suit:

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

Ou utilisez simplement l'essentiel ci - dessus , qui fait la même chose.

Aryeh Leib Taurog
la source
2
Et si aucun d'entre eux ne commence par les caractères attendus? Cela indique-t-il un bug possible? Je suis sur Docker pour Mac beta, FWIW, donc cela ne me surprendrait pas.
neverfox
Soit c'est un bug, soit cela signifie que l'image en question n'a pas d'enfants.
Aryeh Leib Taurog
2
Cela ne répond pas vraiment à la question initiale. Cela montre ce qui a été créé après l'image en question, qui peut dépendre ou non de l'image que l'affiche essayait de supprimer. La réponse de Simon Brady fait l'affaire, pour au moins de petites tailles d'échantillons d'images.
penguincoder
2
@penguincoder c'est à cela que sert le script python.
Aryeh Leib Taurog
Comme @neverfox, cette réponse n'a pas fonctionné pour moi. La réponse de Simon Brady ci-dessous a cependant fonctionné.
Mark le
91

Si vous n'avez pas un grand nombre d'images, il y a toujours l'approche de la force brute:

for i in $(docker images -q)
do
    docker history $i | grep -q f50f9524513f && echo $i
done | sort -u
Simon Brady
la source
1
Je pense que c'est la «meilleure» solution. Vous pouvez développer un peu cela et rendre un peu plus clair ce qui se passe en changeant le echo $1en le plus laid (mais toujours brutal-forcy) docker images | grep $i(plus portable dans les versions docker que d'utiliser des --filterindicateurs pour l'ID d'image)
Jon V
15

Installez dockviz et suivez les branches à partir de l'ID d'image dans l'arborescence:

go get github.com/justone/dockviz
$(go env GOPATH)/bin/dockviz images --tree -l
mmoya
la source
mieux vaut faire d' sudo apt-get update ; sudo apt-get install golang-go; export GOPATH=$HOME/.goabord.
loretoparisi
3
Est disponible sur macOS viabrew install dockviz
rcoup le
Attention, lors de l'utilisation d'Ubuntu. Il utilise généralement des référentiels obsolètes pour go
Qohelet
7

J'ai créé un résumé avec un script shell pour imprimer l'arbre descendant d'une image docker, si quelqu'un est intéressé par la solution 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" ""
Michal Linhard
la source
Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien pour référence. Les réponses aux liens uniquement peuvent devenir invalides si la page liée change. - De l'avis
Juan Cruz Soler
J'ai juste eu du mal à formater le code, alors j'ai abandonné, merci d'avoir fait cela Jan
Michal Linhard
2

C'est ce que j'ai fait afin de préserver mon "image" finale (couche, vraiment - ce qui m'a dérangé, car je suis juste en train d'entrer dans les builds de docker).

Je recevais tout le message "... ne peut pas être forcé ...". J'ai réalisé que je ne pouvais pas supprimer les images dont je n'avais pas besoin car ce ne sont pas vraiment des images indépendantes créées par 'docker commit'. Mon problème était que j'avais plusieurs images (ou calques) entre l'image de base et ma finale, et le simple fait d'essayer de nettoyer est l'endroit où j'ai rencontré l'erreur / l'avertissement concernant l'enfant et le parent.

  1. J'ai exporté l'image finale (ou le calque, si vous voulez) vers une archive tar.
  2. J'ai ensuite supprimé toutes les images que je voulais, y compris ma finale - je l'ai sauvegardée dans une archive tar donc, même si je n'étais pas sûr de pouvoir l'utiliser, je faisais juste des expériences.
  3. J'ai alors couru docker image load -i FinalImage.tar.gz. La sortie était quelque chose comme:

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 de l'image chargée: sha256: 82d4f8ef9ea1eab72d989455728762ed3c0fe35fd85acf9edc47b41dacfd6382

Maintenant, lorsque je liste avec 'docker image ls', je n'ai que l'image de base d'origine et l'image finale que j'ai précédemment enregistrée dans une archive tar.

[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

Mon système est maintenant «propre». Je n'ai que les images que je veux. J'ai même supprimé l'image de base sans problème.

[root@docker1 ~]# docker rmi 36540f359ca3
Untagged: centos:httpd
Untagged:     centos@sha256:c1010e2fe2b635822d99a096b1f4184becf5d1c98707cbccae00be663a9b9131
Deleted: sha256:36540f359ca3b021d4b6a37815e9177b6c2bb3817598979ea55aee7ecc5c2c1f
Jérôme Jordan
la source
Bonne réponse, mais load n'est censé être utilisé que sur une image créée à partir de "docker save". La restauration appropriée pour une "exportation docker" est "importation docker"
Amalgovinus
2

Basé sur slushy et les réponses de Michael Hoffman , si vous n'avez pas une tonne d'images, vous pouvez utiliser cette fonction 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}"
}

puis appelez-le en utilisant

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

Voici une solution basée sur l'API Python ( pip install docker) qui répertorie de manière récursive les descendants avec leurs balises (le cas échéant), en augmentant l'indentation en fonction de la profondeur de la relation (enfants, petits-enfants, etc.):

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

Exemple:

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

Je l'ai rendu disponible sous forme de résumé sur https://gist.github.com/simleo/10ad923f9d8a2fa410f7ec2d7e96ad57

Simleo
la source
1

Voici un moyen simple d'obtenir une liste d'images enfants qui dépendent d'une image parente:

image_id=123456789012

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

Cela générera une liste d'ID d'images enfant / parent, par exemple (tronqué par souci de concision):

sha256:abcdefghijkl sha256:123456789012

Le côté gauche est l'ID de l'image enfant, le côté droit est l'ID de l'image parent que nous essayons de supprimer, mais il indique "l'image a des images enfants dépendantes". Cela nous dit que abcdefghijklc'est l'enfant qui dépend 123456789012. Nous devons donc d'abord docker rmi abcdefghijkl, puis vous pouvez docker rmi 123456789012.

Maintenant, il peut y avoir une chaîne d'images enfants dépendantes, vous devrez peut-être répéter pour trouver le dernier enfant.

wisbucky
la source
0

Vous pouvez supprimer des images Docker indépendamment de la relation parent et enfant via le répertoire ci-dessous de Docker

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

Dans ce répertoire, vous pouvez trouver des images Docker, vous pouvez donc supprimer ce que vous voulez.

Jvn
la source
J'essaie de créer des commandes portables à l'aide de l'API docker, en supposant que le mappeur de périphériques et le moteur docker (par opposition à docker swarm par exemple) en font une solution non portable. Il est également risqué de supprimer des fichiers dans le système de fichiers alors que d'autres processus (y compris le démon docker) pourraient l'utiliser.
nicocesar
où est-il sur macos?
Anthony Kong
1
* AVERTISSEMENT "cela peut causer plusieurs erreurs lors de la suppression et de l'extraction de conteneurs à l'avenir. Ne supprimez jamais les /var/lib/docker
répertoires
0

Que diriez-vous:

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)

Il imprimera les identifiants de l'image enfant, avec le sha256:préfixe.
J'ai également eu ce qui suit, qui ajoute les noms:

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

  • ID= Obtient l'ID complet de l'image
  • IMAGES= Obtient toutes les images enfants qui ont cette image répertoriée comme un Image
  • echo... Supprime les doublons et fait écho aux résultats
Justin
la source
J'aime les conditions au format Go, mais elles sont peut-être meilleures comme filtre pour ce cas d'utilisation.
ingyhere le
0

J'ai concocté ceci pour trouver de manière récursive les enfants, leurs balises repo et imprimer ce qu'ils font:

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
}

N'oubliez pas de supprimer / tmp / dii- * si votre hôte n'est pas sécurisé.

android.weasel
la source
-5

J'étais également confronté au même problème. Suivez les étapes ci-dessous pour résoudre le problème.

Arrêtez tous les conteneurs en cours d'exécution

docker stop $ (docker ps -aq) Supprimer tous les conteneurs

docker rm $ (docker ps -aq) Supprimer toutes les images

docker rmi $ (images de docker -q)

Ram Pasupula
la source
cette réponse ne répond pas aux exigences du questionneur.
Ankur Loriya
Veuillez arrêter de commenter des choses que les gens pourraient copier et coller et faire des choses nuisibles.
nicocesar