Full lesson
Explore the full explanation, examples, and visuals at your own pace.
Terminal: apply succeeds, app disagrees
You apply the ConfigMap, and kubectl says it's configured. The API even returns true for NEW_CHECKOUT. But the app's log line, which is illustrative here, still says false and the legacy flow. The stored data changed, so why didn't the running app notice?
$ kubectl apply -f flags-configmap.yaml
configmap/app-flags configured
$ kubectl get configmap app-flags -o jsonpath='{.data.NEW_CHECKOUT}'
true
$ kubectl logs deploy/web | tail -1
checkout: NEW_CHECKOUT=false, using legacy flowStored config is not running config
kubectl apply only talks to the API Server, and the API Server stores ConfigMap version two with true. That's where the change ends. Kubernetes doesn't restart Pods for a ConfigMap edit, so the web Pod keeps what it read at start. Whether it ever sees true depends on how the value was delivered.
Same ConfigMap, two delivery paths
Take one ConfigMap, app-flags, with NEW_CHECKOUT set to false. Pod A gets it as an environment variable, copied into the process when the container started. Pod B gets it as a file under /etc/flags, and its app read that file. Both begin with false. Let's trace what happens to each.
deployment.yaml: env vs volume vs subPath
Here's how the two paths look in the manifest. Pod A uses configMapKeyRef, which copies one key into an environment variable. Pod B declares a configMap volume and mounts it at /etc/flags. The gotcha is subPath: mount a single file with it, and Kubernetes never updates that file.
containers:
- name: web
env: # Pod A style
- name: NEW_CHECKOUT
valueFrom:
configMapKeyRef:
name: app-flags
key: NEW_CHECKOUT
volumeMounts: # Pod B style
- name: flags
mountPath: /etc/flags
# gotcha: mountPath /etc/flags/NEW_CHECKOUT
# with subPath: NEW_CHECKOUT never updates
volumes:
- name: flags
configMap:
name: app-flagsPod A: environment frozen at container start
Follow Pod A. The kubelet reads the flag as false and starts the container with that value in its environment. Then kubectl applies true, and the ConfigMap updates. But the running process never hears about it. Its environment was fixed at startup, and nothing outside can change it. Only a new container picks up true.
Pod B: file updates later, app never re-reads
Pod B mounts the ConfigMap as a volume, and at startup the app reads false from the file. After kubectl applies true, the kubelet picks it up on its periodic sync, and then swaps the mounted file. That takes a delay, often tens of seconds. The file now says true, but the app still holds false in memory.
Predict: does the change reach the process?
A ConfigMap edit changes the stored recipe, not the running process. Environment variables and subPath mounts need a new container to see the change. A volume mount does update, after a delay, but only helps if the app re-reads the file. Delivery method plus app behavior decides everything.
Three ways to make the change take effect
You have three fixes, each with a trade-off. A rollout restart is simple, but it's manual and easy to forget. The checksum annotation in Helm automates it, because a config change alters the Pod template and triggers a rollout. App reload skips restarts, but it needs a volume mount and code.
# 1) Restart Pods now
kubectl rollout restart deployment/web
# 2) Tie the Pod template to config content (Helm)
spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
# 3) App reload: watch /etc/flags/NEW_CHECKOUT, re-read on changeBefore you flip the next flag
A ConfigMap edit changes the stored recipe, not the running process. Env vars and subPath need a new container. Volumes update the file eventually, but your app has to re-read it. So check the delivery method before you expect a flag to flip.
- ConfigMap update changes stored data; Pods are not restarted
- Env vars and subPath: new containers needed
- Volumes: file updates later; app must reload

