ConfigMaps
Externalise non-sensitive configuration from container images using ConfigMaps.
ConfigMaps and Twelve-Factor Portability
The 12-Factor App methodology states that config should be strictly separated from code. In Kubernetes, this separation is achieved using ConfigMaps. ConfigMaps decouple environment-specific parameters from the immutable container image, allowing the same container image to run across dev, staging, and production environments.
What ConfigMaps Store
- Environment variable values (
LOG_LEVEL=debug) - Full configuration files (
nginx.conf,application.properties) - Command-line arguments
ConfigMaps are for non-sensitive data. Never put passwords or tokens in a ConfigMap β use a Secret instead.
Visualizing ConfigMap Projection
+-------------------------+
| ConfigMap in etcd |
| (Key-Value Data Store) |
+-------------------------+
|
| (API Server)
v
+---------------+
| Kubelet |
+---------------+
|
+---------------------+---------------------+
| (Static Injection) | (Dynamic Sync Loop)
v v
+-----------------------------+ +-----------------------------+
| Environment Variables | | Volume Mount |
| | | |
| - Injected at startup | | - Kubelet writes to tmpfs |
| - Read-only thereafter | | - Atomic symlink flip |
| - Requires Pod restart | | - Live update (~1 min sync) |
+-----------------------------+ +-----------------------------+Consumption Mechanisms & Internal Details
When you reference a ConfigMap in a Pod spec, the injection behaves differently depending on the projection mechanism:
1. Environment Variables (`valueFrom.configMapKeyRef` / `envFrom`)
- Mechanism: The container runtime (e.g. containerd) reads the ConfigMap values from the API server during container creation and sets them inside the container's process environment block (
env). - Low-Level Detail: The process reads env vars once during initialization.
- Update Behavior: Static. If the ConfigMap is modified, the environment variables inside the container do not change. The Pod must be restarted (e.g., via a rolling deployment trigger like
kubectl rollout restart) to pick up updates.
2. Volume Mounts
- Mechanism: The
kubeletcreates a local directory on the host under/var/lib/kubelet/pods//volumes/kubernetes.io~configmap/backed by tmpfs (in-memory RAM filesystem). It requests the ConfigMap from the API server and writes the keys as files. - Low-Level Detail: To prevent race conditions where a process reads a half-written config file during an update, kubelet uses atomic symlink swapping:
1. It writes the new files to a unique timestamped directory (..data_timestamp).
2. It updates a symbolic link (..data) to point to the new directory.
3. The individual keys are symlinked to files inside ..data.
- Update Behavior: Dynamic. Kubelet's periodic sync loop (defaulting to every 60 seconds, controlled by
syncFrequencyandconfigMapAndSecretChangeDetectionStrategy) will detect the update, fetch the new payload, and update the symlinks. - Exception: If you mount a ConfigMap using
subPath, the file is bind-mounted directly. The kernel does not update static bind-mounts when the parent directory's symlinks change. Therefore, subPath mounted ConfigMaps do not receive hot updates.
Three Ways to Consume a ConfigMap
1. Single env var
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL2. All keys as env vars (envFrom)
envFrom:
- configMapRef:
name: app-config3. Volume mount (for config files)
volumes:
- name: config-vol
configMap:
name: nginx-conf
containers:
- volumeMounts:
- name: config-vol
mountPath: /etc/nginxUpdate Behaviour
| Consumption method | Hot-reload when ConfigMap changes? |
|---|---|
| env var / envFrom | No β pod must be restarted |
| Volume mount | Yes β kubelet syncs within ~1 minute |
This difference is critical for production: if you need live config reloads, mount as a volume and design your app to watch the file.