DEV Community

Spacelift team for Spacelift

Posted on • Originally published at spacelift.io

How to Run Environment Variables in a Docker Container

Environment variables are a simple mechanism for separating configuration from code. They're key-value pairs that are set in your shell, ready for running applications to read.

Processes don't necessarily execute directly in your shell, however: Docker allows you to package apps with their dependencies as separate self-contained environments. This requires a slightly different approach to environment variables because you must pass them through from your shell to your containers.

In this guide, we'll walk you through using environment variables with Docker by showing a few different techniques you can try. We'll also share some best practices to ensure you can work with environment variables safely and effectively.

What are environmental variables?

Environment variables are user-definable values that are set outside individual software processes.

Environment variables don't do anything on their own, but processes can read them to apply configuration changes and adjust their behavior --- such as by setting credentials or enabling different features based on the environment variables set. This makes it possible to apply a new configuration each time an app is used or deployed without having to adjust the source code or implement your own config file mechanism.

You can set an environment variable in most shells by running the export key=value command:

$ export foo=bar
Enter fullscreen mode Exit fullscreen mode

Now, processes launched within the shell can read the value of the foo environment variable and see it's set to bar:

$ echo foo
bar

Enter fullscreen mode Exit fullscreen mode

Environment variables can also be set for a single process by specifying them as a prefix to its command line:

$ foo=bar /usr/bin/my-app
Enter fullscreen mode Exit fullscreen mode

What are Docker environment variables?

Docker environment variables are predefined values that can be passed to a containerized application, allowing you to influence its behavior without altering the underlying image. These variables are essential for setting up application or script configurations, fine-tuning Docker images, and securely storing sensitive information such as database credentials or API keys.

Environment variables enhance the flexibility and portability of Docker containers by allowing adjustments in container settings at runtime. This means that you can deploy the same container across different environments, such as development, staging, and production, without modifying the Docker image itself. Instead, the appropriate environment-specific configurations are injected at runtime, making the container adaptable to different scenarios.

Types of Docker environment variables

Here are some of the types of Docker environment variables:

  • Default environment variables: These are predefined variables like HOSTNAME, HOME, and PATH, which give information about the container or the Docker host environment. The list of default variables can vary depending on the base image and Docker version.
  • ARG variables: Defined in the Dockerfile, ARG variables are passed at build time and are not available in the final image or runtime. They can be used to set a default value or modify the build process, but once the image is built, they are no longer accessible inside the running container.
  • ENV variables: These environment variables persist across the image build and are available at runtime, making them useful for runtime configuration. They can be defined in the Dockerfile or passed during docker run. Any environment variable declared with ENV remains in the final image and container.
  • Docker Compose environment variables: Environment variables in Docker Compose can be defined either in the docker-compose.yml file under the environment section or through an external .env file. This is a common approach when working with multi-container applications.
  • Image-specific variables: Some Docker images come with predefined environment variables specific to their functionality. The Docker image creators define and maintain these variables, often documenting them in the image's official repository or documentation.

How to pass environment variables to Docker containers?

Unfortunately, the examples shown in the first section won't work when you start a new container using docker run. Because the container runs in its own isolated environment, the process within the container accesses a separate set of environment variables to those defined in your shell.

Docker environment variables can be set using three main techniques: a CLI flag, a .env file, and Docker Compose's environment option.

Example 1: Setting Docker environment variables with the -e/--env flag

The -e/--env flag is an option for the docker run command that lets you specify environment variables that will be set inside your container. 

You can repeat the flag to set multiple environment variables for your container.

$ docker run -it\
  -e LOG_SERVER=192.168.0.1\
  -e USE_UNENCRYPTED_STORAGE=1\
  alpine:latest sh
Enter fullscreen mode Exit fullscreen mode

The command above starts a new container running the alpine:latest image and sets the LOG_SERVER and USE_UNENCRYPTED_STORAGE environment variables. The -it flag enables interactive mode and attaches your terminal to the container, letting you run commands within it to check the variables have been set:

$ echo $LOG_SERVER
192.168.0.1

$ echo $USE_UNENCRYPTED_STORAGE
1
Enter fullscreen mode Exit fullscreen mode

The variables have been added to the container's environment. Processes running within the container can now read them.

Reusing variables already set in your shell

If you've already set shell variables that you want to pass to your container, you can specify just the variable's name without a value:

$ export LOG_SERVER=192.168.0.254

$ docker run -e LOG_SERVER alpine:latest

Enter fullscreen mode Exit fullscreen mode

Docker will automatically set the variable inside the container, using the value inherited from your shell. In this example, the value of LOG_SERVER inside the container will be 192.168.0.254.

Example 2: Setting environment variables in Docker with a .env file

Another way to set Docker environment variables is with a .env file. This is a file that contains key-value pairs of environment variables:

LOG_SERVER=192.168.0.1
USE_UNENCRYPTED_STORAGE=1
Enter fullscreen mode Exit fullscreen mode

