KubernetesXX · ConfigurationConfiguration
Environment variables — ConfigMap keys as Pod env vars
What you'll learn
- Configure `envFrom` for bulk ConfigMap injection
- Configure `valueFrom.configMapKeyRef` for selective injection
- Explain why env vars do not update on ConfigMap change
- Reason about the secret-leakage risk of env-var consumption
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
ConfigMap keys can be exposed to a container as environment variables. This is the most common consumption pattern for small, simple configuration — feature flags, log levels, external service URLs. The pattern has a critical production caveat: env vars do not update when the ConfigMap changes; the Pod must be restarted. This lesson covers the two injection modes, the runtime semantics, and the patterns that work.
Two modes of injection
envFrom — all keys at once
spec:
containers:
- name: web
image: web:v1
envFrom:
- configMapRef:
name: web-config
Every key in the ConfigMap becomes an env var. With a
ConfigMap containing log_level: info, the container sees
LOG_LEVEL=info. Kubernetes replaces invalid env-var
characters (-, .) with _.
A ConfigMap like:
data:
log_level: info
database.url: postgres://db.prod/data
feature-checkout_v2: "true"
Becomes env vars:
LOG_LEVEL=info
DATABASE_URL=postgres://db.prod/data
FEATURE_CHECKOUT_V2=true
valueFrom — specific keys
spec:
containers:
- name: web
image: web:v1
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: web-config
key: log_level
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: web-config
key: database_url
This is selective. The container sees only the env vars declared, with the exact names. Useful when the application expects a specific env var name that does not match the ConfigMap key.
Required vs optional
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: web-config
key: database_url
optional: false # default
If optional: false (default), the Pod stays in
ContainerCreating until the ConfigMap and key exist.
Setting optional: true allows the Pod to start without
the key (the env var is unset).
flowchart TB
A[Pod created] --> B{ConfigMap<br/>exists?}
B -->|no, optional=true| C["Pod starts<br/>env var unset"]
B -->|no, optional=false| D["Pod stuck<br/>ContainerCreating"]
B -->|yes| E{Key exists?}
E -->|no, optional=true| C
E -->|no, optional=false| D
E -->|yes| F["Pod starts<br/>env var set"]
Runtime update semantics
flowchart LR
A[ConfigMap updated] --> B[Kubelet observes change]
B --> C{Container env vars<br/>updated?}
C -->|no| D["Env vars set at container<br/>start, frozen"]
C -->|n/a, env vars are<br/>read from /proc at start| D
Environment variables are part of the container’s initial
process state. They are set by the container runtime when
the container starts and are read from /proc/<pid>/environ
by the application. Subsequent updates to the ConfigMap
do not modify the running container’s environ.
Triggering a rollout from a ConfigMap change
A ConfigMap change does not automatically roll the Pods. The Deployment’s controller does not watch ConfigMaps by default. The patterns:
flowchart TB
A[ConfigMap changed] --> B{How is it<br/>consumed?}
B -->|env vars| C["Manual rollout<br/>kubectl rollout restart"]
B -->|files| D["App reload<br/>or manual rollout"]
B -->|sha in annotation| E["Deployment annotates<br/>template with sha"]
E --> F["Hash changes<br/>new template hash<br/>rollout triggered"]
The hash annotation pattern:
spec:
template:
metadata:
annotations:
config-checksum: <computed sha256 of the ConfigMap>
A controller (Reloader, Argo CD, Flux) computes the hash and updates the annotation; the Deployment’s template hash changes; the rollout triggers.
Security: env vars in /proc
# On any Pod that has env vars from a ConfigMap
cat /proc/1/environ | tr '\0' '\n'
# LOG_LEVEL=info
# DATABASE_URL=postgres://db.prod/data
Env vars are visible in /proc/<pid>/environ. Any process
in the Pod can read them. Any process with access to the
node (root, kubelet, sidecar with hostPath) can read them.
This is a non-secret consumption pattern. Database URLs
are typically OK; passwords are not. Secrets should be
mounted as files, not env vars, when possible — the file
content can have stricter file permissions, and the
process can mmap it without writing it to a log.
Production patterns
Pattern: feature flags
apiVersion: v1
kind: ConfigMap
metadata:
name: feature-flags
data:
checkout_v2: "true"
new_search: "false"
---
spec:
containers:
- name: web
env:
- name: FF_CHECKOUT_V2
valueFrom:
configMapKeyRef:
name: feature-flags
key: checkout_v2
- name: FF_NEW_SEARCH
valueFrom:
configMapKeyRef:
name: feature-flags
key: new_search
The application reads FF_CHECKOUT_V2 and FF_NEW_SEARCH
at startup. A change to the ConfigMap requires a rollout.
Pattern: external service URLs
apiVersion: v1
kind: ConfigMap
metadata:
name: backend-urls
data:
postgres_url: postgres://db.prod/data
redis_url: redis://cache.prod:6379
auth_url: https://auth.prod/issuer
envFrom:
- configMapRef:
name: backend-urls
All three URLs available as env vars. A change to
postgres_url (e.g., failover) requires a rollout.
Pattern: log level
data:
log_level: info
log_format: json
A LOG_LEVEL=info change requires a restart. Production
typically does not roll a Deployment for a log level
change; the operator accepts that the change takes effect
on the next rollout.
Quiz
Knowledge check · 4 questions
Q1. What is the difference between envFrom and valueFrom in a Pod's env spec?
Q2. Mounting a Secret as an environment variable is more secure than mounting it as a file because env vars are isolated to the process.
Q3. Your team changes a ConfigMap to enable a feature flag. The Pod does not pick up the change. Diagnose.
ConfigMap feature-flags updated to checkout_v2 true. The Deployment's Pod template consumes the ConfigMap via envFrom. The Pod is running; the feature flag is not enabled.
Q4. Why is mounting a Secret as an env var a security risk, and what is the safer pattern?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Use
envFromfor bulk config;valueFromfor specific keys. Both are valid; the choice is the application’s preference. - Document the rollout trigger. A ConfigMap change does not roll the Deployment automatically. The runbook must spell out how to trigger a rollout.
- Don’t put secrets in env vars. A database URL without credentials is fine; a database URL with a password is a Secret.
- Verify env-var visibility.
/proc/<pid>/environis readable by any process in the Pod. The consumption pattern is part of the security review. - Use a hash annotation for automatic rollouts. A controller that hashes the ConfigMap and updates the Deployment annotation triggers a rollout on change; the operator does not need to remember.
Env vars are the simplest way to inject ConfigMap data into a container. They are also the most error-prone — the runtime-update gap is the source of many “I changed the config but nothing happened” tickets. Operators who understand the gap have ConfigMaps that work.