1. Overview
It is often a good idea to separate our services from their configuration. For a twelve-factor app, we should store configuration in the environment.
Of course, this means we'll need a way to inject the configuration into our service.
In this tutorial, we'll achieve this by passing environment variables to a Docker container.
2. Using –env, -e
Throughout this tutorial, we'll use a small (5MB) Linux image called Alpine. Let's start by pulling the image locally:
docker pull alpine:3
When we launch our Docker container, we can pass environment variables as key-value pairs directly into the command line using the parameter –env (or its short form -e).
For instance, let's execute the following command:
$ docker run --env VARIABLE1=foobar alpine:3 env
Simply put, we're reflecting the environment variables we set back to the console:
VARIABLE1=foobar
As can be seen, the Docker container correctly interprets the variable VARIABLE1.
Also, we can omit the value in the command line if the variable already exists in the local environment.
For example, let's define a local environment variable:
$ export VARIABLE2=foobar2
Then, let's specify the environment variable without its value:
docker run --env VARIABLE2 alpine:3 env
And we can see Docker still picked up the value, this time from the surrounding environment:
VARIABLE2=foobar2
3. Using –env-file
The above solution is adequate when the number of variables is low. However, as soon as we have more than a handful of variables, it can quickly become cumbersome and error-prone.
An alternative solution is to use a text file to store our variables, using the standard key=value format.
Let's define a few variables in a file we'll call my-env.txt:
$ echo VARIABLE1=foobar1 > my-env.txt $ echo VARIABLE2=foobar2 >> my-env.txt $ echo VARIABLE3=foobar3 >> my-env.txt
Now, let's inject this file into our Docker container:
$ docker run --env-file my-env.txt alpine:3 env
Finally, let's take a look at the output:
VARIABLE1=foobar1 VARIABLE2=foobar2 VARIABLE3=foobar3
4. Using Docker Compose
Docker Compose also provides facilities to define environment variables. For those interested in this particular subject, check out our Docker Compose tutorial for more details.
5. Beware of Sensitive Values
More often than not, one of the variables will be a password to a database or an external service. We have to be careful about how we inject those variables into the Docker container.
Passing those values directly via the command line is probably the least secure, as there is a greater risk of leaking the sensitive values somewhere we don't expect, such as in our source control system or the OS process list.
Defining sensitive values in the local environment or in a file is a better choice, as both can be secured from unauthorized access.
However, it's important to realize that any user with access to the Docker runtime can inspect a running container and discover the secret values.
Let's inspect a running container:
docker inspect 6b6b033a3240
The output shows the environment variables:
"Config": { // ... "Env": [ "VARIABLE1=foobar1", "VARIABLE2=foobar2", "VARIABLE3=foobar3", // ... ] }
For those situations where security is a concern, it's important to mention that Docker offers a mechanism called Docker Secrets. Container services, like those provided by Kubernetes, AWS or Azure, also provide similar functionalities.
6. Conclusion
In this short tutorial, we've looked at several different options for injecting environment variables into a Docker container. While each approach works well, our choice will ultimately depend on various parameters, such as security and maintainability.