Today I Learned (May 22, 2024)

How to pass multiple build arguments to docker build from a .env file

Docker currently only allows us to pass multiple build arguments via multiple --build-argument options to the docker build command. So, if we have, for example, a .env file containing build arguments (like versions of software we need to install) in our Dockerfile

FROM ubuntu:22.04

ARG VERSION_FOO
ARG VERSION_BAR 
ARG VERSION_BAZ

RUN echo "VERSION_FOO=$VERSION_FOO, VERSION_BAR=$VERSION_BAR, VERSION_BAZ=$VERSION_BAZ"

then we will have to run docker build like so:

docker build --build-arg VERSION_FOO=0.0.1 --build-arg VERSION_BAR=1.0.1 VERSION_BAZ=3.14.0 .

To do this dynamically, we may do a little BASH magic to construct the build args substring from the .env file. Assuming .env contains

VERSION_FOO=0.0.1
VERSION_BAR=1.0.1
VERSION_BAZ=3.14.0

we may read the variable assignments in the .env file into an array and then use this array in our docker build call:

build_args=()
while IFS= read -r line; do
  build_args+="--build-arg=$line"
done < .env
docker build -t test ${build_args[@]} .

:bulb: Note that the = after --build-arg is required (at least in Docker 26.1.2 which is the version I’m running at the time of writing), because docker build will otherwise fail with a syntax error:

unknown flag: –build-arg VERSION_FOO

We also use an array to store the build arguments and use the interpolation syntax for getting all array elements (${build_args[@]}) for the same reason.

:bulb: We could use multiple .env sources, e.g. by using a sub shell with cat: e.g. 

build_args=()
while IFS= read -r line; do
. build_args+="--build-arg=$line"
done <<(cat .env1 .env2)
docker build -t test ${build_args[@]} .