Pass Docker Environment Variables During The Image Build

Working with ENV and environment variables in Docker can be surprisingly challenging.

Let’s look at all the ways you can pass variables while building a Docker image, from simple to more complex.

Option 1: Hardcoding Default ENV values

Fixed ENV values can be good enough in some cases. You can specify a default value right next to your variable definition:

ENV env_var_name=some_value

If your variable values won’t change frequently in the future, you can use this method to configure sane defaults for your future containers. But what if you need to change those values every once and again?

Let’s look at a way to set dynamic ENV values during the build, directly from your command line, without reinventing the wheel.

Intermission: ARG vs ENV

To set environment variables during your image build, you will need either ENV or ARG and ENV at the same time.

Docker ENV and ARG are pretty similar, but not quite the same. One of the differences: ARG can be set during the image build with --build-arg, but there is no such flag for ENV. ARG values can’t do the job - you can’t access them anymore once the image is built. The ENTRYPOINT command, which runs inside the future container, can’t access those values.

ENV values are accessible during the build, and afterwards once the container runs. You can set ENV values in your Dockerfile - either by hardcoding them, or in a dynamic fashion.

Option 2: Setting Dynamic ENV Values

Hardcoded ENV values can be a tedious solution if they need to be changed often. Imagine having to edit your Dockerfile again and again with each build.

You can do better! Introduce a new ARG variable, and reference it to set your initial ENV variables dynamically during the build:

ARG var_name # you could give this a default value as well
ENV env_var_name=$var_name

the “env_var_name” environment variable value passed with “var_name” will be available to future containers. If needed, you can override it when starting up a container from the image. They are merely default values after all.

Option 2.5: Using Host Environment Variable Values to Set ARGs

What if you want to set the ARG value based on a variable in your current environment, without having to type it out each time? You can pass the value directly from your command line using bash command substitution.

$ docker build --build-arg var_name=${VARIABLE_NAME} (...)

The dollar-notation will be substituted with the value of the current environment variable. Alternatively, you can pass the value from the environment automatically, if your variable in the Dockerfile is named the same as the env var in question. Just don’t mention the value, and let Docker look it up:

$ docker build --build-arg var_name (...)

Gotchas You Should Keep In Mind

ARG and ENV values are not suitable to handle secrets without extra care. The stick around in your final images (unless you squash or use careful multi-stage builds).

ARG values, both dynamic and hard-coded, can be looked at by other people after the image is built. You can give it a try, with the docker history command on your own image. ENV values can be discovered in many ways, from within the container if they were not overwritten, with the inspect command or from the history as well if they were hard-coded.

To do better, you can use multi-stage builds or some shiny new BuildKit features.

In Conclusion

I hope that you’ll have an easier time to set Docker environment variables during the image build from now on. Remember to be cautious when considering ARG and ENV for secrets, as they are not safe. Consider looking into multi-stage builds or using BuildKit to handle build-time secrets.

If you want to get a good overview of build-time arguments, environment variables, env_files and docker-compose templating with .env files - head over to this in-depth guide and give it a read.