Home Using a single ARG in Dockerfile with multiple values
Post
Cancel

Using a single ARG in Dockerfile with multiple values

Introduction to the problem

Recently while building a Dockerfile for pipenv in alpine in order to have a smaller footprint image then kennethreitz/pipenv I started using ONBUILD docker trigger.

For those who haven’t used ONBUILD before , this is a build trigger that even by overriding the image will be ran when image is built according to the order defined for the base image. This is very useful, and is used in a multitude of images.

However, since I was using an alpine based image, some of my Pipenv dependencies had system dependencies that don’t come with the alpine base image, such as gcc that is present in the build-base package.

This presented me with a challenge, I wanted to reuse that image and keep it small, but also had the need to extend its base packages to have a list of packages that were not present under the base image I built at first.

First attempt had me going with Dockerfile to override that image, but the triggers from the ONBUILD were ran first, so I had two options, either give that base image build-base so I could use gcc, and force it to anyone using the image on the future but since I wouldn’t want that package in every single python project I would use so that’s definitely a NO, or just create a copy and add the RUN directives first, but then why would I want to have a base image at all?

This made me wonder if I couldn’t just use build ARG as a way to have both of this, allowing me to install new packages I would need without messing with the original image, and also without having a Dockerfile that would be a copy plus the extension I would need, but I wouldn’t also want a script to handle all the args or env’s I could pass to the Dockefile.

Keeping it simple using a ARG as list

As you can see from the Dockefile I ended up using Dockerfile for pipenv:alpine this is actually pretty simple to accomplish for this case.

1
2
3
ARG packages
RUN apk --update add ${packages} \
    && rm -rf /var/cache/apk/*

So now when I wanted to use this image and just add new system packages to it, I would simply use a –build-arg packages.

Usage for this case:

1
docker build -t andreilhicas/pipenv:alpine-custom --build-arg packages="build-base" .

Since this will be expanded in the RUN command under the original image, if I wanted to have more packages I would simply delimit them with a blank space similar to how you would write it on the Dockerfile.

1
docker build -t andreilhicas/pipenv:alpine-custom --build-arg packages="build-base wget curl git"

But I don’t want to clone your repo to have custom packages in my Dockerfile

Of course the problem here lies on having a Dockerfile, since this cannot be achieved by using a docker run or docker pull since this is effectively build a new image using base image layers.

There are two possible approaches to this:

  • Using a dockerfile
1
FROM andreilhicas/pipenv:alpine

And now you may make your changes using only the image that will be pulled from the hub.docker.com in this case, since its a public image,

Or directly from the github repo that hosts this dockerfile.

1
docker build -t andreilhicas/pipenv:alpine-custom --build-arg packages="build-base" https://github.com/Ilhicas/alpine-pipenv.git

For further info on Build from URL visit Docker BUILD Documentation

This post is licensed under CC BY 4.0 by the author.