Skip to content

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-text data.
  • 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: app

The Update Behaviour, Precisely

How it is consumedUpdates when the ConfigMap changes?
Mounted as a directoryYes, within about a minute (the kubelet sync period)
Mounted with subPathNo. The file is a copy, taken when the container started
As an environment variableNo. 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 change

Exercises

  1. Mount a config file and watch it change.

    printf 'log_level: info\n' > app.yaml
    kubectl create configmap app --from-file=app.yaml

    Write a Pod that mounts app at /etc/app and 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 minute

    Nothing restarted. The file changed underneath the running container, which is why an application that watches its config file needs no rollout at all.

  2. Prove subPath does not update. Mount the same ConfigMap with subPath: app.yaml at /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.

  3. Show that the Deployment does not notice. Change a ConfigMap consumed as an environment variable, then run kubectl get pods — same Pods, same age. Only kubectl rollout restart picks it up.

Gotchas Worth Knowing

  • ConfigMaps are namespaced and can only be referenced from the same namespace.
  • subPath mounts 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 in CreateContainerConfigError is 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 restart is how you make it happen.