Skip to main content

Using Docker build args to customize the build

This blog post might be outdated!
This blog post was published more than one year ago and might be outdated!
· 2 min read
Stephan Hochdörfer
Head of IT Business Operations

I wasn't really happy with the current approaches of dealing with different Dockerfiles and docker-compose.yaml files for development and production containers. I don't really see the point of managing multiple configuration files, building a few intermediate containers when the only difference between a development image and a production image is that the code is copied into the image during build. Adding files on every build is also not an ideal solution as you could potentially ship an old version of the application when you miss running a docker build after you made your final changes.

By accident I ran across this post on askubuntu.com which covers the usage of build args to pass the build context as parameter while building the image. By defining a build argument you can do the following in your Dockerfile:

ARG package
ADD $package /var/www/html

This would take the files passed to the docker build command and store them in the /var/www/html folder while building the image. Unfortunately, if a build argument is not passed as an command-line argument, the build outputs an error. Luckily there is an easy fix for this: Simply define a default value for the build argument. In the example below we set the default to .gitignore:

ARG package=.gitignore
ADD $package /var/www/html

This basically means that whenever the container is built e.g. via docker build or via docker-compose, the local .gitignore file will be added to the image. Since this is usually a very small file, adding the file to the image is very fast and will not occupy a lot of disk space in the image.

During the container build for staging and production the following happens in our GitLab CI pipeline:

tar cvfz /tmp/package.tgz --exclude=data --exclude=docker --exclude=.git .

mv /tmp/package.tgz $CI_PROJECT_DIR && \
docker build -t customer/project --build-arg package=package.tgz .

docker tag customer/project:latest registry.loc/customer/project:latest

docker push registry.loc/customer/project:latest

rm $CI_PROJECT_DIR/package.tgz

We simply package the whole project - excluding folders which we do not need inside the container - and pass the tarred package via the build arg to the docker build command. After the build we tag and push the image to our local docker registry and we are done.