A complete guide to using environment variables and files with Docker and Compose
Keep your containers secure and flexible with this easy tutorial
The goal of this article is show you the benefits of working with environment variables in Docker and to demonstrate how to do so. Environment variables keep your app secure, flexible and organized. The main advantages:
- keep confidential information confidential: prevent baking your passwords and secrets into your image
- Organize confidential information in one file; we can .gitignore all of it
- Reuse env files by injecting them in multiple containers; all configurations in one place
In this article we’ll have hands-on examples on how to pass environment variables to containers and docker-compose.yml files. Also we’ll check out how to organize env vars in a file that we can pass, again, to both our containers and configs. Let’s code!
Before we begin..
Obviously, we are going to use Docker and Docker-Compose for this. It’s recommended to first read this and this article if you’re unfamiliar with either.
Setting up
We’ll create a simple Python script called environprinter.py
that prints our all keys and values in our environment:
We’ll bake this file in a simple docker image with the Dockerfile
below.
Execute docker build-t environ_image .
to build the image. As seen on line 4 of the Dockerfile; our python script will execute the moment we spin up our container. If you execute docker run environ_image
you’ll see some variables like HOSTNAME
, LANG
, PYTHON_VERSION
etc. being printed. You’ll see that there are always some environment variables that concern your path, hostname etc. (more about in this article).
Passing env vars to the container
In this section we’ll check out how to load variables into the environment of the container so that the Python script that’s running in this container has access to it. Understand that this differs from passing env vars to the run-configuration; we’ll check this out later.
1. Pass env vars to a container with Docker run
So we have an image that executes a Python script on startup. Our goal is now to start the container, pass an env var to the container and then run the Python script (that will print out all of our env vars).
We can achieve this with a single command:
just execute docker run -e PASSWORD=SECRET environ_image
. Notice that PASSWORD and SECRET now show up in the output!
Pass multiple env vars with te following: docker run -e USERNAME=mike -e PASSWORD=bestpassword environ_image
.
2. Pass env files to a container with Docker run
Typing out all of the env vars can become a bit time-consuming. Let’s create a file called .env and put all of our env vars in there. This is what the contents look like:
USERNAME=mike
PASSWORD=bestpassword
We can pass all of the variables contained in the file in one go by executing: docker run --env-file=.env environ_image
.
You can even pass multiple .env files like this:docker run --env-file=.env --env-file=.env2 environ_image
.
Just remember that the last env file overwrites duplicate keys. So if you have a USER=1 in .env and USER=2 in .env2 then only one env variable will exist in the container’s environment by the key USER and it will have the value 2.
3. Pass env vars to a container with docker-compose
Call me lazy but I don’t like to type out the docker run
commands we’ve used earlier. With docker-compose we can create a config file that we can execute to do the same thing. Just create a file called docker-compose.yml
with the following content:
version: '3.8'
services:
env_printer:
image: "environ_image"
Now we can call docker-compose up
and it will do the exact same thing. We can add individual env vars by adding the last 3 lines below:
version: '3.8'
services:
env_printer:
image: "environ_image"
environment:
- USER=mike
- PASS=123
NOTICE: do NOT include confidential information (like the credentials in the example above) into your compose file. This information can end up in your (public) repository. Read the article below for more information on using .env file for security.
4. Pass env files to a container with docker-compose
Notice that in the previous example we’ve hardcoded our password into our docker-compose.yml. This is definitely not a good idea since the compose-file can end up in your Github repository.
Therefore it’s a better (more secure) idea to add all environment variables in an .env file. You .gitignore
the file so it doesn’t end up on Github. Passing the .env file into your container is just a matter of adding a few lines:
version: '3.8'
services:
env_printer:
image: "environ_image"
environment:
- USER=mike
env_file:
- .env
- .env2
Passing env vars to the container config
This section details how to pass env vars to your docker-compose.yml
file. The main use-cases:
- You don’t want to pass the entire .env file into the container, just one or more keys
- You want to set other docker attributes (like label) with values from the .env file
1. Setup
In order to demonstrate we’ll first need a .env file. Create a file named .env
with the following content:
ENVIRONMENT=acceptation
USERNAME=mike
PASSWORD=test
API_KEY=SOME_KEY
Now our goal is to pass only our API key into our container and use the value for the ENVIRONMENT key as a label in Docker. This is achieved using the following docker-compose.yml
:
version: '3.8'
services:
env_printer:
image: "environ_image"
labels:
environment: ${ENVIRONMENT}
environment:
- API_KEY=${API_KEY}
2. Check the config
Before we spin up our container, let’s check out what the configuration will be: docker-compose --env-file=some_folder/.env config
. This command will print out your compose-file after Docker fills it in. This is the result:
services:
env_printer:
environment:
API_KEY: SOME_KEY
image: environ_image
labels:
environment: acceptation
version: '3.8'
As you see the label is set to acceptation
and we’re passing the API_KEY value from our .env but no other variables.
3. Run the container
When we execute docker-compose --env-file=some_folder/.env up
we start the container and see that our Python program correctly prints out the value associated with the API_KEY variable!
Conclusion
I hope to have shed some light on how to make Docker more secure and convenient to use. Environment variables help you keep all your confidential information in one place, you avoid baking it into your image and it makes running containers even more dynamic.
If you have suggestions/clarifications please comment so I can improve this article. In the meantime, check out my other articles on all kinds of programming-related topics like these:
- Docker for absolute beginners
- Docker Compose for absolute beginners
- Create and publish your own Python package
- Virtual environments for absolute beginners — what is it and how to create one (+ examples)
Happy coding!
— Mike
P.S: like what I’m doing? Follow me!