Як отримати список дитячих зображень залежно від Докера?


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

Як я можу отримати зображення залежних дітей, про які вона стверджує?

з цим ідентифікатором зображення немає запущених та зупинених контейнерів.


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 beta, FWIW, так що мене не здивувало.
neverfox

Або це помилка, або це означає, що на відповідному зображенні немає дітей.
Aryeh Leib Taurog

2
Це насправді не відповідає на початкове запитання. Це показує, що було створено після відповідного зображення, яке може бути, а може і не залежати від зображення, яке плакат намагався видалити. Відповідь Саймона Брейді робить хитрість, принаймні невеликі зразки розмірів зображень.
penguincoder

2
@penguincoder саме для цього призначений сценарій python.
Aryeh Leib Taurog

Як і @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прапорів для зображення Id)
Jon V

15

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

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

краще зробити sudo apt-get update ; sudo apt-get install golang-go; export GOPATH=$HOME/.goспочатку.
loretoparisi

3
Доступний на macOS черезbrew install dockviz
rcoup

Обережно при використанні Ubuntu. Зазвичай він використовує застарілі сховища для go
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

Хороша відповідь, але навантаження передбачається використовувати лише на зображенні, створеному з "збереження докера". Правильним відновленням для "експорту
докера

2

Спираючись на сльозисті відповіді та Майкл Гофман , якщо у вас немає тонни зображень, ви можете використовувати цю функцію оболонки:

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

Ось рішення, засноване на API Python ( 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


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.

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


0

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

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

У цьому каталозі ви можете знайти зображення Докера, щоб ви могли видалити те, що потрібно.


Я намагаюся скласти портативні команди за допомогою API докера, припускаючи, що картограф пристрою та докерний двигун (на відміну від рою докера, наприклад) робить це не портативним рішенням. Також ризиковано видаляти файли у файловій системі, тоді як інший процес (включаючи демон докера) може використовувати його.
nicocesar

де це на macos?
Ентоні Конг

1
* ПОПЕРЕДЖЕННЯ "це може призвести до кількох помилок при видаленні та витягуванні контейнерів у майбутньому. Ніколи не видаляйте /var/lib/docker
дріс

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- *, якщо ваш хост не захищений.


-6

Я також стикався з тим же питанням. Наведені нижче кроки для вирішення проблеми.

Зупиніть усі запущені контейнери

docker stop $ (docker ps -aq) Видаліть усі контейнери

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

docker rmi $ (docker images -q)


ця відповідь не відповідає вимозі запитувача.
Анкур Лорія

Будь ласка, припиніть коментувати речі, які люди могли потенційно копіювати та вставляти та робити шкідливі речі.
nicocesar
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.