Bagaimana cara mendapatkan daftar image anak dependen di Docker?

123

Saya mencoba menghapus gambar dan saya mendapatkan:

# 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

Ini adalah versi buruh pelabuhan:

# 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

tetapi tidak ada informasi tambahan:

# 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

Bagaimana saya bisa mendapatkan gambar anak tanggungan yang diklaimnya?

tidak ada kontainer yang berjalan atau dihentikan dengan id gambar itu.

nicocesar.dll
sumber
9
Saya harus bertanya-tanya mengapa tim buruh pelabuhan tidak dapat menyediakan cara asli untuk melakukan ini?
Amalgovinus

Jawaban:

54

Jawaban singkat: Ini adalah script python3 yang mencantumkan gambar buruh pelabuhan dependen.

Jawaban panjang: Anda dapat melihat id gambar dan id induk untuk semua gambar yang dibuat setelah gambar yang dimaksud dengan berikut ini:

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

Anda harus dapat mencari gambar dengan id induk yang dimulai dengan f50f9524513f, kemudian mencari gambar anak dari itu , dll .. Tapi .Parent bukan itu yang Anda pikirkan. , jadi dalam banyak kasus Anda perlu menentukan di docker images --allatas untuk membuatnya berfungsi, lalu Anda akan mendapatkan id gambar untuk semua lapisan perantara juga.

Berikut skrip python3 yang lebih terbatas untuk mengurai output buruh pelabuhan dan melakukan pencarian untuk menghasilkan daftar gambar:

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

Jika Anda menyimpan ini seperti desc.pyAnda dapat menjalankannya sebagai berikut:

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

Atau gunakan saja inti di atas , yang melakukan hal yang sama.

Aryeh Leib Taurog
sumber
2
Bagaimana jika tidak ada yang memulai dengan karakter yang diharapkan? Apakah itu menunjukkan kemungkinan bug? Saya menggunakan Docker untuk Mac beta, FWIW, jadi itu tidak akan mengejutkan saya.
neverfox
Entah itu bug, atau itu berarti gambar tersebut tidak memiliki anak.
Aryeh Leib Taurog
2
Ini tidak benar-benar menjawab pertanyaan awal. Ini menunjukkan apa yang dibuat setelah gambar yang dipermasalahkan, yang mungkin tergantung atau tidak tergantung pada gambar yang ingin dihapus poster. Jawaban Simon Brady berhasil, setidaknya untuk ukuran sampel kecil.
penguincoder
2
@penguincoder untuk itulah script python.
Aryeh Leib Taurog
Seperti @neverfox, jawaban ini tidak berhasil untuk saya. Namun, jawaban Simon Brady di bawah ini berhasil.
Tandai
91

Jika Anda tidak memiliki banyak gambar, selalu ada pendekatan brute force:

for i in $(docker images -q)
do
    docker history $i | grep -q f50f9524513f && echo $i
done | sort -u
Simon Brady
sumber
1
Saya pikir ini adalah solusi "terbaik". Anda dapat memperluas ini sedikit dan membuatnya sedikit lebih jelas apa dengan mengubahnya echo $1menjadi yang lebih jelek (tapi masih kasar) docker images | grep $i(lebih portabel dalam versi buruh pelabuhan daripada menggunakan --filterbendera untuk Id Gambar)
Jon V
15

Instal dockviz dan ikuti cabang dari image id di tree view:

go get github.com/justone/dockviz
$(go env GOPATH)/bin/dockviz images --tree -l
mmoya
sumber
lebih baik lakukan sudo apt-get update ; sudo apt-get install golang-go; export GOPATH=$HOME/.godulu.
loretoparisi
3
Tersedia di macOS melaluibrew install dockviz
rcoup
Hati-hati, saat menggunakan Ubuntu. Biasanya menggunakan repositori usang untuk go
Qohelet
7

Saya telah membuat inti dengan skrip shell untuk mencetak pohon turunan dari gambar buruh pelabuhan, jika ada yang tertarik dengan solusi 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
sumber
Meskipun tautan ini mungkin menjawab pertanyaan, lebih baik menyertakan bagian penting dari jawaban di sini dan menyediakan tautan untuk referensi. Jawaban link saja bisa menjadi tidak valid jika halaman tertaut berubah. - Dari Ulasan
Juan Cruz Soler
Saya baru saja mengalami kesulitan dalam memformat kode, jadi saya menyerah, terima kasih telah melakukan ini Jan
Michal Linhard
2

Inilah yang saya lakukan untuk melestarikan "gambar" terakhir saya (lapisan, sungguh - yang membuat saya bingung, karena saya baru saja masuk ke dalam pembuatan buruh pelabuhan).

Saya mendapatkan seluruh pesan "... tidak bisa dipaksa ...". Saya menyadari bahwa saya tidak dapat menghapus gambar yang tidak saya perlukan karena gambar tersebut sebenarnya bukan gambar independen yang dibuat oleh 'docker commit'. Masalah saya adalah, saya memiliki beberapa gambar (atau lapisan) antara gambar dasar dan gambar akhir saya, dan hanya mencoba untuk membersihkan di mana saya menemukan kesalahan / peringatan tentang anak dan orang tua.

  1. Saya mengekspor gambar akhir (atau lapisan, jika Anda mau) ke tarball.
  2. Saya kemudian menghapus semua gambar yang saya inginkan, termasuk gambar akhir saya - saya menyimpannya ke tarball jadi, sementara saya tidak yakin apakah saya akan bisa menggunakannya, saya hanya bereksperimen.
  3. Saya kemudian lari docker image load -i FinalImage.tar.gz. Outputnya seperti ini:

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 gambar yang dimuat: sha256: 82d4f8ef9ea1eab72d989455728762ed3c0fe35fd85acf9edc47b41dacfd6382

