Configuration should be separated from code — a core 12-factor principle. In Kubernetes, ConfigMaps hold non-sensitive configuration data (settings, feature flags, config files) and inject it into Pods as environment variables or mounted files.
1. Creating ConfigMaps
From Literal Values
# Imperative: kubectl create configmap app-config \ --from-literal=DB_HOST=postgres.default.svc \ --from-literal=DB_PORT=5432 \ --from-literal=LOG_LEVEL=info
From Files
# From a single file (key = filename, value = file content): kubectl create configmap nginx-conf --from-file=nginx.conf # From a file with a custom key: kubectl create configmap nginx-conf --from-file=custom-key=nginx.conf # From a directory (each file becomes a key): kubectl create configmap app-configs --from-file=./config/
From Environment File
# .env file: # DB_HOST=postgres # DB_PORT=5432 kubectl create configmap app-config --from-env-file=.env
Declarative YAML
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: default
data: # ← string key-value pairs
DB_HOST: postgres.default.svc
DB_PORT: "5432" # ← all values are strings
LOG_LEVEL: info
app.properties: | # ← multi-line config file as a value
server.port=8080
server.timeout=30s
feature.dark-mode=true
binaryData: # ← for non-UTF8 data (base64 encoded)
logo.png: iVBORw0KGgo...
Key Rules
| Rule | Detail |
|---|---|
| Values are always strings | Even numbers: "5432" not 5432 |
| Max size | 1 MiB total (etcd limit) |
| Namespaced | ConfigMap must be in same namespace as Pod |
| Not encrypted | Stored as plain text in etcd — use Secrets for sensitive data |
kubectl create configmap name --from-literal=key=value --dry-run=client -o yaml > cm.yaml. Edit if needed, then apply.
2. Consuming ConfigMaps in Pods
Method 1: Individual Environment Variables
spec:
containers:
- name: app
image: myapp:latest
env:
- name: DATABASE_HOST # ← env var name in container
valueFrom:
configMapKeyRef:
name: app-config # ← ConfigMap name
key: DB_HOST # ← key within ConfigMap
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: app-config
key: DB_PORT
Method 2: All Keys as Environment Variables
spec:
containers:
- name: app
image: myapp:latest
envFrom:
- configMapRef:
name: app-config # All keys become env vars
prefix: APP_ # Optional: prefix each var
# Result: APP_DB_HOST, APP_DB_PORT, APP_LOG_LEVEL
Method 3: Volume Mount (Config Files)
spec:
containers:
- name: nginx
image: nginx:1.25
volumeMounts:
- name: config-vol
mountPath: /etc/nginx/conf.d # Directory where files appear
readOnly: true
volumes:
- name: config-vol
configMap:
name: nginx-conf
# Each key becomes a file in the mount directory
# Key: "default.conf" → File: /etc/nginx/conf.d/default.conf
Method 4: Mount Specific Keys
volumes:
- name: config-vol
configMap:
name: app-config
items: # Only mount these keys
- key: app.properties
path: application.properties # custom filename
# Result: /mountPath/application.properties
Comparison
| Method | Hot Reload? | Best For |
|---|---|---|
Env vars (valueFrom) | ❌ No (set at Pod start) | Simple key-value settings |
Env vars (envFrom) | ❌ No | Bulk injection of many keys |
| Volume mount | ✅ Yes (~60s delay) | Config files that apps read from disk |
Volume mount + subPath | ❌ No | Mount single file without hiding directory |
3. subPath — Mount a Single File
A normal volume mount replaces the entire directory. If you mount to /etc/nginx/, all existing files in that directory disappear. Use subPath to mount a single file without hiding the directory:
spec:
containers:
- name: nginx
volumeMounts:
- name: config-vol
mountPath: /etc/nginx/nginx.conf # specific file path
subPath: nginx.conf # key from ConfigMap
volumes:
- name: config-vol
configMap:
name: nginx-conf
4. Immutable ConfigMaps
apiVersion: v1 kind: ConfigMap metadata: name: app-config-v2 immutable: true # ← cannot be modified after creation data: DB_HOST: postgres.default.svc LOG_LEVEL: debug
Why Make a ConfigMap Immutable?
| Benefit | Explanation |
|---|---|
| Performance | kubelet stops watching for changes → reduces API server load significantly at scale |
| Safety | Prevents accidental edits that could break running Pods |
| GitOps-friendly | Version in the name (app-config-v2), point Deployment to new name, rollback = revert name |
5. ConfigMap Update Patterns
Pattern 1: Volume Mount (Auto-Sync)
# Update ConfigMap: kubectl edit configmap app-config # Wait ~60s → file in container updates automatically # App must watch for file changes (inotify, SIGHUP, periodic re-read)
Pattern 2: Rollout Restart
# Update ConfigMap, then force Pod restart: kubectl edit configmap app-config kubectl rollout restart deployment/web # New Pods pick up the new config at startup
Pattern 3: Config Hash Annotation (GitOps)
# In the Deployment template:
spec:
template:
metadata:
annotations:
configHash: "sha256:a1b2c3..." # CI/CD computes this
# When ConfigMap changes → hash changes → template changes → rollout triggers
# Fully declarative, no manual restart needed
Pattern 4: Immutable + Name Versioning
# Create new ConfigMap with new name: kubectl create configmap app-config-v3 --from-file=... # Update Deployment to reference new name: # volumes.configMap.name: app-config-v3 # Triggers rolling update. Rollback = point back to v2.
immutable: true, it gives you full version control over configuration.
Summary
| Concept | Key Point |
|---|---|
| ConfigMap | Non-sensitive config as key-value pairs or files |
| Creation | --from-literal, --from-file, --from-env-file, or YAML |
| Env vars | valueFrom.configMapKeyRef or envFrom — fixed at start |
| Volume mount | Keys → files — auto-updates in ~60s |
| subPath | Mount single file without hiding directory — disables auto-update |
| Immutable | Set immutable: true — reduces API server load, prevents edits |
| Size limit | 1 MiB total per ConfigMap |
| Best practice | Immutable + name versioning + Deployment reference update |
📝 Quiz: ConfigMaps
Q1: You mount a ConfigMap as a volume at /etc/app/. The directory already has files. What happens to them?
subPath if you need to preserve existing files.Q2: You update a ConfigMap. Pods use it via env.valueFrom.configMapKeyRef. When do they see the new value?
kubectl rollout restart deployment/web) for it to pick up the new value.Q3: You mount a ConfigMap as a volume with subPath. You update the ConfigMap. Does the file in the container update?
subPath mounts are not auto-updated. This is a known limitation. The file remains at its original content until the Pod is restarted. For auto-updates, mount the entire ConfigMap as a directory (without subPath).Q4: Why would you set immutable: true on a ConfigMap in a large cluster?
Q5: A ConfigMap has keys DB_HOST, DB_PORT, and app.conf. You use envFrom to inject all keys. What environment variables does the container get?
DB_HOST and DB_PORT become env vars. app.conf is skipped because it's not a valid environment variable name (contains a dot). Keys that aren't valid env var names are silently ignored by envFrom. No error is raised.Q6: How do you trigger a Deployment rollout when a ConfigMap changes, without using kubectl rollout restart?
annotations:
configHash: "sha256:abc123"When CI/CD updates the ConfigMap and recomputes the hash, the annotation change modifies the Pod template, triggering a rolling update automatically.