To use a .env file with docker run, you must specify the file's path by setting the --env-file flag:

$ docker run --env-file /path/to/env/file alpine:latest
Enter fullscreen mode Exit fullscreen mode

Docker will read the environment variable key-value pairs from the file and set them inside the container.

You can repeat the flag to load variables from multiple .env files. It's also possible to add the -e/--env file to set additional variables not included in your .env file.

💡 You might also like:

Example 3: Passing environment variables using Docker Compose

Docker Compose enables declarative configuration for your Docker containers using a docker-compose.yml file. This lets you configure containers as code, version your changes, and conveniently manage stacks that run multiple services in separate containers.

You can set environment variables for a service using the environment field in your Compose file:

services:
  app:
    image: alpine:latest
    environment:
      - LOG_SERVER=192.168.0.1
Enter fullscreen mode Exit fullscreen mode

Just like docker run, you can instruct Docker Compose to automatically pull in an existing variable's value from your shell:

services:
  app:
    image: alpine:latest
    environment:
      - LOG_SERVER
Enter fullscreen mode Exit fullscreen mode

Compose also supports interpolation, so you can combine different values into one:

services:
  app:
    image: alpine:latest
    environment:
      - LOG_SERVER=https://${LOG_SERVER}
Enter fullscreen mode Exit fullscreen mode

Interpolation allows you to set a fallback value in case a variable isn't set in your shell:

services:
  app:
    image: alpine:latest
    environment:
      - LOG_SERVER=https://${LOG_SERVER:-127.0.0.1}
Enter fullscreen mode Exit fullscreen mode

Here, the final value of LOG_SERVER inside the container will be taken from the LOG_SERVER variable set in your shell, or 127.0.0.1 if no assignment has been made. Regardless of the variable's source, the value inside the container will always be prefixed with https://.

Using env files with Docker Compose

Compose supports .env files in a similar style to docker run. Use the env_file section of your service definition to specify the path to a file:

services:
  app:
    image: alpine:latest
    env_file: config.env
Enter fullscreen mode Exit fullscreen mode

It's also possible to specify multiple .env files and configure them as optional includes. Files marked as required: false won't prevent docker compose up commands from completing, unlike the default setting, which requires referenced .env files to exist.

Let's see an example:

services:
  app:
    image: alpine:latest
    env_file:
      - path: config.env
        required: true
      - path: config.local.env
        required: false
Enter fullscreen mode Exit fullscreen mode

Remember, you don't always need to specify an env_file option when using Compose: The contents of the .env file in your working directory will be loaded automatically if the file exists. This provides a convenient way to override default values for the environment variables you define in your Compose file's environment section.

Setting container environment variables with Spacelift

Spacelift is a flexible infrastructure orchestration platform that makes it simple to build CI/CD pipelines for your infrastructure. Pipelines are structured as stacks that run jobs inside an isolated Docker container.

When you're using Spacelift, you can define environment variables for your stack by heading to the Environment tab. Here, you can add new key-value environment variable pairs and choose between creating a plain environment variable or a protected secret. The values will then be made available to the jobs in your stack.

Best practices for Docker environment variables

Environment variables are easy to work with in Docker, but there are still a few best practices to consider when using them. Here are a few important tips to consider:

1. Use Docker Secrets instead of environment variables for sensitive values

Environment variables shouldn't be used for sensitive values because they can be easily extracted from containers, including by other processes running on your host. 

For example, the docker inspect command provides the values of all the environment variables set in the container, so it's important to use Docker's dedicated Secrets mechanism to provide API keys, credentials, signatures, and similar protected data types.

2. Ensure your containerized processes are designed to be configured using environment variables

It may sound simple, but many containerization problems stem from developers not designing apps to use environment variables for configuration. Whereas config files may be favored for traditional deployments, adjusting apps to use environment variables instead makes them easier to operate as containers.

3. Prefer .env files and Compose configuration

Using a file-based approach to environment variables makes it easier to check their values, keep track of changes, and provide sensible defaults without making users remember which variables your app requires. Settings can still be easily overridden by specifying multiple .env files when a container starts.

4. Use a consistent environment variable naming scheme

Ensuring all your environment variables have a consistent prefix such as MYAPP_ helps avoid any possible conflicts with keys that are already consumed by other processes on your users' machines.

Remember that, although environment variables are ideal for many situations, they aren't your only option. If you need a very large number of variables or support for typed values, it may still be preferable to use a config file you can mount into a volume in your container's filesystem.

Key points

Environment variables allow you to decouple your app's configuration from its source code. They're a simple but flexible mechanism for customizing how processes behave, including when running in Docker containers.

To use environment variables with docker run, you should use the -e flag or --env-file CLI options. However, if you've got numerous environment variables to inject, it's usually more convenient to list them in a docker-compose.yml file that lets you set default values and ensure important options aren't forgotten.

And if you want to learn more about Spacelift, create a free account today or book a demo with one of our engineers.

Written by James Walker

Top comments (0)