Automatically building versioned Docker images on Docker Hub
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!