If you’re a bit like me, you

  • like to automate stuff;
  • you hate to duplicate stuff.

With those two things in mind, together with the desire to use artifact on my projects, I decided that I would need a Docker image in order for art to generate it’s web page files on GitLab CI.

This post can be applied to anything versioned you’d like to build Docker images from, so you don’t need to learn art if you don’t want.

If you’re curious about the result, just visit the relevant GitHub repository, which gets mirrored to GitLab because I like their CI.

So, on to the real stuff.

A simple start

We start off from a fedora:latest image, and then install an application in it.

FROM fedora:latest

RUN dnf groupinstall -y "C Development Tools and Libraries"
RUN dnf install -y curl file openssh-clients rsync

RUN curl https://sh.rustup.rs -sSf | \
           sh -s -- --default-toolchain nightly -y
RUN $HOME/.cargo/bin/rustup run nightly cargo install --root=/usr artifact-app

CMD ["/root/.cargo/bin/art","ls"]

We also specify a default command using CMD. I am not using ENTRYPOINT, because that messes up GitLab CI integration for now.

Docker Hub hooks

So, from there on, we would like to have Docker Hub tag our images for a bunch of different versions of the software itself.

The trick lies in the build file in the hooks directory next to your Dockerfile.

That file overrides the docker command that gets called to build your image. You cannot specify the tag there, but you can pass a parameter to your Dockerfile! The big trick relies on some environment variables that Docker Hub makes available to the build hook file. For example:

#!/usr/bin/env sh

if [ "$DOCKER_TAG" = "latest" ]; then
  echo "Building :latest, without VERSION_ARG"
  docker build --build-arg VERSION_ARG="" -t ${IMAGE_NAME} .
else
  if [ "$DOCKER_TAG" = "master" ]; then
    echo "Building :$DOCKER_TAG, from git"
    docker build --build-arg VERSION_ARG="" -f Dockerfile.git -t ${IMAGE_NAME} .
  else
    echo "Building :$DOCKER_TAG, with VERSION_ARG=\"--vers $DOCKER_TAG\""
    docker build --build-arg VERSION_ARG="--vers $DOCKER_TAG" -t ${IMAGE_NAME} .
  fi
fi

If you want to pass more variables, you need to repeat the --build-arg for each one.

As you see, currently, I have two different Dockerfile’s. One is for builds from git, the other one for versioned releases. It’s perfectly possible to merge them again, and I’ll do that very soon.

In your Dockerfile, you can specify an ARG command, which will catch a variable from a --build-arg parameter.

FROM fedora:latest

ARG VERSION_ARG

RUN dnf groupinstall -y "C Development Tools and Libraries"
RUN dnf install -y curl file openssh-clients rsync
RUN curl https://sh.rustup.rs -sSf | \
           sh -s -- --default-toolchain nightly -y
RUN $HOME/.cargo/bin/rustup run nightly cargo install --root=/usr $VERSION_ARG artifact-app

CMD ["/root/.cargo/bin/art","ls"]

So, I actually generate an extra parameter for in the cargo install command, when a certain version needs to be built.

The git version has a git clone and a cd command in its build file, but you can actually easily abstract over that if you would add a small bash script to your Dockerfile. That’s what I am going to do next.

Configuring Docker Hub

The last thing you’ll need to do is create git tags and push them. Docker Hub takes care of the rest, after you configured a build rule for tags. Just set the type of your second rule to Tag, push save, and that should do it.

If you add a build rule in your repo that maps git branch master to Docker tag master, the above build hook will take care to dispatch to the git version instead of a versioned version.

Docker Hub has currently five builds, all different versions, queued up.

Have fun, good night!