How ConfigMap and Secret Updates Reach Running Pods

Tested on Rocky Linux 10.2 (Red Quartz) workstation
Package kubectl 1.36.3
Applies to Any host with kubectl configured; any Kubernetes cluster
Cert prep CKA · CKAD
Lab environment Multi-node kubeadm cluster with containerd — install Kubernetes with kubeadm
Privilege Normal user (no sudo required on the workstation)
Scope When ConfigMap and Secret updates reach running Pods; environment variables versus volume projection versus subPath; application reload versus Pod restart; rollout restart; checksum annotations; and versioned object names. Does not cover object creation syntax, reloader controllers, or zero-downtime guarantees.
Related guides Deployment rolling updates

You changed a ConfigMap or Secret and want to know when the running application will actually see the new value. The answer depends on how the Pod consumes that object—not on whether the API object updated successfully. This walkthrough runs one controlled experiment in config-update-lab so you can compare environment variables, a normal volume mount, and a subPath file side by side.


Answer First: What Updates Automatically?

Consumption method Files or values inside existing container Pod recreation required
env with configMapKeyRef or secretKeyRef Does not change Yes
envFrom Does not change Yes
Normal ConfigMap volume Eventually projected into the mount No for the file itself
Normal Secret volume Eventually projected into the mount No for the file itself
ConfigMap or Secret mounted with subPath Does not change Yes
Immutable ConfigMap or Secret Source data cannot be updated New object/reference required

Three points follow from this table:

  • A projected file update does not guarantee the application reloads it. A process that reads configuration only at startup keeps old in-memory values until it reloads or restarts.
  • “No Pod restart” is possible only when both the mount updates and the application rereads the file.
  • Updating the ConfigMap in the API is never sufficient proof that the application changed behaviour—verify the mount or environment and the application output.

Object creation syntax lives in Kubernetes ConfigMaps and Kubernetes Secrets. This article focuses on what happens after you change the data.


Build a Controlled Update Lab

The lab uses one ConfigMap and one Deployment with three containers. Each container prints APP_COLOR every five seconds so you can watch behaviour without guessing.

Save app-config.yaml:

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: config-update-lab
data:
  APP_COLOR: blue

Create the namespace:

bash
kubectl create namespace config-update-lab

Sample output:

output
namespace/config-update-lab created

Apply the ConfigMap manifest:

bash
kubectl apply -f app-config.yaml

Sample output:

output
configmap/app-config created

Save update-lab.yaml:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: config-update-lab
  namespace: config-update-lab
spec:
  replicas: 1
  selector:
    matchLabels:
      app: config-update-lab
  template:
    metadata:
      labels:
        app: config-update-lab
    spec:
      containers:
      - name: env-test
        image: busybox:1.36
        command: ["sh", "-c", "while true; do echo env APP_COLOR=$APP_COLOR; sleep 5; done"]
        env:
        - name: APP_COLOR
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: APP_COLOR
      - name: vol-test
        image: busybox:1.36
        command: ["sh", "-c", "while true; do echo vol APP_COLOR=$(cat /etc/config/APP_COLOR); sleep 5; done"]
        volumeMounts:
        - name: cfg
          mountPath: /etc/config
      - name: subpath-test
        image: busybox:1.36
        command: ["sh", "-c", "while true; do echo subpath APP_COLOR=$(cat /etc/app-color); sleep 5; done"]
        volumeMounts:
        - name: cfg
          mountPath: /etc/app-color
          subPath: APP_COLOR
      volumes:
      - name: cfg
        configMap:
          name: app-config

Apply the Deployment and wait for the Pod:

bash
kubectl apply -f update-lab.yaml

Sample output:

output
deployment.apps/config-update-lab created

Wait for the Pod to become ready:

bash
kubectl rollout status deployment/config-update-lab -n config-update-lab --timeout=90s

Store the exact Pod and UID:

bash
POD=$(kubectl get pods -n config-update-lab -l app=config-update-lab -o jsonpath='{.items[0].metadata.name}')

