Skip to content

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

kubectl create configmap nginx-config --from-file=nginx.conf

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:

kubectl create configmap nginx-config --from-file=config=nginx.conf

Now the key is config instead of the filename.

Imperative — from a .env file

kubectl create configmap app-config --from-env-file=.env

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

kubectl create configmap app-config \
  --from-literal=APP_ENV=production \
  --dry-run=client -o yaml

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

envFrom:
- configMapRef:
    name: app-config             # all keys become env vars with the same names

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.