Как получить список зависимых дочерних образов в Docker?

123

Я пытаюсь удалить изображение и получаю:

# 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

Это версия докера:

# 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

но дополнительной информации нет:

# 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

Как я могу получить зависимые дочерние изображения, которые он утверждает?

нет ни запущенных, ни остановленных контейнеров с этим идентификатором изображения.

nicocesar
источник
9
Я должен задаться вопросом, почему команда докеров не может предоставить собственный способ сделать это?
Амальговинус

Ответы:

54

Краткий ответ: вот скрипт python3, в котором перечислены зависимые образы докеров .

Длинный ответ: вы можете увидеть идентификатор изображения и родительский идентификатор для всего изображения, созданного после рассматриваемого изображения, со следующим:

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

Вы должны иметь возможность искать изображения с родительским идентификатором, начинающимся с f50f9524513f, а затем искать их дочерние изображения и т. Д. Но .Parent это не то, что вы думаете. , поэтому в большинстве случаев вам нужно будет указать docker images --allвыше, чтобы это работало, тогда вы также получите идентификаторы изображений для всех промежуточных слоев.

Вот более ограниченный скрипт python3 для анализа вывода докера и выполнения поиска для создания списка изображений:

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

Если вы сохраните это, desc.pyвы можете вызвать его следующим образом:

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

Или просто используйте суть выше , которая делает то же самое.

Арье Лейб Таурог
источник
2
Что, если ни один из них не начинается с ожидаемых символов? Это указывает на возможную ошибку? Я использую бета-версию Docker для Mac, FWIW, так что меня это не удивит.
neverfox
Либо это ошибка, либо это означает, что у рассматриваемого изображения нет дочерних элементов.
Арье Лейб Таурог
2
Это не совсем ответ на исходный вопрос. Это показывает, что было создано после рассматриваемого изображения, что может зависеть или не зависеть от изображения, которое плакат пытался удалить. Ответ Саймона Брэди помогает, по крайней мере, для небольших выборок изображений.
penguincoder
2
@penguincoder - вот для чего нужен скрипт Python.
Арье Лейб Таурог
Как и @ Neverfox, этот ответ у меня не сработал. Однако ответ Саймона Брэди ниже сработал.
Марк
91

Если у вас нет большого количества изображений, всегда есть подход грубой силы:

for i in $(docker images -q)
do
    docker history $i | grep -q f50f9524513f && echo $i
done | sort -u
Саймон Брэди
источник
1
Считаю это «лучшим» решением. Вы можете немного расширить это и сделать более понятным, что к чему, изменив на echo $1более уродливый (но все же грубый) docker images | grep $i(более переносимый в версиях докеров, чем использование --filterфлагов для идентификатора изображения)
Джон В.
15

Установите dockviz и следуйте веткам идентификатора изображения в дереве:

go get github.com/justone/dockviz
$(go env GOPATH)/bin/dockviz images --tree -l
mmoya
источник
лучше сделать sudo apt-get update ; sudo apt-get install golang-go; export GOPATH=$HOME/.goсначала.
loretoparisi
3
Доступно на macOS черезbrew install dockviz
rcoup
Будьте осторожны при использовании Ubuntu. Обычно он использует устаревшие репозитории,
Qohelet
7

Я создал суть со сценарием оболочки для распечатки дерева потомков образа докера, если кого-то заинтересует решение 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" ""
Михал Линхард
источник
Хотя эта ссылка может дать ответ на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если ссылка на страницу изменится. - Из
Хуан Круз Солер,
У меня просто были проблемы с форматированием кода, поэтому я сдался, спасибо за это Ян
Михал Линхард
2

Это то, что я сделал, чтобы сохранить свое окончательное «изображение» (на самом деле, слой - это то, что меня сбило с толку, поскольку я только начинаю заниматься сборками докеров).

Я получал все сообщение «... нельзя принудительно ...». Я понял, что не могу удалить изображения, которые мне не нужны, потому что они не являются действительно независимыми изображениями, созданными с помощью «фиксации докеров». Моя проблема заключалась в том, что у меня было несколько изображений (или слоев) между базовым изображением и моим последним, и просто пытаясь очистить, я встретил ошибку / предупреждение о дочернем и родительском.

  1. Я экспортировал окончательное изображение (или слой, если хотите) в архив.
  2. Затем я удалил все изображения, которые хотел, включая свой последний - я сохранил его в архиве, поэтому, хотя я не был уверен, смогу ли я его использовать, я просто экспериментировал.
  3. Я тогда побежал docker image load -i FinalImage.tar.gz. Результат был примерно таким:

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 загруженного изображения: sha256: 82d4f8ef9ea1eab72d989455728762ed3c0fe35fd85acf9edc47b41dacfd6382

