ConfigMaps — Full Reference¶
Reference: https://kubernetes.io/docs/concepts/configuration/configmap/
What Is a ConfigMap and Why Does It Exist¶
A ConfigMap stores non-sensitive configuration data as key-value pairs, decoupled from the container image.
The problem it solves: without ConfigMaps, every environment difference (dev DB URL vs prod DB URL, log level debug vs error) means either a different container image per environment, or hardcoded values in the pod spec. Both are bad.
With ConfigMaps: one pod spec, multiple ConfigMaps. The pod spec says "get APP_ENV from configmap app-config." The dev cluster has app-config with APP_ENV=development. The prod cluster has app-config with APP_ENV=production. Same image, same pod spec, different config.
ConfigMap vs Secret¶
| ConfigMap | Secret | |
|---|---|---|
| Data type | Non-sensitive config | Sensitive data (passwords, tokens, certs) |
| Storage in etcd | Plain text | Base64-encoded (not encrypted by default) |
Display with kubectl get -o yaml |
Values visible | Values base64-encoded |
kubectl describe |
Values visible | Values hidden (shows key names and sizes only) |
| Access restriction | Standard RBAC | Same RBAC, but you'd restrict more tightly |
| Size limit | 1MB | 1MB |
Rule of thumb: if it's a password, token, or certificate — use Secret. Everything else — ConfigMap.
Pros and Cons¶
Pros:
- Decouples config from code — change config without rebuilding the image
- Same pod spec works across environments (dev/staging/prod) by swapping ConfigMaps
- Can be mounted as files — useful for apps that read config from disk (nginx.conf, app.properties)
- Easy to update with kubectl edit or kubectl apply
- Visible in plain text — easy to inspect and debug
Cons:
- Not encrypted — anyone with kubectl get configmap access can read all values. Don't put passwords here.
- Env var injection is not dynamic — updating a ConfigMap doesn't update running pods' env vars. You must restart/recreate pods.
- Volume mounts do eventually sync (~1-2 min), but there's a delay — not instant.
- 1MB size limit — can't store large files or binary data.
- No versioning built-in — if you update a ConfigMap and something breaks, there's no rollback mechanism. You'd need to manage that yourself (GitOps helps here).
Creating ConfigMaps¶
Imperative — from literals¶
kubectl create configmap app-config \
--from-literal=APP_ENV=production \
--from-literal=LOG_LEVEL=info \
--from-literal=DB_HOST=postgres.svc.cluster.local
Each --from-literal=KEY=VALUE becomes one key in the ConfigMap.
Imperative — from a file¶
The filename becomes the key (nginx.conf), the file contents become the value. Use this for config files you want to mount into a container.
Custom key name:
Now the key is config instead of the filename.
Imperative — from a .env file¶
Parses the file line by line (KEY=VALUE per line), each line becomes a separate key. Different from --from-file which makes the whole file one value.
Declarative — YAML¶
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: default
data:
APP_ENV: "production"
LOG_LEVEL: "info"
DB_HOST: "postgres.svc.cluster.local"
nginx.conf: | # multi-line value (the | means literal block)
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
| in YAML = literal block scalar. Preserves newlines. Use this for multi-line config file content.
Generate YAML without creating¶
Using ConfigMaps — Three Ways¶
1. Env var — single key¶
env:
- name: APP_ENV # env var name inside the container
valueFrom:
configMapKeyRef:
name: app-config # ConfigMap name
key: APP_ENV # key within the ConfigMap
2. envFrom — inject all keys¶
Every key in app-config becomes an env var. APP_ENV, LOG_LEVEL, DB_HOST all injected automatically.
3. Volume mount — keys become files¶
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: config-vol
mountPath: /etc/nginx/conf.d # directory inside container
readOnly: true
volumes:
- name: config-vol
configMap:
name: nginx-config # ConfigMap name
Result: each key in nginx-config becomes a file inside /etc/nginx/conf.d/. If the ConfigMap has key nginx.conf, the file /etc/nginx/conf.d/nginx.conf is created with its value as contents.
Mount only specific keys:
volumes:
- name: config-vol
configMap:
name: app-config
items:
- key: nginx.conf # only this key
path: default.conf # file it becomes (can rename here)
Updating ConfigMaps¶
kubectl edit configmap app-config # opens editor, save to apply
kubectl apply -f configmap.yaml # apply updated YAML
What happens after update:
| Usage method | Picks up update automatically? |
|---|---|
Env var (configMapKeyRef / envFrom) |
No — env vars are set at pod start. Must restart pod. |
| Volume mount | Yes — eventually (~1-2 minutes sync delay) |
For env vars: delete and recreate the pod, or use kubectl rollout restart deployment/<name> if it's a Deployment.
Immutable ConfigMaps¶
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
immutable: true # cannot be changed after creation
data:
APP_ENV: "production"
Immutable ConfigMaps improve cluster performance at scale (no need to watch for changes). Trade-off: any change requires deleting and recreating. Use for config that truly never changes.
All Commands¶
# Create
kubectl create configmap my-cm --from-literal=key=value
kubectl create configmap my-cm --from-file=config.txt
kubectl create configmap my-cm --from-file=key=config.txt
kubectl create configmap my-cm --from-env-file=.env
kubectl apply -f configmap.yaml
# Read
kubectl get configmap
kubectl get configmap my-cm
kubectl get configmap my-cm -o yaml # see full content including values
kubectl describe configmap my-cm # formatted view, values visible
# Update
kubectl edit configmap my-cm
kubectl apply -f configmap.yaml # updated YAML
# Delete
kubectl delete configmap my-cm
# Inspect what a pod sees
kubectl exec my-pod -- env | grep MY_KEY # check env vars
kubectl exec my-pod -- cat /etc/config/key # check mounted file
# kubectl explain
kubectl explain configmap
kubectl explain pod.spec.volumes.configMap
kubectl explain pod.spec.containers.envFrom
Full Example — ConfigMap to Pod¶
# 1. Create the ConfigMap
kubectl create configmap app-config \
--from-literal=APP_ENV=production \
--from-literal=LOG_LEVEL=info
# 2. Verify
kubectl get configmap app-config -o yaml
# 3. Create pod that uses it
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
restartPolicy: Never
containers:
- name: app
image: busybox
command: ["sh", "-c", "echo APP_ENV is $APP_ENV && sleep 3600"]
env:
- name: APP_ENV
valueFrom:
configMapKeyRef:
name: app-config
key: APP_ENV
EOF
# 4. Verify the env var is injected
kubectl exec app-pod -- printenv APP_ENV
Common Exam Patterns¶
"Create a ConfigMap and use it as an env var":
kubectl create configmap my-cm --from-literal=MY_KEY=myvalue
# then add env.valueFrom.configMapKeyRef to pod spec
"Mount a ConfigMap as a volume":
# generate pod YAML, add volumeMounts + volumes.configMap sections
kubectl run my-pod --image=nginx --restart=Never --dry-run=client -o yaml > pod.yaml
"Update a ConfigMap and apply the change to running pods":
kubectl edit configmap my-cm # update the value
kubectl delete pod my-pod # if env var — must recreate
kubectl apply -f pod.yaml # or just wait ~2min if volume mount
Debugging "env var is empty in container":
kubectl describe pod my-pod # check if configmap is referenced correctly
kubectl get configmap my-cm -o yaml # verify the key exists with the right name
kubectl exec my-pod -- printenv # list all env vars — see if it's there at all
Most common cause: typo in the name or key field of configMapKeyRef. The pod starts fine (missing ConfigMap key doesn't crash the pod by default) but the env var is empty.
Make it required (crash if ConfigMap is missing):
configMapKeyRef:
name: my-cm
key: MY_KEY
optional: false # default is false — pod won't start if key is missing
optional: true = inject if exists, skip if not. optional: false (default) = fail pod startup if ConfigMap or key doesn't exist.