Environment Variables and Configuration Management
Introduction
As applications become more complex, managing their configuration becomes crucial, especially in containerized environments like Docker. Hardcoding sensitive or environment-specific information (such as database credentials or API keys) in images or code is insecure and inflexible. Instead, Docker provides mechanisms to inject configuration at runtime using environment variables and external configuration files. This lesson explores how to effectively manage environment variables and configuration in Docker containers.
Why Configuration Management Matters
- Separation of concerns: Keeps configuration separate from application code.
- Security: Prevents sensitive data from being baked into images.
- Portability: Makes containers easily reusable across development, staging, and production environments.
- Flexibility: Allows quick changes without rebuilding images.
Setting Environment Variables in Docker
Using the docker run Command
You can pass environment variables directly when starting a container:
docker run -e APP_ENV=production -e DEBUG=false mywebapp:latest
-eor--env: Sets an environment variable.
Example:
docker run -e MYSQL_ROOT_PASSWORD=supersecret mysql:8.0
Using Environment Files (--env-file)
You can store variables in a file and load them all at once:
.env file:
APP_ENV=production
DEBUG=false
SECRET_KEY=mysupersecretkey
Run with env file:
docker run --env-file .env mywebapp:latest
Benefits:
- Easy to manage and version control (be careful with secrets!)
- Keeps run commands clean
Defining Environment Variables in Dockerfiles
You can set default environment variables in your Dockerfile using the ENV instruction:
FROM node:18-alpine
ENV NODE_ENV=production
ENV PORT=3000
CMD ["node", "app.js"]
How it works:
- These defaults can be overridden at runtime with
docker run -e.
Accessing Environment Variables in Applications
Most programming languages provide access to environment variables. For example:
Node.js:
const port = process.env.PORT || 3000;
console.log(`Server running on port ${port}`);
Python:
import os
db_url = os.environ.get('DATABASE_URL', 'localhost')
print(f"Connecting to {db_url}")
Using Environment Variables in Docker Compose
Docker Compose supports environment variables for service configuration.
Option 1: Inline in docker-compose.yml
services:
web:
image: mywebapp:latest
environment:
- APP_ENV=production
- DEBUG=false
Option 2: Reference an .env File
- By default, Compose looks for a file named
.envin the project directory.
.env:
APP_ENV=production
DEBUG=false
docker-compose.yml:
services:
web:
image: mywebapp:latest
environment:
- APP_ENV
- DEBUG
Configuration Files and Secrets
While environment variables are convenient, they are not always ideal for large or sensitive configurations.
Mounting Configuration Files
You can mount configuration files as volumes:
docker run -v /host/config/app.conf:/app/app.conf mywebapp:latest
Use Case: Complex config files (e.g., YAML, JSON) or files required by application frameworks.
Managing Secrets
Best Practices:
- Avoid putting secrets in images or code.
- Use Docker Secrets (with Swarm) or external secret managers (e.g., HashiCorp Vault, AWS Secrets Manager).
Common Use Cases
- Multiple environments: Set variables to distinguish between dev, staging, and prod.
- Feature toggles: Enable or disable features via env vars.
- Database connections: Pass DB credentials without hardcoding.
- API keys: Inject third-party service keys at runtime.
Common Mistakes and Pitfalls
- Hardcoding secrets in images: Never store passwords or keys directly in Dockerfiles.
- Committing
.envfiles with secrets: Use.gitignoreto avoid accidental leaks. - Typos in variable names: Misspelled names can lead to unexpected application behavior.
- Environment variable precedence: Variables set at runtime override Dockerfile defaults.
- Exposing secrets via process listings: Avoid passing secrets as command-line arguments, as they can be visible in process listings.
Summary
- Environment variables are the standard way to inject configuration into Docker containers.
- Use
-e,--env-file, orENVin Dockerfile to set environment variables. - Docker Compose integrates environment variables seamlessly.
- For sensitive or complex configuration, consider file mounts or secret management tools.
- Avoid common mistakes like hardcoding secrets or committing them to version control.
Quiz
-
Which of the following is NOT a recommended method for injecting sensitive data into a Docker container?
a)
docker run -e MYSQL_PASSWORD=supersecret mysql:8.0
b) Using Docker Secrets with Swarm
c) Baking passwords directly into the application code
d) Mounting a secrets file as a volume -
How can you override an environment variable set in a Dockerfile at runtime?
a) You cannot override it
b) By using the-eflag indocker run
c) By modifying the Dockerfile and rebuilding the image
d) By changing the application code -
In Docker Compose, where does Compose look for environment variables by default?
a)
/etc/environment
b) The.envfile in the project directory
c)/var/lib/docker/env
d) The Dockerfile -
True or False: Environment variables set in a
.envfile are automatically available to all containers started with adocker runcommand. -
What is a potential security risk of passing secrets as command-line arguments to a container?
a) The arguments can be seen in process listings
b) They make the container run faster
c) They are automatically encrypted
d) They are stored in the container image
Answers
- c — Baking passwords directly into the application code is insecure and should be avoided.
- b — Use the
-eflag to override environment variables at runtime. - b — Docker Compose looks for a
.envfile in the project directory by default. - False —
.envfiles are not used bydocker run; they are used by Docker Compose or with--env-file. - a — Secrets passed as command-line arguments can be visible to other users/processes on the host via process listings.