Overriding One Single Value in Your Docker-Compose .env File

Using a .env file is one of the many ways fo configure Docker images and containers. If you are using docker-compose, the values from .env are used to replace ${DOLLAR_NOTATION} placeholders in your docker-compose.yml file.

But what if you want to change one of the values in the .env file dynamically? You could use something like sed or awk to change the file in-place, but there is a better way.

Unfortunately, this is also a possible source of nasty bugs, which you should know about.

Some people also pass the .env as an env_file to their containers. We’re only talking about the way docker-compose handles values in the .env file here.

Your Host’s Environment Variables Override .env Entries

Yep, you read that right. If you are defining a variable in your .env file, but there is an environment variable in your current shell session with the same name, the environment variable will take precedence.

Let’s look at an example! Let’s say you have the following docker-compose.yml file:

version: "3"
services:
  ubuntu:
    image: ubuntu
    entrypoint: env
    environment:
      - NAME: "${NAME}"

Nothing fancy so far. We are running a container from the latest Ubuntu. The entrypoint is the env command, which prints out the container’s environment and exits.

We are using docker-compose to set an environment variable in the container. The value is supposed to be replaced by docker-compose, instead of the ${NAME} placeholder. The usual thing to do, is to create a .env file in the same directory containing the desired value:

NAME=FROM_DOT_ENV

When we run the container using this docker-compose setup, we’ll see the following output:

$ docker-compose up
Recreating lab_ubuntu_1 ... done
Attaching to lab_ubuntu_1
ubuntu_1  | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ubuntu_1  | HOSTNAME=a4439c9b0457
ubuntu_1  | NAME=FROM_DOT_ENV
ubuntu_1  | HOME=/root
lab_ubuntu_1 exited with code 0

The “FROM_DOT_ENV” value taken from the .env file made it into the container. As one would expect.

Now, let’s try overriding the value defined in the .env file by setting an environment variable in the host’s shell:

$ NAME="ENV" docker-compose up
Recreating lab_ubuntu_1 ... done
Attaching to lab_ubuntu_1
ubuntu_1  | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ubuntu_1  | HOSTNAME=7ee3ce6e3965
ubuntu_1  | NAME=ENV
ubuntu_1  | HOME=/root
lab_ubuntu_1 exited with code 0

The container’s NAME variable is set to “ENV”, which is the value of the environment variable.

What Happened Here?

Values in the shell take precedence over those specified in the .env file.

This is specified in the compose docs. But docker-compose does not stop at the .env and the host’s current environment variables.

If it can’t find a value, docker-compose will look for values inside of the provided environment file and even the Dockerfile. You can find the lookup order in the docs. Here is my understanding of the order (the first lines are ‘more important’ and have precedence):

1. Compose file
2. **Shell environment variables**
3. `environment` attribute in compose file 
3. Environment file passed to compose
3. `env_file` attribute in compose file
4. **.env file**
5. Dockerfile

It’s cool that you can simply override values of your .env file, but this flexibility is can also be the source of nasty bugs. Imagine overwriting a .env variable in your Docker containers by accident, without realizing that you just did.

In Conclusion

Overriding a single value in your docker-compose .env file is reasonably simple: just set an environment variable with the same name in your shell before running your docker-compose command.

This is convenient, but can be the source of nasty bugs if you don’t know about this functionality and have an ambiguous environment variable defined. Also, keep in mind that docker-compose won’t stop at your host’s env variables. It will even look inside of your Dockerfile before it gives up.

I hope this explanation has helped you to learn a bit more about using docker-compose with a .env file, and will save you from one more potential gotcha when working with Docker in the future.

Note: if you are working with Django, you might be familiar with django-environ. The current default behavior there, is to override env variables with entries from the .env file (as discussed in this issue). Python-dotenv on the other hand does the opposite, but provides an ‘override=True’ option. I guess you never know for sure until you look it up.

Subscribe to my newsletter!
You'll get notified via e-mail when new articles are published. I mostly write about Docker, Kubernetes, automation and building stuff on the web. Sometimes other topics sneak in as well.

Your e-mail address will be used to send out summary emails about new articles, at most weekly. You can unsubscribe from the newsletter at any time.

Für den Versand unserer Newsletter nutzen wir rapidmail. Mit Ihrer Anmeldung stimmen Sie zu, dass die eingegebenen Daten an rapidmail übermittelt werden. Beachten Sie bitte auch die AGB und Datenschutzbestimmungen .

vsupalov.com

© 2024 vsupalov.com. All rights reserved.