🔐 Docker Environment Variables & Secrets¶
The Complete Guide for DevOps & Backend Engineers (With Hands-On Labs)¶
Docker makes packaging and running applications easy — but config & secrets management is where most beginners make mistakes.
This guide covers:
-
.envfiles -
Environment variables
-
Passing configs securely
-
Docker Compose best practices
-
Docker Secrets (Swarm)
-
Avoiding accidental secret leaks
-
Hands-on labs
-
Interview questions
Let’s go deep.
1️⃣ Why Environment Variables Matter¶
Traditional apps load config from files.
Containers load config from environment variables, enabling:
✔ Immutable images
✔ Configurable deployments
✔ CI/CD-friendly pipelines
✔ Easy switching between environments
✔ Avoiding secrets inside images
A modern production workflow looks like:
Build → Push → Deploy ↘ configs/secrets applied at runtime
2️⃣ Passing Environment Variables to Containers¶
Method 1 — Using -e flag¶
docker run -e PORT=3000 -e NODE_ENV=production node-app
Method 2 — Using an env file¶
.env
PORT=3000 DB_USER=admin DB_PASS=strongpass
Run:
docker run --env-file .env node-app
This is better, cleaner, portable.
Method 3 — Docker Compose¶
app: image: node-app environment: - PORT=3000 - DB_USER=admin
or load .env automatically (Compose does this by default).
3️⃣ How .env Files Work (Most Misunderstood Topic)¶
docker-compose automatically loads .env from the directory where docker-compose.yml exists.
Example:
.env docker-compose.yml
Variables inside:
APP_NAME=myapp PORT=8000
Compose now supports:
services: api: image: node environment: - PORT=${PORT}
⚠ .env is NOT for secrets in production¶
Store ONLY non-sensitive things like:
-
Ports
-
Project names
-
ENABLE_FEATURE flags
4️⃣ The Danger: ENV Vars Are Visible Everywhere¶
Secrets passed via environment variables can be exposed through:
-
docker inspect -
docker history -
Or worse — logs
Example:
docker inspect container
Leaks:
"Env": [ "DB_PASS=supersecret" ]
❌ Never store passwords, API keys, tokens in:¶
-
Dockerfile
-
.envcommitted to Git -
Compose environment block (unless dev)
5️⃣ Introducing Docker Secrets (Production-Grade)¶
Docker Secrets store sensitive data:
✔ Encrypted
✔ Not visible via docker inspect
✔ In-memory only
✔ Mounted as temporary files
✔ Designed for Swarm, but usable with replacements for non-swarm setups
Secrets are not environment variables.
They are files mounted inside /run/secrets/.
6️⃣ Docker Swarm Secrets (Official)¶
Step 1: Create a secret¶
echo "mystrongpassword" | docker secret create db_pass -
Step 2: Attach secret to service¶
docker service create \ --name mydb \ --secret db_pass \ postgres
Inside the container:
/run/secrets/db_pass
You read it in your code as a file, not ENV var.
7️⃣ Hands-On Lab — Node.js App Using Docker Secrets¶
Step 1: Create the secret¶
echo "supersecret123" | docker secret create mongo_pass -
Step 2: Create service¶
docker service create \ --name api \ --secret mongo_pass \ node-app
Step 3: Inside your app, read:¶
Node.js example:
const fs = require("fs"); const password = fs.readFileSync("/run/secrets/mongo_pass", "utf8").trim();
8️⃣ Using Secrets Without Swarm (Production Hack)¶
Most companies using Docker without Swarm use:
-
Kubernetes Secrets
-
Vault
-
Doppler
-
AWS SSM Parameter Store
-
GCP Secret Manager
But you can emulate secrets in Docker Compose using:
Option 1 — Mount secrets as files¶
Create folder:
secrets/ db_pass.txt
Compose:
services: api: image: node-app volumes: - ./secrets/db_pass.txt:/run/secrets/db_pass:ro
Option 2 — Use Docker Compose Secrets (v3.7+)¶
secrets: db_pass: file: ./secrets/db_pass.txt services: api: image: node-app secrets: - db_pass
Works even without Swarm (Compose v2.20+).
9️⃣ Preventing Secrets From Leaking (Best Practices)¶
✔ Avoid secrets inside Dockerfile¶
Bad:
ENV DB_PASS=12345
Leaks via:
-
docker history
-
docker inspect
Good:
Pass at runtime only.
✔ Use .dockerignore¶
Add:
.env secrets/
To prevent accidental Git leaks.
✔ Use runtime secret files¶
Apps should load secrets like:
cat /run/secrets/db_pass
Not env vars.
✔ Never commit plain .env to Git¶
Instead commit:
.env.example
Containing:
DB_USER= DB_PASS= PORT=3000
🔒 Super-Secure Pattern (Used in Fortune 500)¶
Use:
ENV VAR → points to secret path APP reads secret file
Example:
environment: SECRET_PATH=/run/secrets/api_key secrets: - api_key
App loads:
fs.readFileSync(process.env.SECRET_PATH)
Result:
✔ Secret not stored in env
✔ Secret not visible in container metadata
✔ Only your app can access it
🧪 Hands-On Labs (Practice Projects)¶
Lab A — Compose App With Env Vars (Dev)¶
docker-compose.yml
services: web: image: node:18 working_dir: /app volumes: - ./app:/app environment: PORT: ${PORT} GREETING: ${GREETING}
.env
PORT=3000 GREETING=Hello from Docker
Run:
docker compose up
Visit:
http://localhost:3000
Lab B — Compose App With Secrets (Prod)¶
Folder:
secrets/ api_key.txt
docker-compose.yml
services: api: image: node-app secrets: - api_key secrets: api_key: file: ./secrets/api_key.txt
Run:
docker compose up
Inside container:
cat /run/secrets/api_key
👨💼 Interview Questions (With Answers)¶
❓1. Why are environment variables dangerous for secrets?¶
Because they show up in:
-
docker inspect
-
process list
-
logs
-
crash reports
❓2. How do Docker Secrets differ from env vars?¶
| Feature | ENV Vars | Docker Secrets |
|---|---|---|
| Visibility | Visible via inspect | Hidden |
| Security | Low | High |
| Storage | In container metadata | In encrypted secret store |
| Access | Key=value | File under /run/secrets |
❓3. Can you use Docker Secrets without Swarm?¶
YES — using:
-
Docker Compose secrets (v3.7+)
-
Mounted secret files
❓4. How do you prevent leaking .env?¶
Add it to .gitignore and .dockerignore.
❓5. Should you store secrets in Docker images?¶
NEVER.
Use runtime injection only.
🏁 Final Summary¶
You now know:
-
.envfiles -
Passing env vars correctly
-
Secret management
-
Production-safe patterns
-
Docker Secrets (Swarm + Compose)
-
Hands-on labs
-
Interview answers
This is everything required for backend + DevOps interviews.
21. Using Configs¶
configs:
nginx_conf:
file: ./nginx.conf