ConfigMaps
Hardcoding configuration values inside container images is a bad practice. ConfigMaps allow you to decouple configuration from your application code, making your containers portable across different environments.
What is a ConfigMap?
A ConfigMap is a Kubernetes object that stores non-sensitive configuration data as key-value pairs. Pods can consume ConfigMaps as:
- Environment variables
- Command-line arguments
- Configuration files mounted as volumes
┌──────────────────────┐ ┌────────────────────┐
│ ConfigMap │ │ Pod │
│ │ │ │
│ DB_HOST=postgres │──────►│ env: DB_HOST │
│ DB_PORT=5432 │ │ env: DB_PORT │
│ app.conf=<content> │──────►│ /etc/config/ │
│ │ │ app.conf │
└──────────────────────┘ └────────────────────┘
Creating ConfigMaps
From Literal Values
kubectl create configmap app-config \
--from-literal=DB_HOST=postgres \
--from-literal=DB_PORT=5432 \
--from-literal=LOG_LEVEL=info
From a File
Create app.properties:
database.host=postgres
database.port=5432
database.name=myapp
log.level=info
max.connections=100
kubectl create configmap app-config --from-file=app.properties
From an Env File
Create config.env:
DB_HOST=postgres
DB_PORT=5432
LOG_LEVEL=info
kubectl create configmap app-config --from-env-file=config.env
Declarative YAML
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
# Simple key-value pairs
DB_HOST: "postgres"
DB_PORT: "5432"
LOG_LEVEL: "info"
# Multi-line file content
app.conf: |
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://backend:8080;
}
}
application.yaml: |
spring:
datasource:
url: jdbc:postgresql://postgres:5432/myapp
jpa:
hibernate:
ddl-auto: update
kubectl apply -f configmap.yaml
Consuming ConfigMaps
As Environment Variables (Individual Keys)
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: my-app:1.0
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: DB_HOST
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: app-config
key: DB_PORT
As Environment Variables (All Keys at Once)
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: my-app:1.0
envFrom:
- configMapRef:
name: app-config
This injects all key-value pairs from the ConfigMap as environment variables.
As a Mounted Volume (Files)
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: nginx:1.27
volumeMounts:
- name: config-volume
mountPath: /etc/config
readOnly: true
volumes:
- name: config-volume
configMap:
name: app-config
Each key in the ConfigMap becomes a file in /etc/config/:
/etc/config/DB_HOST → contains "postgres"
/etc/config/DB_PORT → contains "5432"
/etc/config/app.conf → contains the nginx config
/etc/config/application.yaml → contains the Spring config
Mount Specific Keys Only
volumes:
- name: config-volume
configMap:
name: app-config
items:
- key: app.conf
path: nginx.conf # Rename the file
This mounts only app.conf as /etc/config/nginx.conf.
Hands-On: Complete Example
Let’s put it all together:
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
default.conf: |
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /health {
return 200 'healthy\n';
add_header Content-Type text/plain;
}
}
index.html: |
<!DOCTYPE html>
<html>
<body>
<h1>Hello from ConfigMap!</h1>
<p>This page was loaded from a ConfigMap.</p>
</body>
</html>
---
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-custom
spec:
replicas: 2
selector:
matchLabels:
app: nginx-custom
template:
metadata:
labels:
app: nginx-custom
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
volumeMounts:
- name: nginx-conf
mountPath: /etc/nginx/conf.d
- name: html-content
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-conf
configMap:
name: nginx-config
items:
- key: default.conf
path: default.conf
- name: html-content
configMap:
name: nginx-config
items:
- key: index.html
path: index.html
# Apply everything
kubectl apply -f configmap.yaml
# Port-forward and test
kubectl port-forward deployment/nginx-custom 8080:80
# Visit http://localhost:8080 → "Hello from ConfigMap!"
# Visit http://localhost:8080/health → "healthy"
Updating ConfigMaps
Volume-Mounted ConfigMaps Auto-Update
When you update a ConfigMap, volume-mounted files are updated automatically (within ~1 minute). The kubelet periodically syncs mounted ConfigMaps.
# Update the ConfigMap
kubectl edit configmap nginx-config
# Or re-apply with changes
kubectl apply -f configmap.yaml
Note: Environment variables from ConfigMaps do NOT auto-update. The Pod must be restarted to pick up changes.
Force a Pod Restart After ConfigMap Update
# Restart all Pods in a Deployment
kubectl rollout restart deployment/nginx-custom
Inspecting ConfigMaps
# List ConfigMaps
kubectl get configmaps
# or: kubectl get cm
# View contents
kubectl describe configmap app-config
# Output as YAML
kubectl get configmap app-config -o yaml
Immutable ConfigMaps
For ConfigMaps that should never change (reduces load on the API server):
apiVersion: v1
kind: ConfigMap
metadata:
name: static-config
data:
VERSION: "1.0.0"
immutable: true
Once set to immutable, the ConfigMap cannot be modified — only deleted and recreated.
Best Practices
| Practice | Reason |
|---|---|
| Use ConfigMaps for non-sensitive data only | Secrets are for passwords, tokens, keys |
| Name ConfigMaps descriptively | app-config, nginx-conf, not cm1 |
| Version ConfigMaps for rollbacks | app-config-v1, app-config-v2 |
| Use volume mounts for config files | More flexible, supports hot-reload |
Set immutable: true for static configs |
Reduces API server load |
Summary
- ConfigMaps store non-sensitive configuration as key-value pairs
- Pods consume them as environment variables or mounted files
- Volume-mounted ConfigMaps auto-update (~1 minute delay)
- Environment variable ConfigMaps require a Pod restart to update
- Use Secrets (next chapter) for sensitive data like passwords and tokens
What’s Next?
ConfigMaps are great for general configuration, but what about passwords, API keys, and certificates? In the next chapter, we’ll learn about Secrets — Kubernetes’ way of handling sensitive data.