ConfigMap as env and as volume
Three ways to pass settings into a Pod from a ConfigMap, and how they differ when the data changes.
Why ConfigMap
In the previous lesson, settings sat right in the Pod manifest, in the
env block. That works as long as there's one Pod and one environment.
Once the same image ships to dev, staging and prod, it's easier to keep
settings in a separate object and plug in the right one for each
environment.
A ConfigMap is a Kubernetes object holding key/value pairs, stored in the cluster's API (backed by etcd). On its own it does nothing. You put app settings into it (a database URL, a run mode, a log level), and the Pod picks how to consume them: as env variables or as files.
The image stays the same, each environment gets its own ConfigMap.
A ConfigMap stores values in plain text, visible to anyone with read access to ConfigMaps in the namespace. Put public settings there, not passwords. For passwords there's Secret, covered in the next lesson.
The minimal YAML
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_MODE: prod
APP_LOG_LEVEL: info
data is a map of strings. Numbers and booleans are written in quotes,
same as in env. A multi-line value (a whole nginx.conf, say) is written
in YAML with |. There's also binaryData for binary files in base64,
but that's rare.
The same thing from the command line:
kubectl create configmap app-config --from-literal=APP_MODE=prod --from-literal=APP_LOG_LEVEL=info
With the flag --from-file=./config.json, the key becomes the file name
(config.json), the value its contents.
How to attach it to a Pod
An env variable from a specific key
env:
- name: APP_MODE
valueFrom:
configMapKeyRef:
name: app-config
key: APP_MODE
The reference has two parts: the ConfigMap's name (name) and a key
inside it (key). The variable's name in the container (APP_MODE on
the first line) doesn't have to match the key.
kubelet reads the key once, when it creates the container, and puts the
value into env. If you change the ConfigMap, env inside the running
container doesn't update. The Pod has to be recreated, which for a
Deployment is kubectl rollout restart.
All keys at once through envFrom
envFrom:
- configMapRef:
name: app-config
Every key of the ConfigMap becomes an env variable with the same name.
Handy when there are many keys and they're already named the way you want.
They update the same way as env.valueFrom: only when the container is
recreated.
The ConfigMap got deleted or its name was misspelled. A running container
survives on its old env, but the next time the container starts (a
restart after a crash, a new Pod) it lands in
CreateContainerConfigError. The cause is written in the Pod's events:
kubectl describe pod <name>, the Events block.
A volume of type configMap
volumes:
- name: config
configMap:
name: app-config
items:
- key: APP_LOG_LEVEL
path: log.level
volumeMounts:
- name: config
mountPath: /etc/config
volumes is described at the Pod's spec level, volumeMounts on the
container. The volume's name is the same in both places.
A volume behaves differently from env. kubelet periodically checks the
files against the current version of the ConfigMap and rewrites them.
data changes, and roughly a minute later the file inside the Pod
updates. The exact delay depends on kubelet's sync period and its cache.
For the new value to take effect, the app has to reread the file itself:
on a timer, on a filesystem event, or on a signal. nginx, for example,
rereads its config on SIGHUP (nginx -s reload).
The items block is needed when the app doesn't need every key, or the
file name has to differ from the key name. Without items, every key
becomes a file with its own name. With items, only the listed keys show
up in the directory.
Three ways side by side
The three ways to attach a ConfigMap differ in whether the data updates in a running Pod:
| way | what it gives | updates live |
|---|---|---|
env.valueFrom | one key in env | no, the Pod must be recreated |
envFrom | all keys in env | no, the Pod must be recreated |
| volume | keys as files | yes, kubelet syncs with a delay |
Env is a process's memory: it was set at startup, and nothing outside can change it. kubelet can rewrite a file in a volume at any moment.
Related commands
kubectl create configmap app-config --from-literal=APP_MODE=prod
kubectl create configmap app-config --from-file=./config.json
kubectl get configmap app-config -o yaml
kubectl describe configmap app-config
kubectl edit configmap app-config
kubectl explain pod.spec.containers.envFrom
kubectl explain pod.spec.volumes.configMap --recursive
Common mistakes
- The ConfigMap was updated, but env in the Pod didn't change. Env never updates live, only files from a volume do. Either recreate the Pod or read the setting from a file.
- A file from a ConfigMap was mounted through
subPath, to place it in a directory alongside other files. kubelet never updates a file mounted that way, even after the ConfigMap changes. - A Pod sits in
CreateContainerConfigError. A container like this has no logs, it never ran. The cause is in the Pod's events (kubectl describe pod): a reference to a ConfigMap or a key doesn't match what's actually in the cluster. - The data in one ConfigMap is capped at 1 MiB. Large files don't belong there.
- A ConfigMap lives in a namespace. A Pod can only reference a ConfigMap from its own namespace, there's no field for a ConfigMap in another one.
What you'll need for the tasks
- Lab 1 (
labs/01-web-config):kubectl create configmap --from-literal,envFrom, aconfigMapvolume withitems, editing a ConfigMap and seeing the difference between env and a file on a live Pod. - Lab 2 (
labs/02-api-missing-key): working throughCreateContainerConfigErrorwithkubectl describe pod, checkingconfigMapKeyRefagainst the ConfigMap's data, fixing a Deployment. - Commands:
kubectl get configmap -o yaml,kubectl edit,kubectl logs,kubectl exec,kubectl describe pod.
Homework
Practice the theory on your own cluster: 3 steps with a check. Set up the cluster with the Kubernetes locally track, the tasks live in the k8s-practice repository.
./run.sh start k8s-configmap # set up the starting state
./run.sh verify k8s-configmap # check the current step
In short
- A ConfigMap stores key/value pairs in plain text. For passwords there's Secret.
- A key reaches a Pod three ways:
env.valueFrom,envFrom, a volume of typeconfigMap. - Both env forms are read once, at container start. To pick up an update, recreate the Pod.
- The volume form updates on its own: kubelet syncs files with a delay of
about a minute. Updates never reach a file mounted through
subPath. - Data is capped at 1 MiB. A ConfigMap is only visible to Pods in its own namespace.
Done reading?
Mark the lesson as read to move your track progress forward.
Lesson marked as done.
Go through it with an AI agent
The agent explains anything unclear in plain words, gives you 2 labs for this lesson and drills you on interview questions. $49 one-time, lifetime access.
Tell the agent: use MCP izi, give me lesson k8s-config-02-configmap
Progress saved in this browser
Clear your history or open this on your phone, and the marks will be gone. Leave your email and they'll move to your account. No password needed.
Done. moved to your account. You can see your progress on any device. My progress