# Day 34: Taming Kubernetes ConfigMaps and PersistentVolumes Like a Pro!


The Mission: ConfigMaps as Volumes and Persistent Storage
Today’s goal was to level up my Flask + Redis app by:
Mounting a ConfigMap as a volume to store Flask’s configuration (like
FLASK_ENV
andREDIS_HOST
) in a file, instead of environment variables.Adding PersistentVolumes (PVs) and PersistentVolumeClaims (PVCs) to make sure Redis data doesn’t vanish when a pod restarts.
Fixing a pesky bug that had my Flask pod in a
CrashLoopBackOff
tantrum (more on that later!).
Kicking Off with a Quick Review
I started by firing up Minikube with minikube start --driver=docker
and checked my Day 33 setup:
kubectl get pods,svc,configmap,secret
minikube service flask-service --url
My Redis pod (redis-5d7f4c7db8-nfxw7
) was happily running, but oh no—my Flask pod (flask-deployment-5b97f5b4f4-6psfd
) was stuck in CrashLoopBackOff
! A quick kubectl logs
revealed the culprit:
NameError: name 'logger' is not defined
Turns out, in my app.py
, I was trying to use logger.info
before defining the logger. Rookie mistake! I’ll fix that soon, but first, I opened vi ~/flask-redis-app/notes/Day_34_Activities.txt
and jotted down the header: Day 34: ConfigMap Volume Mounts and PersistentVolumes - July 4, 2025
.
To warm up, I asked myself: How do ConfigMaps as environment variables (Day 33) differ from Docker environment variables (Day 6)? Easy—Kubernetes ConfigMaps are managed centrally and can be updated dynamically, while Docker env vars are static and tied to the container. Then, I asked Grok (in think mode): “What are the benefits of mounting ConfigMaps as volumes versus using environment variables in Kubernetes?” Grok explained that volumes allow file-based configs, support dynamic updates without pod restarts (if the app reloads files), and are great for complex configs. Environment variables, though simpler, need pod restarts for updates. Mind blown!
Mounting ConfigMaps Like a File Wizard
Time to make my Flask app read its config from a file instead of environment variables. I created a ConfigMap (flask-configmap-volume.yaml
) with a config.ini
file:
vi ~/flask-redis-app/k8s/flask-configmap-volume.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: flask-app-config-volume
data:
config.ini: |
[app]
FLASK_ENV=production
REDIS_HOST=redis-service
APP_PORT=5000
Applied it with kubectl apply -f
and updated my Flask deployment (flask-deployment.yaml
) to mount this striking out environment variables and adding:
spec:
containers:
- name: flask
image: uyap/flask-redis-app_web:latest
volumeMounts:
- name: config-volume
mountPath: /app/config
readOnly: true
volumes:
- name: config-volume
configMap:
name: flask-app-config-volume
Now, the fun part—fixing that NameError
in app.py
. The issue was that I called logger.info
before defining logger
. I rearranged the code to initialize logging first:
import logging
import configparser
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
config = configparser.ConfigParser()
config.read('/app/config/config.ini')
FLASK_ENV = config['app']['FLASK_ENV']
REDIS_HOST = config['app']['REDIS_HOST']
APP_PORT = int(config['app']['APP_PORT'])
logger.info(f"Loaded config: FLASK_ENV={FLASK_ENV}, REDIS_HOST={REDIS_HOST}, APP_PORT={APP_PORT}")
I rebuilt and pushed the Docker image:
cd ~/tmp/flask-redis-app
docker build -t uyap/flask-redis-app_web:latest .
docker push uyap/flask-redis-app_web:latest
kubectl apply -f ~/flask-redis-app/k8s/flask-deployment.yaml
Tested with kubectl exec -it <flask-pod-name> -- cat /app/config/config.ini
—boom, the config file was there! A quick curl <flask-service-url>
confirmed the app was running smoothly. I logged in Day_34_Activities.txt
: “Mounted ConfigMap as volume—feels like giving Flask a config file it can actually read!”
I asked Grok: “How to update ConfigMap volume mounts without restarting pods?” DeepSearch revealed that Kubernetes updates mounted ConfigMap files automatically (within seconds, thanks to kubelet sync). But, my Flask app needs to poll or watch the file for changes to use them without a restart. Noted for future tweaks!
Making Redis Data Stick with PVs and PVCs
Next, I tackled persistent storage for Redis to ensure data survives pod restarts. I created a PersistentVolume (redis-pv.yaml
):
apiVersion: v1
kind: PersistentVolume
metadata:
name: redis-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /mnt/redis-data
And a PersistentVolumeClaim (redis-pvc.yaml
):
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Applied them with kubectl apply -f
, then updated redis-deployment.yaml
:
spec:
containers:
- name: redis
image: redis:latest
volumeMounts:
- name: redis-storage
mountPath: /data
volumes:
- name: redis-storage
persistentVolumeClaim:
claimName: redis-pvc
After reapplying with kubectl apply -f
, I tested persistence:
curl <flask-service-url>/set_key?key=test&value=123
kubectl delete pod -l app=redis
kubectl get pods # Wait for new pod
curl <flask-service-url>/get_key?key=test
The key test=123
was still there—success! I checked the PV/PVC binding with kubectl describe pvc redis-pvc
and logged: “Redis data is now sticky like glue!”
I asked Grok: “What’s the difference between hostPath and other storage classes in Minikube?” DeepSearch explained that hostPath
is simple, using Minikube’s local filesystem (e.g., /mnt/redis-data
), but data may vanish on restarts if the directory isn’t persistent. Other storage classes, like CSI drivers, offer features like snapshots but need addons. For Minikube, hostPath
is perfect for testing.
Polishing the App and Blogging
I added a log to app.py
for Redis persistence:
logger.info(f"Redis data persisted at: /data")
Rebuilt, pushed, and redeployed the image, then checked logs with kubectl logs -l app=flask
. All good!
Committed to GitHub:
git add .
git commit -m "Day 34: ConfigMap volume mounts and PV/PVC for Redis"
git push origin main
Key Takeaways
Today was a blast! Fixing that NameError
felt like solving a puzzle, and seeing Redis data persist was pure joy. ConfigMap volume mounts are like giving your app a config file it can read anytime, and PV/PVCs are the superheroes of data durability. Next up, I’m eyeing StorageClasses or Ingress for Day 35. Stay tuned, and let’s keep rocking this Kubernetes adventure!
Subscribe to my newsletter
Read articles from Usman Jap directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
