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.