Day 8: Securing My Flask App with Docker Compose Env Vars and Secrets!


Day 8 was a deep dive into Docker Compose environment variables and secrets, leveling up my Flask + Redis app with secure configurations. I wrestled with errors, explored 2025 DevOps trends on X, and leaned on Grok to sharpen my skills. Buckle up for a 1500-word journey through secure DevOps, with a sprinkle of 2025 flair!
Kicking Off with Environment Variables
After conquering scaling and volumes on Day 7, I shifted gears to make my Flask + Redis app more portable and secure using environment variables and secrets. My goal was to configure the app dynamically, avoiding hardcoded values, and protect sensitive data like passwords. I started in my Ubuntu environment:
bash
cd ~/tmp/flask-redis-app
My docker-compose.yml from Day 7 defined a web (Flask) and redis service, with a redis-data volume. I modified app/app.py to use environment variables for the Redis host and app title:
python
import os
from flask import Flask
from redis import Redis
app = Flask(__name__)
redis_host = os.getenv('REDIS_HOST', 'redis')
app_title = os.getenv('APP_TITLE', 'My Flask App')
redis = Redis(host=redis_host, port=6379)
@app.route('/')
def hello():
count = redis.incr('hits')
return f'{app_title}: Visited {count} times.'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
I updated docker-compose.yml to include environment variables:
yaml
services:
web:
build: .
ports:
- "5000:5000"
environment:
- REDIS_HOST=redis
- APP_TITLE=Awesome Flask App
depends_on:
- redis
networks:
- flask-net
I also created an .env file for portability:
bash
echo "REDIS_HOST=redis" > .env
echo "APP_TITLE=App from .env" >> .env
Running docker compose up -d --build and hitting http://localhost:5000 showed: “App from .env: Visited 1 times.” Success! This made my app environment-agnostic, a 2025 DevOps must-have.
Adding Secrets for Security
Next, I tackled secrets to secure a Redis password. I created redis_password.txt:
bash
echo "supersecretpassword" > redis_password.txt
I updated docker-compose.yml to use secrets:
yaml
services:
redis:
image: redis:latest
command: redis-server --requirepass ${REDIS_PASSWORD}
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD}
secrets:
- redis_password
volumes:
- redis-data:/data
networks:
- flask-net
secrets:
redis_password:
file: ./redis_password.txt
I modified app/app.py to read the secret:
python
redis = Redis(host=redis_host, port=6379, password=open('/run/secrets/redis_password').read().strip())
But chaos ensued…
Battling Interpolation Errors
My first attempt to set REDIS_PASSWORD via environment: - REDIS_PASSWORD=$(cat redis_password.txt) triggered:
ERROR: Invalid interpolation format for "environment" option in service "redis": "REDIS_PASSWORD=$(cat redis_password.txt)"
Grok explained: Docker Compose doesn’t support shell substitution ($(cat ...)) in environment. I moved the password to .env:
REDIS_PASSWORD=supersecretpassword
Updated docker-compose.yml to use ${REDIS_PASSWORD}, and it worked! I tested:
bash
docker compose up -d
curl http://localhost:5000
Output: “App from .env: Visited 2 times.” Redis authenticated correctly:
bash
docker exec -it $(docker compose ps -q redis) redis-cli
AUTH supersecretpassword
GET hits
Counter: 2. Persistence held after docker compose down and up -d.
The ContainerConfig Snafu
Another error hit during docker compose up -d --build:
ERROR: for redis 'ContainerConfig'
KeyError: 'ContainerConfig'
This was a compatibility issue with an outdated Compose version (1.29.2). I upgraded to v2.36.2:
bash
sudo rm /usr/bin/docker-compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
Verified:
bash
docker compose version
Output: Docker Compose version v2.36.2. With Docker 28.1.1, I reran and the error vanished.
The --resolve-env Misstep
I tried inspecting variables with:
bash
docker compose config --resolve-env
But got:
unknown flag: --resolve-env
Grok clarified: --resolve-env doesn’t exist! docker compose config already resolves variables. Running:
bash
docker compose config
Showed REDIS_PASSWORD: supersecretpassword. Lesson learned: stick to documented flags.
Mastering Configuration Commands
I practiced Day 8 commands:
docker compose config: Validated YAML and variable substitution.
docker compose run web env: Showed REDIS_HOST=redis, APP_TITLE=App from .env.
docker compose run redis cat /run/secrets/redis_password: Confirmed supersecretpassword.
I tested an external secret:
bash
echo "newsecretpass" > external_redis_password.txt
Updated docker-compose.yml:
yaml
secrets:
redis_password:
file: ./external_redis_password.txt
Reran and verified with redis-cli AUTH newsecretpass. This mimicked 2025’s dynamic secret management.
Grok’s Wisdom and X Insights
Grok’s think mode shone with queries:
“Explain .env files in Docker Compose in 100 words”: They store key-value pairs for portability, loaded automatically, overridden by environment.
“Best practices for secrets in 150 words”: Use secrets for sensitive data, mount at /run/secrets/, integrate with Vault in 2025 fintech apps.
“Environment variables portability in 100 words”: They decouple configs, enabling seamless environment switches.
Using DeepSearch, I found X posts on 2025 Compose environment variables:
@TheDockerDev
(May 21, 2025): “Advanced patterns for on-prem SaaS, secure secret management.” (140 views, 5 faves). Secrets complement env vars for secure configs.
@DOh_Bams
(May 26, 2025): “Best practices like secrets, health checks.” (627 views, 26 faves). Env vars underpin these practices.
A 50-word summary for @TheDockerDev:
@TheDockerDev
shares advanced Docker Compose patterns for 2025 on-prem SaaS, emphasizing secure secret management. Environment variables configure services dynamically, ensuring portability and security, aligning with scalable DevOps trends.
Error-Fixing Adventures
Day 8 was an error-fixing marathon:
Interpolation errors: Fixed by using .env instead of $(cat ...).
ContainerConfig: Resolved with Compose v2.36.2.
--resolve-env: Dropped for docker compose config.
Grok’s step-by-step guidance was clutch, reinforcing my DevOps debugging skills.
Subscribe to my newsletter
Read articles from Usman Jap directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
