ConfigMaps
Externalize application configuration using ConfigMaps. Mount configuration as environment variables or files.
ConfigMaps
In the Previous Tutorial, we learned about Services and how to expose our apps. Now let's talk about something every developer deals with — configuration.
Hardcoding configuration in container images is a terrible idea. Every time you want to change a database URL or a log level, you'd have to rebuild the entire image. That's like reprinting an entire book just to fix a typo.
ConfigMaps solve this — they store configuration data separately from your application and inject it at runtime. Change the config, not the code.
What is a ConfigMap?
So it's just a key-value store?
Pretty much! A ConfigMap is a Kubernetes object that stores non-sensitive configuration data as key-value pairs. Your application reads this configuration without knowing (or caring) where it comes from.
Use cases:
- Environment-specific settings (dev, staging, prod)
- Feature flags
- Configuration files (nginx.conf, application.properties)
- Command-line arguments
Important: ConfigMaps are for non-sensitive data only. For passwords and API keys, use Secrets (next tutorial). Please don't put your database password in a ConfigMap. Just... don't.
Create a ConfigMap
There are several ways to create a ConfigMap. Let's explore them all.
Method 1: From Literal Values
The quick and easy way — great for a few key-value pairs:
kubectl create configmap app-config
--from-literal=DATABASE_HOST=db.example.com
--from-literal=DATABASE_PORT=5432
--from-literal=LOG_LEVEL=info
Check it:
```bash
kubectl get configmap app-config -o yaml
Output:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_HOST: db.example.com
DATABASE_PORT: "5432"
LOG_LEVEL: info
Method 2: From a File
Got a config file? You can turn the whole thing into a ConfigMap:
Create app.properties:
database.host=db.example.com
database.port=5432
log.level=info
cache.enabled=true
Create ConfigMap from file:
kubectl create configmap app-config-file --from-file=app.properties
The filename becomes the key — neat, right?
kubectl get configmap app-config-file -o yaml
data:
app.properties: |
database.host=db.example.com
database.port=5432
log.level=info
cache.enabled=true
Method 3: From Directory
kubectl create configmap app-config-dir --from-file=./config-directory/
Each file in the directory becomes a key.
Method 4: YAML Definition (Recommended)
This is the way the pros do it — version-controlled, reviewable, and repeatable. Create configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_HOST: db.example.com
DATABASE_PORT: "5432"
LOG_LEVEL: info
# Multi-line config file
nginx.conf: |
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
Apply:
kubectl apply -f configmap.yaml
Use ConfigMaps in Pods
Okay, I've created a ConfigMap. How does my app actually read it?
Three ways! Pick the one that fits your use case:
1. Environment Variables (Single Keys)
Inject specific keys as environment variables — the most common approach:
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: nginx
env:
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: DATABASE_HOST
- name: DB_PORT
valueFrom:
configMapKeyRef:
name: app-config
key: DATABASE_PORT
Inside the container:
kubectl exec app-pod -- env | grep DB_
DB_HOST=db.example.com
DB_PORT=5432
2. Environment Variables (All Keys)
Feeling lazy? Just inject ALL keys at once with envFrom:
apiVersion: v1
kind: Pod
metadata:
name: app-pod-all-env
spec:
containers:
- name: app
image: nginx
envFrom:
- configMapRef:
name: app-config
All ConfigMap keys become environment variables automatically. Zero effort. Love it.
3. Volume Mounts (Files)
This one's interesting — you can mount ConfigMap data as actual files inside the container:
apiVersion: v1
kind: Pod
metadata:
name: app-pod-volume
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/conf.d
volumes:
- name: config-volume
configMap:
name: app-config
items:
- key: nginx.conf
path: default.conf
This mounts nginx.conf from the ConfigMap as /etc/nginx/conf.d/default.conf.
Without items, all keys are mounted as files:
volumes:
- name: config-volume
configMap:
name: app-config
Each key becomes a file in /etc/nginx/conf.d/.
Practical Example: Custom Nginx Config
Let's do something fun — we'll serve a custom webpage using ConfigMaps. No image rebuilding required!
Create nginx-configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
index.html: |
<!DOCTYPE html>
<html>
<head><title>Hello from ConfigMap!</title></head>
<body>
<h1>Configuration loaded from ConfigMap</h1>
<p>This content is stored in Kubernetes, not the image.</p>
</body>
</html>
Create nginx-pod.yaml:
apiVersion: v1
kind: Pod
metadata:
name: nginx-custom
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
configMap:
name: nginx-config
Apply both:
kubectl apply -f nginx-configmap.yaml
kubectl apply -f nginx-pod.yaml
Test it:
kubectl port-forward nginx-custom 8080:80
Open http://localhost:8080. You'll see "Configuration loaded from ConfigMap" instead of the default nginx page. The content lives in Kubernetes, not in the image. How cool is that?
Update ConfigMaps
Update the ConfigMap
kubectl edit configmap nginx-config
Or apply an updated YAML file.
How Pods React
Here's something important to know:
Environment variables: Don't update automatically. The Pod must be restarted to pick up changes. It's like the Pod reads the config on startup and then forgets the source exists.
Volume mounts: Update automatically! Kubernetes syncs changes within about a minute. The Pod doesn't need to restart — it just reads the new files. Magic!
Force immediate update with volume mounts:
kubectl exec nginx-custom -- cat /usr/share/nginx/html/index.html
After editing the ConfigMap, wait ~60 seconds and check again.
Restarting Pods for Env Changes
kubectl rollout restart deployment <deployment-name>
Or delete and recreate the Pod.
Immutable ConfigMaps
Once you're sure a ConfigMap won't change, mark it as immutable. Why? Two reasons:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config-immutable
data:
setting: value
immutable: true
Benefits:
- Kubernetes doesn't watch for changes (better performance)
- Prevents accidental modifications
To change an immutable ConfigMap, delete and recreate it. It's like writing in permanent marker — you better be sure.
ConfigMap Size Limits
ConfigMaps have a 1MB size limit. That's plenty for config files, but if you're trying to store War and Peace in there... don't.
For larger data:
- Use a Persistent Volume
- Store data externally (S3, databases)
- Split into multiple ConfigMaps
Best Practices
1. Use Descriptive Names
Future-you will thank present-you:
# Good — tells you exactly what it is
name: payment-service-config
name: redis-config-prod
# Bad — what even is this?
name: config1
name: my-config
2. Namespace Your ConfigMaps
ConfigMaps are namespaced. Create them in the same namespace as the Pods that use them.
3. Version Your ConfigMaps
Include version in the name when using immutable ConfigMaps:
name: app-config-v1
name: app-config-v2
4. Use Separate ConfigMaps
Don't put everything in one giant ConfigMap. It's like putting all your clothes in one drawer — it works until it doesn't:
# Separate concerns — clean and organized
name: database-config
name: logging-config
name: feature-flags
Inspect ConfigMaps
# List all ConfigMaps
kubectl get configmaps
# View details
kubectl describe configmap app-config
# View data
kubectl get configmap app-config -o yaml
# View specific key
kubectl get configmap app-config -o jsonpath='{.data.DATABASE_HOST}'
Clean Up
kubectl delete pod nginx-custom app-pod app-pod-all-env app-pod-volume 2>/dev/null
kubectl delete configmap app-config nginx-config app-config-file 2>/dev/null
What's Next?
ConfigMaps handle regular configuration beautifully. But what about passwords, API keys, and database credentials? You can't put those in ConfigMaps — they're stored in plain text!
In the next tutorial, you'll learn about Secrets — ConfigMap's security-conscious cousin. Let's go!
What's Next?
ConfigMaps handle regular configuration. But what about passwords, API keys, and certificates? You don't want those in plain text. In the next tutorial, you'll learn about Secrets — Kubernetes' way of managing sensitive data.