จะรับรายการอิมเมจลูกที่ต้องพึ่งพาใน 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

ฉันจะรับภาพเด็กที่อ้างว่ามีได้อย่างไร

ไม่มีคอนเทนเนอร์ที่ทำงานหรือหยุดทำงานด้วยรหัสรูปภาพนั้น


9
ฉันต้องสงสัยว่าทำไมทีมนักเทียบท่าจึงไม่สามารถจัดหาวิธีดั้งเดิมในการทำเช่นนี้ได้?
Amalgovinus

คำตอบ:


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
นี่ไม่ได้ตอบคำถามเดิมจริงๆ สิ่งนี้แสดงถึงสิ่งที่สร้างขึ้นหลังจากภาพที่เป็นปัญหาซึ่งอาจจะขึ้นอยู่กับภาพที่ผู้โพสต์พยายามลบหรือไม่ก็ได้ คำตอบของ Simon Brady เป็นเคล็ดลับสำหรับภาพตัวอย่างอย่างน้อยขนาดเล็ก
penguincoder

2
@penguincoder นั่นคือสิ่งที่สคริปต์ python มีไว้สำหรับ
Aryeh Leib Taurog

เช่นเดียวกับ @neverfox คำตอบนี้ไม่ได้ผลสำหรับฉัน คำตอบของ Simon Brady ด้านล่างใช้งานได้จริง
ทำเครื่องหมาย

91

หากคุณไม่มีภาพจำนวนมากมักมีวิธีการบังคับที่ดุร้าย:

for i in $(docker images -q)
do
    docker history $i | grep -q f50f9524513f && echo $i
done | sort -u

