Docker is a great addition to you DevOps toolbox. Sometimes you may want to build several similar images using the same Dockerfile. That’s where parameterized docker builds come in:
They provide the ability to provide configuration values at image build time. Do not confuse this with environment variables when running the container! We used parameterized builds for example to build images for creating distribution-specific packages of native libraries and executables.
Our use case
We needed to package some proprietary native programs for several linux distribution version, in our case openSuse Leap. Build ARGs allow us to use a single Dockerfile but build several images and run them to build the packages for each distribution version. This can be easily achieved using so-called multi-configuration jobs in the jenkins continuous integration server. But let us take a look at the Dockerfile first:
ARG LEAP_VERSION=15.1 FROM opensuse/leap:$LEAP_VERSION ARG LEAP_VERSION=15.1 # add our target repository RUN zypper ar http://our-private-rpm-repository.company.org/repo/leap-$LEAP_VERSION/ COMPANY_REPO # install some pre-requisites RUN zypper -n --no-gpg-checks refresh && zypper -n install rpm-build gcc-c++ WORKDIR /buildroot CMD rpmbuild --define "_topdir `pwd`" -bb packaging/project.spec
ARG instruction defines a parameter name and a default value. That allows us to configure the image at build time using the
--build-arg command line flag. Now we can build a docker image for Leap 15.0 using a command like:
docker build -t project-build --build-arg LEAP_VERSION=15.0 -f docker/Dockerfile .
In our multi-configuration jobs we call
docker build with the variable from the axis definition to build several images in one job using the same Dockerfile.
As you may have noticed we have put the same
ARG instruction twice in the Dockerfile: once before the
FROM instruction and another time after
FROM. This is because the build args are cleared after each
FROM instruction. So beware in multi-stage builds, too. For more information see the docker documentation and this discussion. This had cost us quite some time as it was not as clearly documented at the time.
Parameterized builds allow for easy configuration of your Docker images at image build time. This increases flexibility and reduces duplication like maintaining several almost identical Dockerfiles. For runtime container configuration provide environment variables to the
docker run command.