Stage 4 · Provision
Running & Networking Containers
Environment Variables
Pass env vars with -e and --env-file, separate config from images, and avoid leaking secrets.
Why Environment Variables?
Environment variables are the standard way to configure containers without modifying the image. They let you change database URLs, API keys, feature flags, and other settings between environments without rebuilding. Twelve-factor app methodology recommends storing configuration in the environment.
Passing Env Vars
# Single variable
docker run -e DATABASE_URL=postgres://db:5432/app myapp
# Multiple variables
docker run \
-e DATABASE_URL=postgres://db:5432/app \
-e REDIS_URL=redis://cache:6379 \
-e NODE_ENV=production \
myapp
# Pass from host
export API_KEY=secret123
docker run -e API_KEY myapp
# Override image ENV
docker run -e NODE_ENV=development myapp
# Overrides ENV NODE_ENV=production in DockerfileThe -e flag sets an environment variable for the container. If the variable exists in the image (via ENV), the -e value overrides it for that container.
Env Files
For many variables, passing them individually with -e is tedious. The --env-file flag reads variables from a file, keeping your command clean and your configuration organized.
# Create an env file
cat > .env << EOF
DATABASE_URL=postgres://db:5432/app
REDIS_URL=redis://cache:6379
NODE_ENV=production
LOG_LEVEL=info
EOF
# Use the env file
docker run --env-file .env myapp
# Multiple env files
docker run --env-file .env.production --env-file .env.secrets myappEnv files use the format KEY=VALUE, one per line. Lines starting with # are comments. Empty lines are ignored. The --env-file flag can be specified multiple times.
Env files often contain database passwords and API keys. Add .env and .env.* to .gitignore. Use .env.example with placeholder values to document required variables.
Config Separation
Environment variables separate configuration from code. The same image runs in development, staging, and production — only the environment variables change. This is a fundamental container best practice.
# Development
docker run -e NODE_ENV=development -e DEBUG=true myapp
# Staging
docker run -e NODE_ENV=staging -e DEBUG=false myapp
# Production
docker run -e NODE_ENV=production -e DEBUG=false myappThe image is identical in all three cases. Only the environment changes. This eliminates environment-specific builds and ensures consistency.
Avoiding Leaks
Environment variables are visible in docker inspect, docker history, and process listings. They should never contain long-lived secrets. Use BuildKit secret mounts for build-time secrets and runtime secret management for production secrets.
# Anyone with Docker access can see env vars
docker inspect mycontainer --format '{{.Config.Env}}'
# [DATABASE_URL=postgres://db:5432/app API_KEY=secret123]
# Env vars are visible in process listings
docker exec mycontainer ps aux
# Can show command-line arguments with env vars
# Never hardcode secrets in Dockerfiles
# BAD: ENV API_KEY=secret123
# GOOD: Pass at runtime with -e or --env-filedocker inspect shows all environment variables. If an attacker gains access to the Docker daemon, they can read every env var in every container. Keep secrets in a proper secret management system.
Inspecting Env Vars
# List all env vars in a container
docker exec mycontainer env
# Inspect env vars as JSON
docker inspect mycontainer --format '{{json .Config.Env}}'
# Check a specific variable
docker exec mycontainer printenv NODE_ENV
# View env vars in docker ps output
docker ps --format "table {{.Names}} {{.Image}}"docker exec env shows the runtime environment. Variables set by ENV in the Dockerfile and -e at runtime are both visible.
docker exec mycontainer printenv VAR_NAME is the quickest way to verify a specific environment variable. It prints just the value, making it easy to use in scripts.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.