1. Overview

In this tutorial, we’ll learn how to get the list of dependent child images in Docker. First, we’ll see when to seek such information. Then, we’ll retrieve it depending on the Docker builder we use.

2. Motivation

When a Docker image is built off of another one, the former is called the child and the latter parent.

It’s often helpful to get all child images of a given parent, especially when Docker prevents the removal of a parent:

$ docker rmi 645c04d243f1  
Failed to remove image (a3550c143d4e): Error response from daemon: conflict: unable to delete a3550c143d4e (cannot be forced) - image has dependent child images

Here, Docker urges us to remove child images of parent a3550c143d4e. Bypassing the error with the –force flag won’t do much. That’s why finding those child images becomes crucial. We’ll resolve this error in the following sections.

Finding the dependent child images of a parent image depends on the Docker builder used. Since Docker Desktop and Docker Engine 23.0, BuildKit is the new and default builder for Linux images. The previous versions used the legacy builder. We’ll distinguish between those two builders.

3. Using Docker Legacy Builder

The legacy builder is the default one on Docker versions lower than 23.0. Regardless, we can opt for it by deactivating BuildKit with DOCKER_BUILDKIT=0. 

Let’s reproduce the error in the previous section.

3.1. Case Study

First, we’ll define a parent image:

$ DOCKER_BUILDKIT=0 docker build -t parent -<<EOF
FROM scratch
LABEL kind=parent
EOF

It’s important to note that the legacy builder will be removed in future releases:

DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
            BuildKit is currently disabled; enable it by removing the DOCKER_BUILDKIT=0
            environment-variable.

We need to keep that warning in mind and be prepared to migrate to BuildKit.

Next, let’s create a child image based on parent:

$ DOCKER_BUILDKIT=0 docker build -t child -<<EOF
FROM parent:latest
LABEL kind=child
EOF

Now that we have everything in place, let’s retrieve the parent ID:

$ docker images ls --filter reference=parent
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
parent       latest    a3550c143d4e   4 minutes ago   0B

We’ll face the initial error when attempting parent deletion:

$ docker rmi 645c04d243f1  
Failed to remove image (a3550c143d4e): Error response from daemon: conflict: unable to delete a3550c143d4e (cannot be forced) - image has dependent child images

This is due to the way the legacy builder works. It caches images used to build others and prevents their deletion. That information is kept in the Parent metadata of the child image:

$ docker inspect --format '{{json .Parent}}' child
"sha256:a3550c143d4e25331167344afeb842b21780ef7d3f20dabe748390d89c16cf8b"

The legacy builder keeps track of the parent. We’ll use this information to get dependent child images based on the parent image ID.

3.2. Getting Dependent Child Images

Let’s create a get_children_of.sh script to get the dependent child images:

#!/bin/sh
set -e
parent=$1
echo "Dependent Child IDs of $parent "
docker inspect --format='{{.Id}} {{.Parent}}' $(docker images --all --quiet --filter since=$parent) \
awk -v parent=$parent '{ if($2 == parent) print $1 }'

Let’s break down what’s going on. First, the script takes the parent image ID as a parameter. Next, we list all images built after the parent:

docker images --all --quiet --filter since=$parent

The –all flag is important to list even hidden images. The –quiet flag only shows image IDs. Following, we inspect those images’ metadata:

docker inspect --format='{{.Id}} {{.Parent}}' 

The result of the docker images command is used as an argument for docker inspect. We narrowed the output format to only get the child image ID and the parent ID. Moving on, we print the dependent child images using awk:

awk -v parent=$parent '{ if($2 == parent) print $1 }'

Here, the conditional check is critical to only print the children of the relevant parent ID.

Finally, the script gets us the dependent child images of our parent image a3550c143d4e:

$ ./get_children_of.sh sha256:a3550c143d4e25331167344afeb842b21780ef7d3f20dabe748390d89c16cf8b
Dependent Child IDs of sha256:a3550c143d4e25331167344afeb842b21780ef7d3f20dabe748390d89c16cf8b 
sha256:ddfecb5979b759ff56c1a730e5fc957e963cfd5bbe2108c72244b65182857bab

It’s imperative to pass the long-form ID to the script. We can retrieve it by passing the –no-trunc flag when describing the parent image:

$ docker images ls --filter reference=parent --no-trunc
REPOSITORY   TAG       IMAGE ID                                                                  CREATED          SIZE
parent       latest    sha256:a3550c143d4e25331167344afeb842b21780ef7d3f20dabe748390d89c16cf8b   40 minutes ago   0B

Having those child image IDs, we can remove them to solve our initial error.

4. Using BuildKit

BuildKit has been the default Docker builder for Linux images since version 23.0. It comes with many improvements from the legacy builder.

Particularly, it doesn’t cache parent images. This implies that we won’t face the error we saw earlier when we used BuildKit.

Let’s activate Buildkit in our previous case study with DOCKER_BUILDKIT=1. Another way to achieve it is by updating the Docker daemon configuration in /etc/docker/daemon.json:

{
    "features":{
        "buildkit":true
    }
}

Now let’s recreate the parent and child images. First, we’ll define the parent image:

$ DOCKER_BUILDKIT=1 docker build -t parent -<<EOF
FROM scratch
LABEL kind=parent
EOF

Next, let’s create the child image based on parent:

$ DOCKER_BUILDKIT=0 docker build -t child -<<EOF
FROM parent:latest
LABEL kind=child
EOF

We’ll immediately notice that we can’t retrieve any information about the parent image from the child image:

$ docker inspect --format '{{json .Parent}}' child
 ""

BuildKit doesn’t set the Parent field. Removing the parent image doesn’t cause any errors.

$ docker rmi sha256:a3550c143d4e25331167344afeb842b21780ef7d3f20dabe748390d89c16cf8b
Untagged: parent:latest
Deleted: sha256:a3550c143d4e25331167344afeb842b21780ef7d3f20dabe748390d89c16cf8b

Regardless of the builder, we can always remove dangling and unused images from the system:

$ docker image prune --all --force

The –force flag is useful when we don’t need confirmation.

5. Conclusion

In this article, we saw how to get the list of dependent child images in Docker. First, we discussed the main use case for it. Then, we learned how to achieve the result depending on the Docker builder in use.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.