Passing Environment Variables to Docker Container

Environment variables are useful for configuring the behavior of an application without modifying its code. They are often used to store sensitive information such as passwords, API keys, or database credentials. However, passing environment variables to a Docker container can be tricky, especially if you want to keep them secure and avoid exposing them in the command line or the Dockerfile.

In this tutorial, I will show you three different ways to pass environment variables to a Docker container:

    • using the -e flag,
    • using an env-file, and
    • using docker-compose.

I will also explain the pros and cons of each method and give you some tips on how to use them effectively.

Using the -e flag

The simplest way to pass an environment variable to a Docker container is to use the -e flag (short for –env) in the docker run command. This flag allows you to specify a key-value pair that will be set as an environment variable in the container. For example, if you want to pass a variable called MESSAGE with the value “Hello world” to an alpine container, you can run:

docker run -e server.port=8081 -e spring.profiles.active=dev users-microservice-app

This method is easy and convenient, but it has some drawbacks.

  • First, the variables are not persisted in the container image, which means they will be lost if you stop or restart the container.
  • Second, the variables are not available during the build process of the image, which means you cannot use them in the Dockerfile instructions.

Using an env-file

Another way to pass environment variables to a docker container is to use an env-file. This is a file that contains one or more key-value pairs of environment variables, each on a new line. For example, you can create a file called env.list with the following content:

server.port=8081
spring.profiles.active=dev

Then, you can pass this file to the docker run command using the --env-file flag:

docker run --env-file env.list users-microservice-app

By using this method, you can set the same environment variables as before. To make this file more secure, you can use file permissions (chmod, chown) to limit who can access or modify it.

However, this method is not perfect. It has some drawbacks that you should be aware of:

  • One drawback is that you have to create and manage a different file for each container or image that requires environment variables. This can be tedious and prone to mistakes.
  • Another drawback is that the variables are not stored in the container image or accessible during the build process. This means that they will be lost if you stop or restart the container or rebuild the image.

Using docker-compose

The third and most powerful way to pass environment variables to a docker container is to use docker-compose. This is a tool that allows you to define and run multiple containers using a YAML file called docker-compose.yml. For example, you can create a file with the following content:

version: "3"
services:
  users-microservice:
    image: users-microservice
    environment:
      - server.port=8081
      - spring.profiles.active=dev

This file creates a service called users-microservice that uses the users-microservice image and sets two environment variables: server.port and spring.profiles.active. To start this service, you can use the docker-compose up command:

docker-compose up

This will make and run a container named users-microservice_1 with the same environment variables as before. You can also use the docker-compose logs command to see the output of your container:

docker-compose logs users-microservice

The logs command will show you the messages from your container, including the ones that use the environment variables.

Passing Environment Variables at Build Time

Passing environment variables at build time means setting the values of the environment variables during the image creation process, not when the container is launched from the image. This can be useful for scenarios where you need to customize the image based on some parameters, such as installing some files that require authentication, or setting some configuration options that are only relevant for the image build.

There are two main ways to pass environment variables at build time in Docker:

  • Using ARG instructions: ARG instructions allow you to define and assign default values to variables that can be used in the Dockerfile, such as in RUN, COPY, or ADD commands.
  • Using Build arguments: Build arguments allow you to override the default values of ARG variables or set new variables when you run the docker build command.

Using ARG instructions

ARG instructions allow you to define and assign default values to variables that can be used in the Dockerfile, such as in RUN, COPY, or ADD commands. To use ARG instructions, you need to add them to your Dockerfile before the commands that use them. For example, if you want to use a variable called ACTIVE_PROFILE in a RUN command, you need to define it with an ARG instruction and assign it a default value with an ENV instruction:

FROM openjdk:11-jdk
ARG ACTIVE_PROFILE=dev
ENV ACTIVE_PROFILE=$ACTIVE_PROFILE
COPY target/*.jar app.jar
RUN echo "ACTIVE_PROFILE = $ACTIVE_PROFILE"
ENTRYPOINT ["java","-jar","/app.jar","--spring.profiles.active=$ACTIVE_PROFILE"]

This Dockerfile is for a Spring Boot application that uses the environment variable ACTIVE_PROFILE to determine which profile to activate. A profile is a named set of properties and beans that can be used to customize the application behavior for different environments, such as development, testing, or production.

Using Build Arguments

Build arguments allow you to override the default values of ARG variables or set new variables when you run the docker build command. To use build arguments, you need to add the –build-arg option to the docker build command and specify the name and value of the variable you want to set or override. For example, if you want to change the value of ACTIVE_PROFILE to prod, you need to run:

docker build --build-arg ACTIVE_PROFILE=prod -t myapp .

This will pass prod as the value of ACTIVE_PROFILE to the Docker build process and print ACTIVE_PROFILE = prod in the output.

You can also use build arguments in conjunction with docker-compose by adding the args property under the build section of your service in the docker-compose.yml file. For example, if you want to pass ACTIVE_PROFILE as a build argument to your service, you need to write:

version: "3"
services:
  app:
    build:
      context: .
      args:
        ACTIVE_PROFILE: ${ACTIVE_PROFILE:-dev}
    image: myapp
    environment:
      - ACTIVE_PROFILE=${ACTIVE_PROFILE:-dev}

This will use the value of ACTIVE_PROFILE from your environment or use dev as a fallback value. You can then use the docker-compose commands to build and run the service. For example, if you want to build and run the service with the prod profile, you need to run:

ACTIVE_PROFILE=prod docker-compose up --build

Final words

I hope you have enjoyed this tutorial on how to pass environment variables to a docker container. You have learned four different methods:

  • using the -e flag,
  • using an env-file, and
  • using docker-compose,
  • passing environment variables at build time.

If you want to learn more about Docker and how to use it for your applications, I invite you to check out my other docker tutorials as well. There you will find many useful and interesting topics, such as how to build, run, and deploy docker images, how to use docker volumes and networks, how to use docker swarm and kubernetes, and much more. You will also find code examples and exercises to help you practice your skills.