OLD_UID=$(kubectl get pod "$POD" -n config-update-lab -o jsonpath='{.metadata.uid}')

printf 'pod=%s uid=%s\n' "$POD" "$OLD_UID"

Sample output:

output
pod=config-update-lab-7f9464dcd-cffjf uid=085eea95-35db-47b0-bfa4-4ddbf0fc3f0d

Store the ConfigMap resource version before you change anything:

bash
OLD_RV=$(kubectl get configmap app-config -n config-update-lab -o jsonpath='{.metadata.resourceVersion}')

printf '%s\n' "$OLD_RV"

Sample output:

output
460690

All three containers should print blue in their logs:

bash
kubectl logs "$POD" -n config-update-lab -c env-test --tail=1

Sample output:

output
env APP_COLOR=blue
bash
kubectl logs "$POD" -n config-update-lab -c vol-test --tail=1

Sample output:

output
vol APP_COLOR=blue
bash
kubectl logs "$POD" -n config-update-lab -c subpath-test --tail=1

Sample output:

output
subpath APP_COLOR=blue

Compare Update Behaviour

Update the Source ConfigMap

Change APP_COLOR to green in app-config.yaml:

yaml
data:
  APP_COLOR: green

Apply the manifest:

bash
kubectl apply -f app-config.yaml

Sample output:

output
configmap/app-config configured

Confirm the object's resourceVersion changed:

bash
NEW_RV=$(kubectl get configmap app-config -n config-update-lab -o jsonpath='{.metadata.resourceVersion}')

printf 'old_rv=%s new_rv=%s\n' "$OLD_RV" "$NEW_RV"

Sample output:

output
old_rv=460690 new_rv=460726

resourceVersion represents the stored version of the object and should not be treated as an application revision number. The ConfigMap now holds green. The question is whether each container sees it.

Environment Variables Stay Unchanged

Container environment variables are assembled when the container starts. The kubelet copies values from referenced ConfigMaps and Secrets into the process environment at that moment. Updating the source object later does not rewrite the environment of a running process.

envFrom, configMapKeyRef, and secretKeyRef all follow this startup-time behaviour. A new Pod or restarted container is required to receive new environment values.

Five seconds after the ConfigMap update, the env container still reports blue:

bash
kubectl exec "$POD" -n config-update-lab -c env-test -- printenv APP_COLOR

Sample output:

output
blue

The ConfigMap resourceVersion changed, but the existing container process still holds the value from Pod creation. The Pod UID also stays the same—no recreation occurred:

bash
kubectl get pod "$POD" -n config-update-lab -o jsonpath='{.metadata.uid}{"\n"}'

Sample output:

output
085eea95-35db-47b0-bfa4-4ddbf0fc3f0d

Normal Volume Files Eventually Update

When a ConfigMap or Secret is mounted as a normal volume, the kubelet eventually refreshes projected file content. The update is not immediate. Delay depends on kubelet synchronization and its configured configMapAndSecretChangeDetectionStrategy (watch, TTL-based cache, or direct API access). Do not assume a fixed interval such as exactly one or two minutes.

The Pod UID and container process can remain unchanged while the file on disk changes. Wait for the projected file instead of assuming an immediate update:

bash
VALUE=""

for attempt in {1..90}; do
  VALUE=$(kubectl exec "$POD" -n config-update-lab -c vol-test -- cat /etc/config/APP_COLOR)
  [[ "$VALUE" == "green" ]] && break
  sleep 2
done

if [[ "$VALUE" != "green" ]]; then
  echo "Timed out waiting for the ConfigMap volume update" >&2
  exit 1
fi

printf '%s\n' "$VALUE"

Sample output:

output
green

This proves the update while allowing up to three minutes for different kubelet configurations.

The env container still holds the startup value:

bash
kubectl exec "$POD" -n config-update-lab -c env-test -- printenv APP_COLOR

Sample output:

output
blue