1
ฉันคิดว่านี่เป็นทางออกที่ "ดีที่สุด" คุณสามารถขยายสิ่งนี้ได้เล็กน้อยและทำให้ชัดเจนขึ้นเล็กน้อยว่าอะไรคืออะไรโดยการเปลี่ยนเป็นecho $1uglier (แต่ยังคงดุร้าย) docker images | grep $i(พกพาได้มากกว่าในเวอร์ชันนักเทียบท่ามากกว่าการใช้--filterแฟล็กสำหรับ Image 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 โดยปกติจะใช้ที่เก็บที่ล้าสมัยไปแล้ว
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" ""

แม้ว่าลิงก์นี้อาจตอบคำถามได้ แต่ควรรวมส่วนสำคัญของคำตอบไว้ที่นี่และระบุลิงก์เพื่อการอ้างอิง คำตอบแบบลิงก์เท่านั้นอาจไม่ถูกต้องหากหน้าที่เชื่อมโยงเปลี่ยนไป - จากรีวิว
Juan Cruz Soler

ฉันมีปัญหาในการจัดรูปแบบรหัสดังนั้นฉันจึงยอมแพ้ขอบคุณที่ทำในเดือนมกราคมนี้
Michal Linhard

2

นี่คือสิ่งที่ฉันทำเพื่อรักษา "ภาพ" สุดท้ายของฉัน (เลเยอร์จริงๆ - ซึ่งเป็นสิ่งที่ทำให้ฉันผิดหวังในขณะที่ฉันเพิ่งเริ่มสร้างนักเทียบท่า)

ฉันได้รับข้อความ "... ไม่สามารถบังคับ ... " ทั้งหมด ฉันรู้ว่าฉันไม่สามารถลบภาพที่ฉันไม่ต้องการได้เพราะมันไม่ใช่ภาพที่สร้างขึ้นโดย 'นักเทียบท่า' ปัญหาของฉันคือฉันมีหลายภาพ (หรือเลเยอร์) ระหว่างภาพพื้นฐานและภาพสุดท้ายของฉันและเพียงแค่พยายามทำความสะอาดคือที่ที่ฉันพบข้อผิดพลาด / คำเตือนเกี่ยวกับเด็กและผู้ปกครอง

  1. ฉันส่งออกภาพสุดท้าย (หรือเลเยอร์ถ้าคุณต้องการ) ไปยัง tarball
  2. จากนั้นฉันก็ลบภาพทั้งหมดที่ฉันต้องการรวมถึงภาพสุดท้ายของฉัน - ฉันได้บันทึกไว้ใน tarball ดังนั้นในขณะที่ฉันไม่แน่ใจว่าจะสามารถใช้งานได้หรือไม่ฉันก็แค่ทดลอง
  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' ฉันมีเพียงภาพฐานดั้งเดิมและภาพสุดท้ายที่ฉันเคยบันทึกไว้ใน 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

ระบบของฉันตอนนี้ 'สะอาด' ฉันมีเพียงภาพที่ฉันต้องการ ฉันยังลบภาพพื้นฐานโดยไม่มีปัญหา

[root@docker1 ~]# docker rmi 36540f359ca3
Untagged: centos:httpd
Untagged:     centos@sha256:c1010e2fe2b635822d99a096b1f4184becf5d1c98707cbccae00be663a9b9131
Deleted: sha256:36540f359ca3b021d4b6a37815e9177b6c2bb3817598979ea55aee7ecc5c2c1f

คำตอบที่ดี แต่ควรใช้โหลดกับภาพที่สร้างจาก "docker save" เท่านั้น การกู้คืนที่เหมาะสมสำหรับ "นักเทียบท่าส่งออก" คือ "นักเทียบท่านำเข้า"
Amalgovinus

2

จากคำตอบเฉอะแฉะและMichael Hoffmanหากคุณไม่มีรูปภาพจำนวนมากคุณสามารถใช้ฟังก์ชันเชลล์นี้ได้:

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


1

วิธีง่ายๆในการรับรายการภาพย่อยที่ขึ้นอยู่กับอิมเมจหลักมีดังนี้

image_id=123456789012

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

ซึ่งจะสร้างรายการ ID อิมเมจลูก / พาเรนต์ตัวอย่างเช่น (ตัดทอนเพื่อความกะทัดรัด):

sha256:abcdefghijkl sha256:123456789012

ด้านซ้ายคือรหัสภาพย่อยด้านขวาคือรหัสภาพหลักที่เราพยายามลบ แต่มีข้อความว่า "ภาพมีภาพย่อยขึ้นอยู่กับ" นี้บอกเราว่าเป็นเด็กที่จะขึ้นอยู่กับabcdefghijkl 123456789012ดังนั้นเราจึงต้องแรกแล้วคุณสามารถdocker rmi abcdefghijkldocker rmi 123456789012

ตอนนี้อาจมีภาพลูกที่ขึ้นอยู่กับลูกโซ่ดังนั้นคุณอาจต้องทำซ้ำเพื่อค้นหาลูกคนสุดท้าย


0

คุณสามารถลบอิมเมจ Docker โดยไม่คำนึงถึงความสัมพันธ์ของผู้ปกครองและเด็กผ่านไดเร็กทอรีด้านล่างของ Docker

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

ในไดเร็กทอรีนี้คุณสามารถค้นหาอิมเมจ Docker ได้ดังนั้นคุณจึงสามารถลบสิ่งที่คุณต้องการได้


ฉันกำลังพยายามสร้างคำสั่งแบบพกพาโดยใช้ docker API โดยสมมติว่าผู้ทำแผนที่อุปกรณ์และนักเทียบท่าเอ็นจิ้น (เมื่อเทียบกับกลุ่มนักเทียบท่า) ทำให้วิธีนี้ไม่ใช่โซลูชันแบบพกพา นอกจากนี้ยังมีความเสี่ยงที่จะลบไฟล์ในระบบไฟล์ในขณะที่กระบวนการอื่น ๆ (รวมถึง Docker daemon) อาจใช้งานได้
nicocesar

มันอยู่ที่ไหนบน macos?
Anthony Kong

1
* คำเตือน "อาจทำให้เกิดข้อผิดพลาดหลายครั้งในการลบและดึงคอนเทนเนอร์ในอนาคตอย่าลบ dirs /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 แต่บางทีมันอาจจะดีกว่าสำหรับตัวกรองสำหรับกรณีการใช้งานนี้
นี่

0

ฉันปรุงสิ่งนี้เพื่อค้นหาเด็กซ้ำแท็ก repo ของพวกเขาและพิมพ์สิ่งที่พวกเขากำลังทำ:

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- * หากโฮสต์ของคุณไม่ปลอดภัย


-5

ฉันก็ประสบปัญหาเดียวกัน ขั้นตอนล้มเหลวด้านล่างเพื่อแก้ไขปัญหา

หยุดการทำงานของคอนเทนเนอร์ทั้งหมด

docker stop $ (docker ps -aq) ลบคอนเทนเนอร์ทั้งหมด

นักเทียบท่า rm $ (นักเทียบท่า ps -aq) ลบภาพทั้งหมด

นักเทียบท่า rmi $ (ภาพนักเทียบท่า -q)


คำตอบนี้ไม่ตรงตามข้อกำหนดของผู้ถาม
Ankur Loriya

โปรดหยุดแสดงความคิดเห็นเกี่ยวกับสิ่งที่ผู้คนอาจคัดลอกและวางและทำสิ่งที่เป็นอันตราย
nicocesar
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.