I’ve been creating a lot of Docker images for a project I’m working on. A number of those images are just being used to support working through a book on Flask: Flask Web Development, by Miguel Grinberg.

The list of Docker images on my development machine is getting really long. I wanted some way to filter the list so I could see only the images pertinent to the book examples I’d been working on. That’s when I discovered that I could assign labels to Docker images. Many labels.

So that’s what I did. I added labels to all the images that I wanted to find in a filtered image list. I added this to the end of my existing Dockerfiles and built the images again.1

The Dockerfile lines looked something like this:

ENV LABEL_EXAMPLE_AT_ 2016-12-04T10:07:50-0600
LABEL net.develves.examples="flask-web-development-book" \
    net.develves.distro="alpine" \
    net.develves.distro-version="alpine 3.4"

Next I wanted to display the labels attached to a given image. You do that using the docker inspect command. But getting the output to show just what I wanted took a bit of work, more than expected, so I documented what I discovered in a TIL2 called “Listing the labels of an image”. That done, I could validate that the images had the labels I was expecting. The command looks something like:

docker inspect --format='{{range $k, $v := .ContainerConfig.Labels}} {{- printf "%s = \"%s\"\n" $k $v -}} {{end}}' datihein/flask-aae

Then I needed to add a --filter argument to the docker images command to list just the images that matched the label or label value I was interested in. Straightforward, but I documented it in a TIL as well, one called “Listing images with a specific label”. That command would look something like this:

docker images --filter "label=net.develves.examples=flask-web-development-book"

Both commands, especially the first, are a bit inconvenient to type. I created a couple Bash functions that make it easier.

dkr_list_image_labels() {
  if [ -z "$1" ]; then
    return 1
  fi
  local tmp_="--format='{{range \$k, \$v := .ContainerConfig.Labels}} "
  tmp_="$tmp_{{- printf \"%s = \\\"%s\\\"\\n\" \$k \$v -}} {{end}}'"
  docker inspect "${tmp_}" "$1"
}

dkr_list_images() {
  if [ -z "$1" ]; then
    docker images
  else
    docker images --filter "label=$1"
  fi
  return 0
}

I add those to my Bash profile so I can invoke them from the command line. Here is some sample output:

~$ dkr_list_image_labels datihein/flask-aaa
net.develves.distro = "alpine"
net.develves.distro-version = "alpine 3.4"
net.develves.examples = "flask-web-development-book"

~$ dkr_list_images net.develves.examples=flask-web-development-book
REPOSITORY                                TAG                 IMAGE ID            CREATED             SIZE
datihein/flask-aaf                        latest              0eec6ff5fed1        2 minutes ago       199.9 MB
datihein/flask-aae                        latest              067e7a915e5a        2 minutes ago       196.7 MB
datihein/flask-aad                        latest              5719a84f5042        2 minutes ago       183.6 MB
datihein/flask-aac                        latest              486574196f96        2 minutes ago       182.4 MB
datihein/flask-aab                        latest              1cfcd535c129        3 minutes ago       182.4 MB
datihein/flask-aaa                        latest              23cfa2e04caa        5 minutes ago       180.1 MB
datihein/python3.5.2-flask-nginx-alpine   latest              8e9899e6db86        About an hour ago   179.9 MB
datihein/rsync-alpine                     latest              055300a919e7        3 hours ago         11.19 MB
~$

You could also just specify the label key, e.g. dkr_list_images net.develves.examples, and that would show all the images with that label key, regardless of the label value.

Oh, and if you are rebuilding a bunch of images to add labels then you’ll end up with a lot of orphaned images and intermediate images. You can clean them up with this Bash function:

# found this nice image/container cleanup script here:
# http://stackoverflow.com/a/32723127/1392864
#
dkr_cleanup_unused() {
  docker rm -v $( docker ps --filter status=exited -q 2> /dev/null ) 2> /dev/null
  docker rmi $( docker images --filter dangling=true -q 2> /dev/null ) 2> /dev/null
}

I did a TIL about that a while back; it’s called “Remove orphaned images”

  1. Fortunately I understood the dependency tree of the images and built them up in the proper sequence. Some tool to manage a rebuild of images would probably be helpful here. One may exist; I haven’t looked.

  2. TIL is an acronym for “Today I Learned”. One maintains a collection of small, useful learnings; each item in the collection is referred to as a “TIL”. See the introductory post on TILs.