Automatically Building Docker Containers With Different Base Image Tags

Posted on Wed 20 April 2016 in blog

At work I recently added a Dockerfile to one of our accessory tools, and set it up with Jenkins to build on a nightly basis. This build occurs nightly as opposed to on new master commits to ensure that the resulting container always has the latest versions of all its dependencies (including node).

I wrote the Dockerfile such that we were building off of the official node containers. Specifically, off of the latest tag. Here is what I mean:

FROM node:latest

RUN some-stuff

This would ensure that I was always using the latest node version every night, which is exactly what I wanted. Perfect!

A few weeks later as news of the container made its way around the devs, I was asked to provide a build of the tool that uses the latest LTS node release instead of the latest-latest release. I should be able to do that, no problem. On Docker Hub there is a node tag named argon, which corresponds to the latest build of the current LTS branch (currently node 4.4.3). So my challenge was to provide two identical containers with only the node version changed between them.

I first considered using the Docker --build-arg flag with a corresponding ARG line in the Dockerfile. Typically this is used in the following way:

FROM ubuntu

ARG myvar

RUN apt-get install ${myvar}

And then built like so:

$ docker build --build-arg myvar=value -t container-name .

But of course, I wanted to use this build argument in the FROM line. So first I tried this:

ARG tag

FROM node:${tag}

RUN some-stuff

But that isn't going to work. The first line in every Dockerfile must be a FROM statement.

What I instead decided to do (and settled on) was to instead use a file I named Dockerfile-template, and then use the unix tool sed to generate the actual Dockerfile one at a time. Here is what that looked like:

FROM node:TAG

RUN some-stuff

And the scrubbed bash script that was run by Jenkins:

#!/bin/bash
TAGS="latest:argon"

for tag in ${tags//:/ }; do
    sed 's/TAG/'"${tag}"'/' Dockerfile-template > Dockerfile
    docker build --no-cache -t container-name:${tag} .
    docker push container-name:${tag}
    docker rmi container-name:${tag}
done

So now I'm providing nightly rebuilds of the internal tool, one with tag latest and one with tag argon, each corresponding to what version of node it was built with!