ConfigMaps
A ConfigMap holds non-sensitive configuration: a feature flag, an nginx.conf, a list of upstream hosts, a log level. The point is to separate what changes between environments from the image that runs in them, so the same image can be promoted from test to production without being rebuilt.
A ConfigMap and a Secret are the same object with different intentions. Everything here applies to Secrets too, with one addition: ConfigMaps are the safe place to keep things you are happy to read in a describe.
Reference
Terminology
- ConfigMap — Key/value data, up to about 1 MiB, that a Pod can consume as environment variables or as files.
binaryData— Base64 values for non-text content, alongside the plain-textdata.immutable— Freezes the contents. The kubelet stops watching it, which matters in clusters with many ConfigMaps and many nodes.subPath— Mounts a single key as a single file instead of mounting the whole ConfigMap as a directory. Convenient, and it breaks live updates — see below.- Projected volume — Combines several ConfigMaps, Secrets and downward-API sources into one mount point.
Creating One
kubectl create configmap app --from-literal=LOG_LEVEL=debug
kubectl create configmap nginx --from-file=./nginx.conf
kubectl create configmap app --from-env-file=./app.env
kubectl create configmap app --from-literal=LOG_LEVEL=debug --dry-run=client -o yaml > app.yaml--from-file uses the filename as the key and the file contents as the value. That is what makes the mounted-file pattern work so naturally: your local nginx.conf becomes /etc/nginx/nginx.conf in the container.
Consuming One
# as environment variables — fixed for the life of the container
envFrom:
- configMapRef:
name: app
# as mounted files — updated when the ConfigMap changes
volumeMounts:
- name: config
mountPath: /etc/app
readOnly: true
volumes:
- name: config
configMap:
name: appThe Update Behaviour, Precisely
| How it is consumed | Updates when the ConfigMap changes? |
|---|---|
| Mounted as a directory | Yes, within about a minute (the kubelet sync period) |
Mounted with subPath | No. The file is a copy, taken when the container started |
| As an environment variable | No. Never. Not even after a restart of the container process |
The third row is the one that catches people: environment variables are resolved by the kubelet when it creates the container. Restarting the process inside the container does not re-read them — only replacing the Pod does.
And because a ConfigMap is not part of the Deployment’s Pod template, changing one does not trigger a rollout. The Deployment has no idea anything changed:
kubectl rollout restart deployment/web # the standard way to pick up a changeExercises
Mount a config file and watch it change.
printf 'log_level: info\n' > app.yaml kubectl create configmap app --from-file=app.yamlWrite a Pod that mounts
appat/etc/appand sleeps. Then change the ConfigMap:printf 'log_level: debug\n' > app.yaml kubectl create configmap app --from-file=app.yaml --dry-run=client -o yaml | kubectl apply -f - kubectl exec <pod> -- cat /etc/app/app.yaml # debug, within a minuteNothing restarted. The file changed underneath the running container, which is why an application that watches its config file needs no rollout at all.
Prove
subPathdoes not update. Mount the same ConfigMap withsubPath: app.yamlat/etc/app/app.yaml, repeat the change, and watch the file stay behind. This is a two-minute experiment that saves an afternoon of confusion later.Show that the Deployment does not notice. Change a ConfigMap consumed as an environment variable, then run
kubectl get pods— same Pods, same age. Onlykubectl rollout restartpicks it up.
Gotchas Worth Knowing
- ConfigMaps are namespaced and can only be referenced from the same namespace.
subPathmounts never update, which is the usual explanation for “my config change did nothing”.- A missing ConfigMap key blocks the Pod from starting unless you mark the reference
optional: true. A Pod stuck inCreateContainerConfigErroris usually a typo’d key name. - Do not put secrets in a ConfigMap because it is more convenient. They are not protected, they show up in
describe, and they end up in dashboards.
What to Take Away
- A ConfigMap separates configuration from the image, so one image can run in every environment.
- Mounted as a directory, it updates live. As environment variables or through
subPath, it does not. - Changing a ConfigMap does not restart anything —
kubectl rollout restartis how you make it happen.