使用docker可以确定哪些图像依赖于另一个图像


4

随着docker我可以找出所有命名和标记的集装箱,docker images其中列出了出来。

我可以找出给定图像使用的其他图像,docker inspect --format '{{.RootFS.Layers}}' _imageId_并且通过手动比较SHA可以看到图像B使用图像A。

有什么办法可以让docker告诉我或使用bash(或可移植外壳)脚本来查找依赖于给定图像的所有命名图像。例如,在此示例中,当我根据A搜索图像时,将返回B。

我一直没有成功搜索docker帮助输出,在线docker文档,google和SE,SO,SU来寻找现有的替代方案来手动发现依赖关系。

Answers:


1

如问题中所述,似乎没有内置的方法可以做到这一点。以下docker-find-dependants脚本在此处维护并完成工作

#!/bin/bash

# Script to determine what named images and containers are dependent on the specified image (or a containers image) from stdin or in the args
# An unmatchable input is ignored
# All of the following will be found:
#    Any image name / tag / name:tag / id that has a prefix in it that matches the input
#    Any other image that relies on the images specified
#    Any containers (running or not) that use any of these images

set -euf -o pipefail

debugMsg() {
    true
    #printf "%s\n" "$@" >&2
}


specifiedParents=""
# Find all the images that need to be removed
if [ "$#" -ge "1" ]; then
    # Images for removal in args
    specifiedParents="$(printf " %s\n" "$@")"
else
    # Images for removal to arrive via stdin
    while IFS= read -r inStr; do
        if [ -n "$inStr" ]; then
            specifiedParents="$(printf "%s %s\n" "$specifiedParents" "$inStr")"
        fi
    done
fi
debugMsg "DBG:1 specifiedParents = '$specifiedParents'"

# Check there is some input
if [ -z "$specifiedParents" ]; then
    printf "%s" "Nothing specified to search for; images/containers must be specified as either args or on the stdin" >&2 
    exit 1
fi

# Collect the container and image info
containersData="$(docker ps -a --format 'Container {{.ID}} {{.Image}} {{.Names}} {{.Labels}}' --no-trunc)"
allImagesData="$(docker images -a --format 'Image {{.ID}} {{.Repository}}:{{.Tag}} {{.Repository}} {{.Tag}}' --no-trunc | sed 's/ [^:]*:/ /')"
namedImagesData="$(docker images --format 'Image {{.ID}} {{.Repository}}:{{.Tag}}' --no-trunc | sed 's/ [^:]*:/ /')"
debugMsg "DBG:2 containersData = '$containersData'"
debugMsg "DBG:3 allImagesData = '$allImagesData'"
debugMsg "DBG:4 namedImagesData = '$namedImagesData'"

# Check to see if you can find a matching container
parents=""
while IFS= read -r aParent; do
    if [ -z "$aParent" ]; then
        continue
    fi

    # Use space to ensure matching starts at the beginning of a field
    anImageId=" $(printf "%s" "$containersData" | grep -F " $aParent" | awk '{print $3}' || true)"
    if [ "$anImageId" != " " ]; then
        # A container matched so use the image ID
        parents="$(printf "%s%s\n" "$parents" " $anImageId")"
    else
        # Not a container, so presumably an image
        parents="$(printf "%s%s\n" "$parents" " $aParent")"
    fi
done <<< $(printf "%s\n" "$specifiedParents") # Performing while inside this shell
#debugMsg "DBG:5 parents = '$parents'"

# Get the full parent image ID's
parentImageIds=""
while IFS= read -r aParent; do
    debugMsg "DBG:6 aParent = '$aParent'"
    # Find anything matching the parent and get it's full ID
    while IFS= read -r parentImageId; do
        if [ -z "$parentImageId" ]; then
            continue
        fi
        debugMsg "DBG:7 parentImageId = '$parentImageId'"
        # Add the full ID to the parentImageIds, including a space to assist matching later
        parentImageIds="$(printf "%s%s\n" "$parentImageIds" " $parentImageId")"
    done <<< $(printf "%s" "$allImagesData" | grep -F " $aParent" | awk '{print $2}')
done <<< $(printf "%s" "$parents") # Performing while inside this shell
debugMsg "DBG:8 parentImageIds = '$parentImageIds'"

