Setting up automated Docker image builds is a widely publicised process, but ensuring that only a single image is created when multiple tags are required, is not such a well known thing. Read on to find out how to do this.

A Docker Hub automated build is a mechanism for automatically creating Docker images based on code changes pushed to a web-hosted source code management system (SCM). The Docker Hub can be linked to accounts on GitHub or Bitbucket, whose repositories can be the target for automated builds, provided a Dockerfile exists within the repository. There are numerous benefits associated with automated builds; published images are automatically kept in sync with code changes, image consumers can attach some credence to the image integrity through inspection of the Dockerfile, and so on.

The automated build is governed by build rules, which specify the branch or tag in the remote SCM repository, the location of the Dockerfile within that context, and a corresponding tag to be used for the new Docker image. For example, if we were building a Docker image for the Ubuntu OS based on the most recent LTS version, we might create a Docker Hub repository called ubuntu linked to a corresponding, remote SCM repository which contains the build context, and define a build rule, thus:

When the automated build is triggered via a change in the remote repository, the Docker Hub clones the remote repository, performs a build based on the contents of the build context, and then tags the image with the supplied Docker image tag, xenial, before pushing the image to the relevant repository.

This is all very straightforward. Sometimes, however, it's convenient to create an image that contains multiple tags. In the above example, we might want to have the following tags: xenial, 16.04, and latest. These tags are all valid descriptions of the same image. To achieve this, we could provide multiple build rules, each using the same branch or tag, but each with a unique Docker tag. There is a problem with this approach, however. Instead of producing one image with three different tags, the automated build creates three identical images, each with a different tag. Whilst this serves the purpose of providing multiple tags, it is very inefficient, as three images are created rather then one, and it could be very confusing to the image consumer. This is a known limitation of the Docker Hub, which will hopefully get resolved one day, but in the meantime there is a workaround.

The workaround involves the use of a post push hook, which triggers a user-defined script. The script can contain Docker CLI commands, such as docker tag, which is used to create a tag for an existing image, and docker push for pushing the additional tag to the Docker Hub repository. A variable, IMAGE_NAME, can be referenced for use in the script, which is set to the Docker image name derived from the build rule. The script must be called post_push, and it must reside in a directory called hooks at the root of the build context. A simple script to ensure we get the 16.04 and latest tags in addition to the xenial tag specified in the build rule, might look like this:

#!/bin/bash

set -e

# Parse image name for repo name
tagStart=$(expr index "$IMAGE_NAME" :)  
repoName=${IMAGE_NAME:0:tagStart-1}

# Tag and push image for each additional tag
for tag in {16.04,latest}; do  
    docker tag $IMAGE_NAME ${repoName}:${tag}
    docker push ${repoName}:${tag}
done  

In the example, when an automated build is triggered, an image is built based on the build rule, which results in an image being created with the name joe/ubuntu:xenial (assuming the Docker Hub user is joe), which is then pushed to the Docker Hub. Immediately following this, courtesy of the post push script, that same image is tagged with 16.04 and latest, before the tags are pushed to the Docker Hub. One image, three different tags.

This is an undocumented feature of the Docker Hub, but looks very similar in form to the Docker Cloud autobuild and autotest features. The Docker Cloud autobuild and autotest processes have numerous environment variables available for hook execution (over and above IMAGE_NAME), which are also available for automated builds on the Docker Hub. The Docker Hub automated build logs also report Building in Docker Cloud's infrastructure..., which further suggests that what is documented for Docker Cloud autobuild and autotest, also applies for Docker Hub automated builds. Do remember, however, that in the context of the Docker Hub, this is undocumented, unsupported and should be used with caution.