Como obter a lista de imagens de filhos dependentes no Docker?

123

Estou tentando remover uma imagem e recebo:

# 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

Esta é a versão 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

mas não há informações extras:

# 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

Como posso obter as imagens de crianças dependentes que afirma ter?

não há contêineres em execução ou interrompidos com esse id de imagem.

Nicocesar
fonte
9
Eu tenho que me perguntar por que a equipe docker não pode fornecer uma maneira nativa de fazer isso?
Amalgovinus

Respostas:

54

Resposta curta: Aqui está um script python3 que lista as imagens dependentes do docker.

Resposta longa: você pode ver o id da imagem e o id pai de todas as imagens criadas após a imagem em questão com o seguinte:

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

Você deve ser capaz de procurar imagens com id pai começando com f50f9524513f, então procurar imagens filhas dessas , etc. Mas .Parent não é o que você pensa. , então, na maioria dos casos, você precisaria especificar docker images --allacima para fazer isso funcionar, então você obterá ids de imagem para todas as camadas intermediárias também.

Aqui está um script python3 mais limitado para analisar a saída do docker e fazer a pesquisa para gerar a lista de imagens:

#!/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 você salvá- desc.pylo, poderá invocá-lo da seguinte maneira:

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

Ou apenas use a essência acima , que faz a mesma coisa.

Aryeh Leib Taurog
fonte
2
E se nenhum deles começar com os personagens esperados? Isso indica um possível bug? Estou no Docker para Mac beta, FWIW, então isso não me surpreenderia.
neverfox
Ou é um bug ou significa que a imagem em questão não tem filhos.
Aryeh Leib Taurog
2
Isso realmente não responde à pergunta original. Mostra o que foi criado após a imagem em questão, que pode ou não depender da imagem que o pôster estava tentando excluir. A resposta de Simon Brady resolve o problema, pelo menos para pequenos tamanhos de amostra de imagens.
penguincoder
2
@penguincoder é para isso que serve o script python.
Aryeh Leib Taurog
Como @neverfox, essa resposta não funcionou para mim. A resposta de Simon Brady abaixo funcionou, no entanto.
Marcos
91

Se você não tem um grande número de imagens, há sempre a abordagem da força bruta:

for i in $(docker images -q)
do
    docker history $i | grep -q f50f9524513f && echo $i
done | sort -u
Simon Brady
fonte
1
Acho que essa é a "melhor" solução. Você pode expandir isso um pouco e deixar um pouco mais claro o que é o quê, alterando o echo $1para o mais feio (mas ainda brute-forcy) docker images | grep $i(mais portátil nas versões docker do que usando --filtersinalizadores para o Id da imagem)
Jon V
15

Instale o dockviz e siga as ramificações do id da imagem na visualização em árvore:

go get github.com/justone/dockviz
$(go env GOPATH)/bin/dockviz images --tree -l
mmoya
fonte
melhor fazer sudo apt-get update ; sudo apt-get install golang-go; export GOPATH=$HOME/.goprimeiro.
Loretoparisi
3
Está disponível no macOS viabrew install dockviz
rcoup
Cuidado, ao usar o Ubuntu. Normalmente usa repositórios desatualizados para go
Qohelet
7

Eu criei uma essência com script de shell para imprimir a árvore descendente de uma imagem do docker, caso alguém esteja interessado na solução 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
fonte
Embora este link possa responder à pergunta, é melhor incluir as partes essenciais da resposta aqui e fornecer o link para referência. As respostas somente com link podem se tornar inválidas se a página vinculada mudar. - Da avaliação
Juan Cruz Soler
Eu só tive problemas para formatar o código, então desisti, obrigado por fazer isso Jan
Michal Linhard 01 de
2

Isso é o que eu fiz a fim de preservar minha "imagem" final (camada, na verdade - que é o que me confundiu, já que estou entrando nas versões docker).

Eu estava recebendo toda a mensagem "... não pode ser forçado ...". Percebi que não poderia excluir as imagens de que não precisava, porque elas não são imagens realmente independentes criadas pelo 'docker commit'. Meu problema era que eu tinha várias imagens (ou camadas) entre a imagem de base e a minha final e, apenas tentando limpar, encontrei o erro / aviso sobre a criança e os pais.

  1. Exportei a imagem final (ou camada, se preferir) para um tarball.
  2. Em seguida, apaguei todas as imagens que queria, incluindo a minha final - salvei em um tarball, então, embora não tivesse certeza se seria capaz de usá-la, estava apenas experimentando.
  3. Eu então corri docker image load -i FinalImage.tar.gz. O resultado foi algo como:

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 da imagem carregada: sha256: 82d4f8ef9ea1eab72d989455728762ed3c0fe35fd85acf9edc47b41dacfd6382

