Day 30: The Multi-Environment Magic Show


Setting the Stage: What’s Multi-Environment Configs?
Imagine your app as a theater production. In development, you’re rehearsing with a small crew (light resources, debug logs). In staging, you’re doing a dress rehearsal with a bigger setup (more replicas, stricter settings). In production, it’s showtime with a full audience (high availability, tight security). Docker Compose’s multi-environment configs let you switch between these “stages” without rewriting your script (aka docker-compose.yml
). Using .env
files, override YAMLs, and variable substitution, I made my Flask + Redis app shine in dev, staging, and prod—each with its own vibe!
Act 1: Crafting Environment-Specific .env
Files
First, I navigated to ~/tmp/flask-redis-app
and whipped up three .env
files using vi
(because nano
is so last week 😉):
.
env.dev
:FLASK_ENV=development APP_TITLE=Dev Flask App REDIS_HOST=redis-service LOG_LEVEL=DEBUG
.env.staging
:FLASK_ENV=staging APP_TITLE=Staging Flask App REDIS_HOST=redis-service LOG_LEVEL=INFO
.
env.prod
:FLASK_ENV=production APP_TITLE=Prod Flask App REDIS_HOST=redis-service LOG_LEVEL=ERROR REDIS_PASSWORD=my-redis-password
These files are like costume changes for my app—each sets the mood (and settings) for its environment. I used vi
, hitting i
to insert, typing away, and saving with Esc
, :wq
. Easy peasy!
Act 2: Override Files for the Win
Next, I created override files (docker-compose.dev
.yml
, docker-compose.staging.yml
, docker-compose.prod
.yml
) to tweak settings like ports and replicas. For example, docker-compose.prod
.yml
:
services:
web-prod:
environment:
- FLASK_ENV=${FLASK_ENV}
- APP_TITLE=${APP_TITLE}
- LOG_LEVEL=${LOG_LEVEL}
- REDIS_HOST=${REDIS_HOST}
- REDIS_PASSWORD=${REDIS_PASSWORD}
deploy:
replicas: 3
nginx-prod:
ports:
- "8082:80"
These overrides layer on top of my base docker-compose.yml
, letting me scale to three replicas in production or map different ports (e.g., 8080
for dev, 8081
for staging). Variable substitution (${VARIABLE}
) is the secret sauce, pulling values from the .env
files. It’s like giving my app a wardrobe that fits every occasion!
Act 3: The Redis Authentication Drama 😱
Midway through testing, disaster struck! My production containers (web-prod-1
) were marked “unhealthy” with a dreaded redis.exceptions.AuthenticationError: Authentication required
. Turns out, my Redis service in production used requirepass my-redis-password
, but my Flask app wasn’t sending the password. No wonder it was throwing a tantrum!
I dove into app/
app.py
with vi
and updated the Redis connection:
redis = redis.Redis(
host=os.getenv('REDIS_HOST', 'redis-service'),
port=6379,
password=os.getenv('REDIS_PASSWORD'),
decode_responses=True
)
I added REDIS_PASSWORD=my-redis-password
to .
env.prod
and updated docker-compose.prod
.yml
to pass it to web-prod
. After rebuilding with:
docker compose --env-file .env.prod -f docker-compose.yml -f docker-compose.prod.yml up -d --build --wait
I ran docker compose ps
and saw all containers glowing “Healthy.” A quick curl
http://localhost:8082
confirmed: “Prod Flask App: Visited 1 times.” Crisis averted! 🎉 I committed the fix to GitHub with:
git add app/app.py .env.prod docker-compose.prod.yml
git commit -m "Fix Redis authentication for production"
git push origin main
Act 4: Mastering Commands and Grok Queries
To lock in my skills, I practiced multi-environment commands:
docker compose --env-file .env.staging config
: Validated my staging setup.docker compose exec web env
: Peeked at environment variables.docker compose ps
: Checked running services.
I also tapped Grok’s brain on grok.com, asking, “How does variable substitution improve Docker Compose flexibility?” Grok explained it makes configs reusable and CI/CD-friendly—super handy! Using DeepSearch, I found an X post from 2025 praising .env
files for simplifying deployments. I jotted insights in day_30_notes.txt
for active recall, reinforcing my learning.
Learning Hacks: Spaced Repetition and Active Recall
To keep my brain sharp, I used spaced repetition to review Day 27’s named volumes and Day 28’s CPU pinning, skipping overlapping topics like Day 19’s secrets. For active recall, I wrote a 50-word summary of multi-environment benefits in day_30_notes.txt
: “Multi-environment configs make deployments flexible, reusable, and scalable. Using .env
files and overrides, I tailored my Flask app for dev, staging, and prod without code changes. Variable substitution simplifies setup, and X posts confirm it’s a 2025 must-have!”
Why This Matters
Multi-environment configs are a game-changer for real-world apps. They let you test in dev, refine in staging, and shine in production without rewriting code. Fixing the Redis authentication bug taught me to double-check environment-specific settings— a lesson I’ll carry to Kubernetes next week!
Subscribe to my newsletter
Read articles from Usman Jap directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