Sekarang, ketika saya mendaftar dengan 'docker image ls', saya hanya memiliki gambar dasar asli, dan gambar akhir yang saya simpan sebelumnya ke 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

Sistem saya sekarang 'bersih'. Saya hanya memiliki gambar yang saya inginkan. Saya bahkan menghapus gambar dasar tanpa masalah.

[root@docker1 ~]# docker rmi 36540f359ca3
Untagged: centos:httpd
Untagged:     centos@sha256:c1010e2fe2b635822d99a096b1f4184becf5d1c98707cbccae00be663a9b9131
Deleted: sha256:36540f359ca3b021d4b6a37815e9177b6c2bb3817598979ea55aee7ecc5c2c1f
Jerome Jordan
sumber
Jawaban bagus, tetapi memuat hanya seharusnya digunakan pada gambar yang dibuat dari "docker save". Pemulihan yang tepat untuk "ekspor buruh pelabuhan" adalah "impor buruh pelabuhan"
Amalgovinus
2

Berdasarkan jawaban slushy dan Michael Hoffman , jika Anda tidak memiliki banyak gambar, Anda dapat menggunakan fungsi shell ini:

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

dan kemudian menyebutnya menggunakan

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

Berikut adalah solusi berdasarkan Python API ( pip install docker) yang secara rekursif mencantumkan turunan bersama dengan tag mereka (jika ada), meningkatkan indentasi sesuai dengan kedalaman hubungan (anak, cucu, dll.):

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

Contoh:

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

Saya telah membuatnya tersedia sebagai intinya di https://gist.github.com/simleo/10ad923f9d8a2fa410f7ec2d7e96ad57

simleo
sumber
1

Berikut cara sederhana untuk mendapatkan daftar gambar anak yang bergantung pada gambar induk:

image_id=123456789012

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

Itu akan menghasilkan daftar ID gambar anak / induk, misalnya (dipotong agar singkat):

sha256:abcdefghijkl sha256:123456789012

Sisi kiri adalah ID gambar anak, sisi kanan adalah ID gambar induk yang kita coba hapus, tetapi dikatakan "gambar memiliki gambar anak dependen". Ini memberitahu kita bahwa itu abcdefghijkladalah anak yang menjadi tanggungan 123456789012. Jadi kita perlu dulu docker rmi abcdefghijkl, baru kamu bisa docker rmi 123456789012.

Sekarang, mungkin ada rangkaian gambar anak yang bergantung, jadi Anda mungkin harus terus mengulang untuk menemukan anak terakhir.

bijak
sumber
0

Anda dapat menghapus image Docker terlepas dari relasi induk dan anak melalui direktori Docker di bawah ini

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

Di direktori ini Anda dapat menemukan gambar Docker, sehingga Anda dapat menghapus apa yang Anda inginkan.

Jvn
sumber
Saya mencoba membuat perintah portabel menggunakan API buruh pelabuhan, dengan asumsi pemeta perangkat dan mesin buruh pelabuhan (sebagai lawan dari kelompok buruh pelabuhan misalnya) menjadikan ini solusi non portabel. Juga berisiko untuk menghapus file dalam sistem file sementara proses lain (termasuk daemon buruh pelabuhan) dapat menggunakannya.
nicocesar
di mana itu di macos?
Anthony Kong
1
* PERINGATAN "ini dapat menyebabkan banyak kesalahan dengan menghapus dan menarik kontainer di masa mendatang. Jangan pernah menghapus direktori /var/lib/dockersecara langsung dengan tangan
vladkras
0

Bagaimana tentang:

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)

Ini akan mencetak id gambar anak, dengan sha256:awalan.
Saya juga memiliki yang berikut ini, yang menambahkan nama:

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

  • ID= Mendapatkan id penuh dari gambar
  • IMAGES= Mendapatkan semua gambar anak yang memiliki gambar ini terdaftar sebagai file Image
  • echo... Menghapus duplikat dan menggemakan hasilnya
Justin
sumber
Saya suka kondisional format Go, tapi mungkin mereka lebih baik sebagai filter untuk kasus penggunaan ini.
ingyhere
0

Saya membuat ini untuk secara rekursif menemukan anak-anak, tag repo mereka, dan mencetak apa yang mereka lakukan:

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
}

Jangan lupa untuk menghapus / tmp / dii- * jika host Anda tidak aman.

android.weasel
sumber
-5

Saya juga menghadapi masalah yang sama. Langkah-langkah bera di bawah ini untuk menyelesaikan masalah.

Hentikan semua kontainer yang sedang berjalan

buruh pelabuhan stop $ (buruh pelabuhan ps -aq) Hapus semua kontainer

docker rm $ (docker ps -aq) Hapus semua gambar

buruh pelabuhan rmi $ (gambar buruh pelabuhan -q)

Ram Pasupula
sumber
jawaban ini tidak memenuhi persyaratan penanya.
Ankur Loriya
Harap berhenti mengomentari hal-hal yang berpotensi disalin & ditempel oleh orang lain dan melakukan hal-hal berbahaya.
nicocesar