Remove all Docker images without containers or child images, even if they're tagged

Jos*_*ica 7 docker

I want to clean up all of my Docker images that aren't being used, directly or indirectly, by my current containers. Docker provides the docker image prune command for this, but I can't get it to remove exactly what I want. If I use that command without -a, it removes too little: it leaves behind all tagged images, even if no container uses them. If I use that command with -a, it removes too much: it removes images that are parents of images that aren't being removed. Here's a table explaining the problem:

Used by container | Has child image | Has tag | Removed without -a | Removed with -a | I want to remove
Yes               | Yes/No          | Yes/No  | No                 | No              | No
No                | Yes             | Yes/No  | No                 | Yes             | No
No                | No              | Yes     | No                 | Yes             | Yes
No                | No              | No      | Yes                | Yes             | Yes
Run Code Online (Sandbox Code Playgroud)

Is there some other flag for this command (such as something with --filter), or some other command or sequence of commands, that lets me remove just what I want to remove?

EDIT: David Maze points out in the comments that the images I'm referring to are merely being untagged, not removed entirely. Given that, here's an updated phrasing of the question: How can I make docker image prune -a not untag images that it's not actually going to remove?

Rei*_*ica 2

我经常想知道同样的事情,所以我想出了这个解决方案:

# create unique array of image ids (including all descendants) used by running containers
get_active_image_history()
{
    for image_name in $(docker ps --format={{.Image}})
    do
        docker history -q $image_name
    done | sort -u
}

# iterate over each image id in your system, and output the ids that should be deleted
# conceptually similar to an intersection of two arrays
get_unused_image_ids()
{
    image_history=$(get_active_image_history)
    for image_id in $(docker image ls -q)
    do
        if [[ ! "${image_history[@]}" =~ "${image_id}" ]]; then
            echo "$image_id"
        fi
    done  | sort -u
}

docker_clean()
{
    image_ids=$(get_unused_image_ids)
    if [ -z "$image_ids" ]; then
        >&2 echo "Error: no unused images found"
        return 1
    fi

    if [[ "$1" = "-y" ]]; then
        echo y | docker container prune > /dev/null
        docker image rm $(get_unused_image_ids)
        return 0
    fi

    echo -e "Warning! this will remove all stopped containers, and the following images:\n"
    image_ids=$(get_unused_image_ids)
    echo "REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE"
    docker image ls | grep "$image_ids"
    echo
    read -p "Continue (y/n)?" cont
    if [ "$cont" = "y" ]; then
        echo y | docker container prune > /dev/null
        docker image rm $image_ids
    else
        echo "aborting..."
    fi
}
Run Code Online (Sandbox Code Playgroud)

不是很优雅,但它足以在开发中使用。您可以传递一个-y标志来消除警告提示。

我遇到过几种情况,提示错误地显示了当前使用的图像,并试图将其删除,但随后被 docker 守护进程捕获,从而导致类似于以下的误导性噪音:

Error response from daemon: conflict: unable to delete <image id> (must be forced) -
image is being used by stopped container <container id>
Run Code Online (Sandbox Code Playgroud)

在所有情况下,仅删除正确的图像,但这可能会因您的系统而异。青年MMV

太长了;不安全生产