How do I set environment variables during the build in docker
I'm trying to set environment variables in docker container during the build but without success. Setting them when using run command works but I need to set them during the build.
Dockerfile
FROM ubuntu:latest
ARG TEST_ENV=something
Command I'm using to build
docker build -t --build-arg TEST_ENV="test" myimage .
Running
docker run -dit myimage
I'm checking available environment variables by using
docker exec containerid printenv
and the result is
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=e49c1abfd58b
TERM=xterm
no_proxy=*.local, 169.254/16
HOME=/root
TEST_ENV is not present
ARG
is for setting environment variables which are used during the docker build
process - they are not present in the final image, which is why you don't see them when you use docker run
.
You use ARG
for settings that are only relevant when the image is being built, and aren't needed by containers which you run from the image. You can use ENV
for environment variables to use during the build and in containers.
With this Dockerfile:
FROM ubuntu
ARG BUILD_TIME=abc
ENV RUN_TIME=123
RUN touch /env.txt
RUN printenv > /env.txt
You can override the build arg as you have done with docker build -t temp --build-arg BUILD_TIME=def .
. Then you get what you expect:
> docker run temp cat /env.txt
HOSTNAME=b18b9cafe0e0
RUN_TIME=123
HOME=/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
BUILD_TIME=def
PWD=/
I'll summarize highlights from this great article.
ARG Vs ENV
1 ) Short explanation:
ARG is only available during the build of a Docker image (RUN etc), not after the image is created and containers are started from it (ENTRYPOINT, CMD).
ENV values are available to containers, but also RUN-style commands during the Docker build starting with the line where they are introduced. If you set an environment variable in an intermediate container using bash (RUN export VARI=5 && …) it will not persist in the next command.
2 ) Longer explanation:
ARG are also known as build-time variables. They are only available from the moment they are ‘announced’ in the Dockerfile with an ARG instruction up to the moment when the image is built. Running containers can’t access values of ARG variables. This also applies to CMD and ENTRYPOINT instructions which just tell what the container should run by default. If you tell a Dockerfile to expect various ARG variables (without a default value) but none are provided when running the build command, there will be an error message.
However, ARG values can be easily inspected after an image is built, by viewing the docker history of an image. Thus they are a poor choice for sensitive data.
ENV variables are also available during the build, as soon as you introduce them with an ENV instruction. However, unlike ARG, they are also accessible by containers started from the final image. ENV values can be overridden when starting a container, more on that below.
3 ) With diagrem:
Here is a simplified overview of ARG and ENV availabilities around the process around building a Docker image from a Dockerfile, and running a container.
They overlap, but ARG is not usable from inside the containers.
Setting ARG and ENV values
Setting ARG values
So, you have your Dockerfile
, which defines ARG
and ENV
values. How to set them, and where? You can leave them blank in the Dockerfile
, or set default values. If you don’t provide a value to expected ARG variables which don’t have a default, you’ll get an error message.
Here is a Dockerfile
example, both for default values and without them:
ARG some_variable_name
# or with a hard-coded default:
#ARG some_variable_name=default_value
RUN echo "Oh dang look at that $some_variable_name"
# you could also use braces - ${some_variable_name}
When building a Docker image from the commandline, you can set ARG
values using –build-arg
:
$ docker build --build-arg some_variable_name=a_value
Running that command, with the above Dockerfile
, will result in the following line being printed (among others): Oh dang look at that a_value
So, how does this translate to using docker-compose.yml
files?
When using docker-compose, you can specify values to pass on for ARG
, in an args block:
(docker-compose.yml file)
version: '3'
services:
somename:
build:
context: ./app
dockerfile: Dockerfile
args:
some_variable_name: a_value
When you try to set a variable which is not ARG
mentioned in the Dockerfile
, Docker will complain.
Setting ENV Values
So, how to set ENV
values? You can do it when starting your containers (and we’ll look at this a bit below), but you can also provide default ENV
values directly in your Dockerfile
by hard-coding them. Also, you can set dynamic default values for environment variables!
When building an image, the only thing you can provide are ARG
values, as described above. You can’t provide values for ENV
variables directly. However, both ARG
and ENV
can work together. You can use ARG to set the default values of ENV
vars.
Here is a basic Dockerfile
, using hard-coded default values:
# no default value
ENV hey
# a default value
ENV foo /bar
# or ENV foo=/bar
# ENV values can be used during the build
ADD . $foo
# or ADD . ${foo}
# translates to: ADD . /bar
And here is a snippet for a Dockerfile
, using dynamic on-build env values:
# expect a build-time variable
ARG A_VARIABLE
# use the value to set the ENV var default
ENV an_env_var=$A_VARIABLE
# if not overridden, that value of an_env_var will be available to your containers!
Once the image is built, you can launch containers and provide values for ENV
variables in three different ways, either from the command line or using a docker-compose.yml
file.
All of those will override any default ENV
values in the Dockerfile
.
Unlike ARG
, you can pass all kinds of environment variables to the container. Even ones not explicitly defined in the Dockerfile
.
It depends on your application whether that’ll do anything however.
Option 1: Provide values one by one
From the commandline, use the -e flag:
$ docker run -e "env_var_name=another_value" alpine env
From a docker-compose.yml
file:
version: '3'
services:
plex:
image: linuxserver/plex
environment:
- env_var_name=another_value
Option 2: Pass environment variable values from your host
It’s the same as the above method.
The only difference is, you don’t provide a value, but just name the variable. This will make Docker access the current value in the host environment and pass it on to the container.
$ docker run -e env_var_name alpine env
For the docker-compose.yml
file, leave out the equation sign and everything after it for the same effect.
version: '3'
services:
plex:
image: linuxserver/plex
environment:
- env_var_name
Option 3: Take values from a file (env_file)
Instead of writing the variables out or hard-coding them (not in good taste according to the 12-factor folks), we can specify a file to read values from. The contents of such a file look something like this:
env_var_name=another_value
The file above is called env_file_name (name arbitrary) and it’s located in the current directory.
You can reference the filename, which is parsed to extract the environment variables to set:
$ docker run --env-file=env_file_name alpine env
With docker-compose.yml
files, we just reference a env_file, and Docker parses it for the variables to set.
version: '3'
services:
plex:
image: linuxserver/plex
env_file: env_file_name
Common ways to set ARG and ENV from the command line
Here is a small cheat sheet, combining an overview of ARG
and ENV
availability with common ways to set them from the command line.