The volume container log eventually prints vol APP_COLOR=green on its next read cycle. Secret volumes follow the same eventual projection model. Secret-derived environment variables remain unchanged in existing processes, while normal Secret volume files are eventually refreshed. Secret files mounted using subPath do not receive automated updates. These behaviours are documented for Secret environment variables, normal Secret volumes, and subPath mounts.

subPath Files Stay Unchanged

A subPath mount binds one file at container start. It does not follow later ConfigMap or Secret projection changes. In the lab, subpath-test still reads blue after the ConfigMap holds green:

bash
kubectl exec "$POD" -n config-update-lab -c subpath-test -- cat /etc/app-color

Sample output:

output
blue

Recreating the Pod is required for a subPath mount to use new content. General subPath syntax and directory-preservation patterns are covered in subPath volume examples—this article focuses on the update limitation.


File Update vs Application Reload

Kubernetes can change a mounted file, but the application decides whether that change matters. Three common behaviours:

Application behaviour Result after projected file changes
Reads file for every request Uses new content automatically
Watches the file or supports reload Uses new content after its reload mechanism
Reads configuration only at startup Continues using old in-memory configuration

This distinction is the central message of the article. A successful kubectl apply on the ConfigMap plus an updated file on disk still leaves a startup-only application serving old behaviour until you reload or restart it.


Apply Configuration Changes

Reload the Application

When the mount updates and the application supports it, you can reload without a new Pod:

  • Built-in file watcher in the application
  • HTTP or admin reload endpoint
  • Signal such as SIGHUP where the application handles it
  • Sidecar that detects file changes and triggers the supported reload action

Kubernetes only updates mounted data. It does not know how an arbitrary application reloads configuration. Do not kill PID 1 as a general reload method. That terminates the container rather than asking the application to reload configuration. The kubelet may restart it according to the Pod restart policy, but this is not a controlled workload rollout and may cause an interruption.

Restart the Workload

When environment variables or subPath mounts must pick up new values, restart the workload so new containers start with current data. kubectl rollout restart adds a Pod-template annotation that triggers a normal rolling replacement:

bash
kubectl rollout restart deployment/config-update-lab -n config-update-lab

Sample output:

output
deployment.apps/config-update-lab restarted

Track the rolling replacement:

bash
kubectl rollout status deployment/config-update-lab -n config-update-lab --timeout=90s

Sample output:

output
deployment "config-update-lab" successfully rolled out

Resolve the new Pod rather than relying only on selector-based logs:

bash
NEW_POD=$(kubectl get pods \
  -n config-update-lab \
  -l app=config-update-lab \
  --sort-by=.metadata.creationTimestamp \
  -o custom-columns=NAME:.metadata.name \
  --no-headers | tail \
  -1)

NEW_UID=$(kubectl get pod "$NEW_POD" -n config-update-lab -o jsonpath='{.metadata.uid}')

printf 'old_uid=%s new_uid=%s\n' "$OLD_UID" "$NEW_UID"

Sample output:

output
old_uid=085eea95-35db-47b0-bfa4-4ddbf0fc3f0d new_uid=a1b2c3d4-e5f6-7890-abcd-ef1234567890

After the rollout, all three lab containers print green—including env-test and subpath-test, which could not update in place:

bash
kubectl logs "$NEW_POD" -n config-update-lab -c env-test --tail=1

Sample output:

output
env APP_COLOR=green

The subPath container also picks up green only after recreation:

bash
kubectl logs "$NEW_POD" -n config-update-lab -c subpath-test --tail=1

Sample output:

output
subpath APP_COLOR=green

kubectl rollout restart works for Deployments, StatefulSets, and DaemonSets.


Automate Configuration Rollouts

Checksum Annotations

Changing only the data inside a referenced ConfigMap or Secret does not modify the workload's Pod template. Controllers create replacement Pods when spec.template changes, which is why deployment tools commonly place a configuration checksum in a Pod-template annotation.

Helm charts often use a template like this:

yaml
metadata:
  annotations:
    checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}

When the ConfigMap content changes, the rendered checksum changes, the Pod template changes, and the workload controller performs a normal rollout. This is a packaging convention—not a built-in Kubernetes feature. Plain YAML or CI pipelines must compute and inject the checksum with external tooling. See Kubernetes Helm charts for how release templates manage this pattern.

Versioned ConfigMap and Secret Names

Explicit versioning avoids patching data in place and works well with immutable objects:

  • app-config-v1app-config-v2
  • Update the Deployment to reference the new name

Benefits:

  • Configuration version is visible in the object name
  • Works with immutable: true
  • Produces a Pod-template change when the reference updates
  • Rollback is a template revert to the earlier name

Pair this with a normal rollout when env vars or subPath mounts must refresh.


Verify the Effective Configuration

Check three layers—not just the API object:

  1. Source ConfigMap or Secret contains the intended value (kubectl get … -o yaml)
  2. Mounted file or environment variable inside the container matches (kubectl exec, application logs)
  3. Application behaviour confirms reload or restart (HTTP response, metrics, functional test)

Treating the ConfigMap alone as proof of change is a common mistake. The lab made this visible: after the API showed green, only the volume mount caught up without a Pod restart—and even that required waiting for kubelet projection.


Common Mistakes

Symptom Likely cause Fix
ConfigMap shows new value but printenv is old Value consumed through env or envFrom kubectl rollout restart the workload
File on disk is new but app behaviour unchanged Application reads config only at startup Reload through app mechanism or restart containers
subPath file never updates subPath does not receive projections Recreate Pod or avoid subPath when live refresh is required
Patched immutable ConfigMap fails immutable: true blocks edits Create new object name and update the reference
Volume updated slowly Kubelet sync delay Wait and re-check; do not assume instant propagation

What's Next


References


Summary

ConfigMap and Secret updates do not reach every running container the same way. Environment variables from configMapKeyRef, secretKeyRef, and envFrom are fixed at container start—patching the source object leaves existing processes unchanged until new Pods are created. Normal ConfigMap and Secret volumes are eventually refreshed by the kubelet, but the delay is not guaranteed to be immediate, and subPath mounts never receive live updates.

Even when the mounted file changes, an application that reads configuration only at startup keeps serving old behaviour until it reloads or the container restarts. Use application-supported reload mechanisms when the mount path can update in place; use kubectl rollout restart, checksum annotations, or versioned object names when env vars or subPath mounts must change. Always verify inside the container and through application behaviour—not only at the API object.


Frequently Asked Questions

1. Do ConfigMap environment variables update in a running Pod?

No. Environment variables from configMapKeyRef, secretKeyRef, or envFrom are set when the container starts. Updating the ConfigMap or Secret does not change values in an existing process. Restart the Pod or roll out a new ReplicaSet to pick up new environment values.

2. How long does a ConfigMap volume take to update?

The kubelet eventually refreshes projected ConfigMap and Secret files, but the delay is not fixed. It depends on kubelet sync timing and the configured configMapAndSecretChangeDetectionStrategy. Do not assume an immediate update.

3. Does subPath receive ConfigMap updates?

No. A file mounted with subPath does not receive later ConfigMap or Secret projection changes. Recreate the Pod or change the Pod template so a new container starts with the updated mount.

4. Is updating the ConfigMap enough for my application to use new settings?

Not always. Kubernetes may update a mounted file, but an application that reads configuration only at startup keeps the old in-memory values until it reloads or the container restarts.

5. What is the simplest way to apply new env vars from a ConfigMap?

Run kubectl rollout restart on the Deployment, StatefulSet, or DaemonSet. That creates new Pods whose containers start with the current ConfigMap or Secret values.

6. Do Secrets update the same way as ConfigMaps?

Yes for consumption paths. Environment variables stay fixed at container start. Normal Secret volumes are eventually refreshed by the kubelet. subPath Secret mounts do not update until the Pod is recreated.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)