Теперь, когда я указываю «docker image ls», у меня есть только исходный базовый образ и последний образ, который я ранее сохранил в архиве.

[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

Моя система теперь «чистая». У меня есть только те изображения, которые мне нужны. Я даже без проблем удалил базовый образ.

[root@docker1 ~]# docker rmi 36540f359ca3
Untagged: centos:httpd
Untagged:     centos@sha256:c1010e2fe2b635822d99a096b1f4184becf5d1c98707cbccae00be663a9b9131
Deleted: sha256:36540f359ca3b021d4b6a37815e9177b6c2bb3817598979ea55aee7ecc5c2c1f
Джером Джордан
источник
Хороший ответ, но загрузка должна использоваться только для образа, созданного с помощью "docker save". Правильным восстановлением для «экспорта
докеров
2

Основываясь на ответах Slushy и Майкла Хоффмана , если у вас нет тонны изображений, вы можете использовать эту функцию оболочки:

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

а затем назовите его, используя

docker_image_desc <image-id> | awk '!x[$0]++'
Максим Суслов
источник
2

Вот решение, основанное на Python API ( pip install docker), которое рекурсивно перечисляет потомков вместе с их тегами (если есть), увеличивая отступ в соответствии с глубиной отношения (дети, внуки и т. Д.):

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

Пример:

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

Я сделал его доступным по адресу https://gist.github.com/simleo/10ad923f9d8a2fa410f7ec2d7e96ad57.

simleo
источник
1

Вот простой способ получить список дочерних изображений, которые зависят от родительского изображения:

image_id=123456789012

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

Это сгенерирует список идентификаторов дочерних / родительских изображений, например (усеченный для краткости):

sha256:abcdefghijkl sha256:123456789012

Левая часть - это идентификатор дочернего изображения, правая часть - это идентификатор родительского изображения, которое мы пытаемся удалить, но в нем говорится, что «изображение имеет зависимые дочерние изображения». Это говорит нам, что abcdefghijklэто ребенок, от которого зависит 123456789012. Так что сначала нам нужно docker rmi abcdefghijkl, а потом можно docker rmi 123456789012.

Теперь может существовать цепочка зависимых дочерних изображений, поэтому вам, возможно, придется повторять, чтобы найти последний дочерний элемент.

wisbucky
источник
0

Вы можете удалить образы Docker независимо от родительского и дочернего отношения через приведенный ниже каталог Docker.

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

В этом каталоге вы можете найти образы Docker, так что вы можете удалить все, что хотите.

JVN
источник
Я пытаюсь создавать переносимые команды с помощью API-интерфейса докеров, предполагая, что устройство сопоставления устройств и механизм докеров (в отличие, например, от docker swarm) делают это непереносимым решением. Также рискованно удалять файлы в файловой системе, в то время как другие процессы (включая демон докера) могут их использовать.
Никосесар
где это на macos?
Энтони Конг
1
* ВНИМАНИЕ: "это может вызвать множественные ошибки при удалении и извлечении контейнеров в будущем. Никогда не удаляйте каталоги /var/lib/dockerнапрямую вручную
vladkras
0

Как насчет:

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)

Он напечатает идентификаторы дочерних изображений с sha256:префиксом.
У меня также было следующее, к которому добавляются имена:

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

  • ID= Получает полный идентификатор изображения
  • IMAGES= Получает все дочерние изображения, у которых это изображение указано как Image
  • echo... Удаляет дубликаты и повторяет результаты
Джастин
источник
Мне нравятся условные выражения формата Go, но, возможно, они лучше подходят в качестве фильтра для этого варианта использования.
ingyhere
0

Я приготовил это, чтобы рекурсивно находить детей, их теги репо и распечатывать то, что они делают:

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
}

Не забудьте удалить / tmp / dii- *, если ваш хост небезопасен.

android.weasel
источник
-5

Я тоже столкнулся с той же проблемой. Чтобы решить проблему, выполните следующие действия.

Остановить все запущенные контейнеры

docker stop $ (docker ps -aq) Удалить все контейнеры

docker rm $ (docker ps -aq) Удалить все изображения

docker rmi $ (образы докеров -q)

Рам Пашупула
источник
этот ответ не соответствует требованиям спрашивающего.
Анкур Лория 06
Пожалуйста, прекратите комментировать то, что люди могут скопировать и вставить и сделать что-то вредоносное.
nicocesar