Skip to main content
RunBook Academy

KubernetesXX · ConfigurationConfiguration

Update behaviour — env vars are frozen, files are eventually consistent

Advanced⏱ ~17 minkubectlkubeadm

What you'll learn

  • Explain the asymmetry between env-var and file consumption
  • Design patterns that ensure ConfigMap changes take effect
  • Use the hash annotation pattern for automatic rollouts
  • Avoid the common production failure: a config change that does nothing

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

The ConfigMap update semantics depend entirely on the consumption pattern. Env vars are frozen at container start; the running process sees the value from /proc/<pid>/ environ until the Pod restarts. Files are updated by the kubelet within syncPeriod; the running process must detect the change and reload. This asymmetry is the source of the most common production ConfigMap mistake: a change that does nothing.

The asymmetry

flowchart TB
    A[ConfigMap changed] --> B{Consumption}
    B -->|envFrom / valueFrom| C["Env vars FROZEN<br/>at container start"]
    B -->|volumeMount| D["Files UPDATED<br/>within syncPeriod"]
    C --> E["Running process sees<br/>old values<br/>until restart"]
    D --> F["Running process sees<br/>new values<br/>after reload"]

The Kubelet does not restart the Pod on ConfigMap change. The Deployment controller does not roll the Pod on ConfigMap change (ConfigMaps are not in the Pod template’s hash). The result:

  • Env vars: the change has no effect on the running Pod. The Pod must be restarted (typically via a rollout).
  • Files: the change takes effect within ~60 seconds, but only if the application reloads.

Patterns that ensure changes take effect

Pattern 1: trigger a manual rollout

kubectl create configmap web-config -n prod \
  --from-literal=log_level=debug \
  -o yaml --dry-run=client | kubectl apply -f -

kubectl rollout restart deployment/web -n prod
kubectl rollout status deployment/web -n prod

The operator makes the ConfigMap change, then explicitly restarts the Deployment. The Pods are recreated with the new env vars.

Pattern 2: hash annotation

spec:
  template:
    metadata:
      annotations:
        config.checksum/web: <sha256 of the ConfigMap>

A controller (Reloader, Argo CD, Flux) computes the checksum and updates the annotation when the ConfigMap changes. The Deployment’s template hash changes; the rollout triggers automatically.

flowchart LR
    A[ConfigMap updated] --> B[Reloader controller]
    B --> C[Compute new sha256]
    C --> D{Annotation<br/>changed?}
    D -->|yes| E["Update Deployment<br/>template annotation"]
    E --> F["Deployment controller<br/>sees template hash change"]
    F --> G[Rollout triggered]
    G --> H["Pods recreated with<br/>new ConfigMap"]

Pattern 3: file mount with reload

volumeMounts:
- name: config
  mountPath: /etc/web
volumes:
- name: config
  configMap:
    name: web-config

The kubelet syncs the mount within syncPeriod (default ~60s). A sidecar or the application itself detects the file change and reloads:

# Sidecar that watches the file and SIGHUPs the process
while true; do
  inotifywait -e modify /etc/web/app.conf
  kill -HUP $(pidof web-app)
done

No rollout; no restart; the change takes effect within ~60 seconds + the application’s reload time.

When to use which pattern

flowchart TB
    A[ConfigMap change] --> B{Application<br/>reads env vars<br/>or files at startup?}
    B -->|env vars| C["Use Pattern 1 or 2<br/>Rollout required"]
    B -->|files with reload| D["Use Pattern 3<br/>No rollout needed"]
    C --> E["Hash annotation or<br/>manual rollout"]
    D --> F["Sidecar or<br/>app-level reload"]
PatternUse caseTrade-off
Manual rolloutEnv-var consumers; infrequent config changesOperator must remember to roll
Hash annotationAuto-roll on any config changeAdds a controller; brief downtime
File mount + reloadHot-reload config; zero-downtime changesApp must support reload

Failure modes

Failure 1: ConfigMap changed, env var consumer

flowchart LR
    A["Operator: change<br/>log_level=debug"] --> B[ConfigMap updated]
    B --> C["Operator expects<br/>Pods to log at debug"]
    C --> D["Pods continue<br/>at log_level=info"]
    D --> E["Operator confused<br/>\"config not applied\""]
    E --> F[Ticket opened]
    F --> G["Engineer: \"did you<br/>roll the Deployment?\""]
    G --> H[Operator rolls]
    H --> I[Change takes effect]

This is the most common ConfigMap ticket. The fix is in the runbook: every ConfigMap change is paired with a rollout command. Or the hash annotation pattern eliminates the manual step.

Failure 2: File mount without reload

The kubelet updates the file; the application does not detect it. The application continues with the old config. This is harder to detect because there is no obvious “restart needed” symptom.

The fix: instrument the application to log when it loads its config. A “loaded at” timestamp in the logs surfaces the staleness.

logger.info("config loaded at %s from %s",
            time.ctime(), os.stat('/etc/web/app.conf').st_mtime)

Failure 3: File mount with crash on reload

An application that crashes when reloading a malformed config. A typo in the ConfigMap takes every Pod down. The fix: validate the config before applying it (a CI step that kubectl apply --dry-run=server and tests the application’s startup with the new config).

Sync period tuning

kubelet --config=/etc/kubernetes/kubelet.yaml \
  --config-sync-period=10s

The kubelet’s syncPeriod determines how often it checks for ConfigMap/Secret changes. The default is 60s; tighter periods (10s, 5s) reduce the staleness window but cost more API server traffic.

For workloads that need rapid config updates (a rate limit that must change within seconds of an incident), tighten the syncPeriod. For workloads that change config rarely (feature flags toggled weekly), the default is fine.

Quiz

Knowledge check · 4 questions

  1. Q1. When a ConfigMap is updated and consumed via envFrom, what happens to a running Pod?

  2. Q2. Mounted ConfigMap files update automatically without any application-side reload - the kubelet handles the reload.

  3. Q3. Your team deploys a hash annotation controller (Reloader) that updates a Deployment annotation when a ConfigMap changes. The Deployment's template hash changes; the rollout triggers. Diagnose and verify.

    ConfigMap web-config updated. Reloader updates Deployment web's annotation config-checksum/web to the new sha. The Deployment rolls.

  4. Q4. Why does a manual rollout after a ConfigMap change require operator discipline, and what is the automated pattern?

Passing score: 75%. Answers are checked in this browser.

Production discipline

  • Document the consumption pattern. A ConfigMap manifest without a comment about how it is consumed is half a manifest.
  • Pair env-var changes with a rollout. A runbook entry that says “change the ConfigMap then kubectl rollout restart” is the minimum.
  • Use the hash annotation pattern for high-volume config changes. A controller that updates the annotation eliminates the manual step.
  • Verify the application’s reload path. A file mount without reload is a config change that does nothing.
  • Validate before applying. A ConfigMap that crashes every Pod on reload is an incident waiting to happen.

The ConfigMap update semantics are deterministic. The discipline is in the consumption pattern and the rollout trigger. Operators who understand the asymmetry have ConfigMaps that work.