# Stop if there are no parents
if [ -z "$parentImageIds" ]; then
    exit 0
fi

# Deduplicate
parentImageIds="$(printf "%s" "$parentImageIds" | LC_ALL=C sort -u)"
debugMsg "DBG:9 parentImageIds = '$parentImageIds'"

# Find descendent images
descendentImages=""
while IFS= read -r imageData; do
    anImageId="$(printf "%s" "$imageData" | awk '{print $2}')"

    # Check to see if this ID is a descendent of parentImageIds by imageInfo by moving through it's lineage
    areDescendents=""
    imageIdsChecked=""
    while true; do
        # Record that anImageId is being checked; including the space at the start to assist matching later
        imageIdsChecked="$(printf "%s%s\n" "$imageIdsChecked" " $anImageId")"

        if printf "%s" "$descendentImages" | grep -q -F "$anImageId"; then
            # Already determined that anImageId is a descendent of parentImageIds so TheImage is too
            areDescendents="true"
            break;
        else
            if printf "%s" "$parentImageIds" | grep -q -F " $anImageId"; then
                # TheImage is a descendent of parentImageIds
                areDescendents="true"
                break;
            fi

            # Move onto the parent of anImageId
            anImageId="$(docker inspect --format '{{.Parent}}' "$anImageId" | sed 's/.*://')"
            if [ -z "$anImageId" ]; then
                # Reached the end of the line; abandon all hope ye who enter here
                break;
            fi
        fi
    done

    # Add descendents to the descendentImages
    if [ -n "$areDescendents" ]; then
        descendentImages="$(printf "%s%s\n" "$descendentImages" "$imageIdsChecked")"
    fi
done <<< $(printf "%s" "$allImagesData") # Performing while inside this shell
debugMsg "DBG:10 descendentImages = '$descendentImages'"

checkIfDescendentImageFound() {
    # Check to see if this is a descendent from any parent
    # $1 is thisImageId
    # $2 is the display text
    # Using the space to ensure matching form the start of an ID
    if printf "%s" "$descendentImages" | grep -q -F " $1"; then
        # We've found a descendent; display it quick before it gets away
        debugMsg "DBG: Found "
        printf "%s\n" "$2"
    fi
}

# Identify any named images that are descendents of the parentImageIds
debugMsg "DBG:11 namedImagesData = '$namedImagesData'"
printf "%s\n" "$namedImagesData" | while IFS= read -r imageData; do
    thisImageId="$(printf "%s" "$imageData" | awk '{print $2}')"
    checkIfDescendentImageFound "$thisImageId" "$imageData"
done

# Identify containers that rely on images that are descendents of the parentImageIds
debugMsg "DBG:12 containersData = '$containersData'"
printf "%s\n" "$containersData" | while IFS= read -r containerData; do
    thisImageId="$(printf "%s" "$containerData" | awk '{print $3}')"
    checkIfDescendentImageFound "$thisImageId" "$containerData"
done

例:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                 CREATED             STATUS              PORTS               NAMES
f89b835ae7a0        96c117cf0a5e        "/bin/sleep infinity"   12 hours ago        Up 12 hours                             test
$ docker images -a
REPOSITORY          TAG                   IMAGE ID            CREATED             SIZE
golang-build        2017-03-09T05-46GMT   96c117cf0a5e        39 hours ago        293 MB
<none>              <none>                752877a5f5b1        39 hours ago        293 MB
<none>              <none>                cb1c86494369        39 hours ago        3.98 MB
alpine              latest                4a415e366388        7 days ago          3.98 MB
$ docker-find-dependants blah
$ docker-find-dependants 752877a5f5b1
Image 96c117cf0a5ef75c6203f862ec92ae75418c1a431d86440dd71b945e5fdbff77 golang-build:2017-03-09T05-46GMT
Container f89b835ae7a08e0394c080d0e57de2020f6a9c6dd334bc078913171d4171962f 96c117cf0a5e test 

如果有人比这个脚本有一个更优雅的答案,我将有兴趣看到它(而且我敢肯定其他人也会如此)
RidiculousRichard

请注意,虽然'docker ps -f ancestor = xxxx'有效,但没有适用于'docker images'的祖先过滤器。还应注意,通过在脚本中执行此操作,您可以选择以特定方式对图像进行排序。
RidiculousRichard
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.