I allways follow a simple pattern:
– ARG: whenever a variable is used for build-time commands
– ENV: whenever a variable is used for run-time commands, either directly understood by the main application or used in entrypoint scripts to modify configuration files before the main application is started.
Usualy people tend to put everything into ENV variables, which makes end users of the image wonder why a modification of some of the ENV variables has no effect.
I prefer to not use conditional steps in Dockerfiles. Instead I create different Dockerfiles, as ultimately the resulting image is not the same.
In case I was not clear let me clarify.
Imagine we have 20 parameters used for building an image, which
.1. have defaults
.2. we should be able to pass non-default values easy
ARGs work for this goal, e.g. it would look like this
ARG param1=default1
ARG param2=default2
…
ARG param10=default10
Here we have default values, and can pass specific non-default values by “–build-arg” parameters.
The cons of using ARGs are
.1. we have to re-define them after each FROM
.2. they create an intermediate containers for each ARG
so with 10 ARGs and 3 FROMs it would be 40 ARGs, which make the process slower due to creating/removing intermediate containers
It would be faster with ENVs, but in order to set the defaults we would need to add an extra script called before the docker file to set env variables with default values for those which are not set yet,
it could be something like this
In this case we would set non-default parameters as environment variables before calling params.sh and then calling docker build with our docker file.
Option #3 is where we create a specific docker file for each image, replacing the variables by the values, so the docker file would not have ARGs at all, but had actual values, like
docker file:
COPY somefile1 somefile2 /home/username/
instead of
COPY $param1 $param2 $param3
which we have with using ARGs
I wasn’t confused because I didn’t understand you… I was confused about why you strip away the semantics of ARGs and ENVs.
So basicly you have two options, not three. Either use ARGs and ENVs how they are supposed to be used, or render the Dockerfile to skip ARGs completly and render their values staticly into the file. A simple templating can be achived with envsubst of the gettext package. You will not get any oprhaned intermediate containers, if you append the parameter --force-rm.
Without seeing your Dockerfile, it is impossible to spot design problems in you Dockerfile. Using 20-30 Args kind of smells like a non optimal design…