Agora, quando listo com 'docker image ls', só tenho a imagem base original e a imagem final que salvei anteriormente em um 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

Meu sistema está 'limpo' agora. Só tenho as imagens que quero. Até apaguei a imagem base sem problemas.

[root@docker1 ~]# docker rmi 36540f359ca3
Untagged: centos:httpd
Untagged:     centos@sha256:c1010e2fe2b635822d99a096b1f4184becf5d1c98707cbccae00be663a9b9131
Deleted: sha256:36540f359ca3b021d4b6a37815e9177b6c2bb3817598979ea55aee7ecc5c2c1f
Jerome Jordan
fonte
Boa resposta, mas o load só deve ser usado em uma imagem criada em "docker save". A restauração adequada para uma "exportação docker" é "importação docker"
Amalgovinus
2

Com base nas respostas slushy e Michael Hoffman , se você não tiver uma tonelada de imagens, pode usar esta função 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 então chamá-lo usando

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

Esta é uma solução baseada na API Python ( pip install docker) que lista os descendentes recursivamente junto com suas tags (se houver), aumentando o recuo de acordo com a profundidade do relacionamento (filhos, netos, 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())

Exemplo:

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

Eu o disponibilizei como uma essência em https://gist.github.com/simleo/10ad923f9d8a2fa410f7ec2d7e96ad57

simleo
fonte
1

Esta é uma maneira simples de obter uma lista de imagens filhas que dependem de uma imagem pai:

image_id=123456789012

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

Isso irá gerar uma lista de IDs de imagens filho / pai, por exemplo (truncada para concisão):

sha256:abcdefghijkl sha256:123456789012

O lado esquerdo é o ID da imagem filha, o lado direito é o ID da imagem pai que estamos tentando excluir, mas está dizendo "a imagem tem imagens filho dependentes". Isso nos diz que abcdefghijklé a criança que depende 123456789012. Então, precisamos primeiro docker rmi abcdefghijkl, então você pode docker rmi 123456789012.

Agora, pode haver uma cadeia de imagens de filhos dependentes, então você pode ter que repetir para encontrar o último filho.

wisbucky
fonte
0

Você pode excluir imagens do Docker independentemente da relação pai e filho através do diretório abaixo do Docker

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

Nesse diretório, você pode encontrar imagens Docker, para que possa excluir o que deseja.

Jvn
fonte
Estou tentando fazer comandos portáteis usando a API docker, supondo que o mapeador de dispositivos e o mecanismo docker (em oposição ao docker swarm, por exemplo) tornem isso uma solução não portátil. Também é arriscado excluir arquivos do sistema de arquivos enquanto outro processo (incluindo o docker daemon) pode estar usando.
Nicocesar
onde está no macos?
Anthony Kong
1
* AVISO "isso pode causar vários erros com a exclusão e extração de contêineres no futuro. Nunca exclua diretórios /var/lib/dockerdiretamente manualmente
vladkras
0

E se:

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)

Ele vai imprimir os ids da imagem filha, com o sha256:prefixo.
Eu também tinha o seguinte, que acrescenta os nomes:

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

  • ID= Obtém o id completo da imagem
  • IMAGES= Obtém todas as imagens secundárias que possuem esta imagem listada como um Image
  • echo... Remove duplicatas e ecoa os resultados
Justin
fonte
Eu gosto das condicionais de formato Go, mas talvez elas sejam melhores como um filtro para este caso de uso.
ingyhere
0

Eu preparei isso para encontrar recursivamente os filhos, suas tags de repositório e imprimir o que eles estão fazendo:

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ão se esqueça de deletar / tmp / dii- * se seu host não for seguro.

android.weasel
fonte
-6

Eu também estava enfrentando o mesmo problema. Siga as etapas abaixo para resolver o problema.

Pare todos os contêineres em execução

docker stop $ (docker ps -aq) Remova todos os contêineres

docker rm $ (docker ps -aq) Remover todas as imagens

docker rmi $ (docker imagens -q)

Ram Pasupula
fonte
esta resposta não atende ao requisito do questionador.
Ankur Loriya
Pare de comentar coisas que as pessoas podem copiar e colar e fazer coisas prejudiciais.
Nicocesar