07: ConfigMaps
07: ConfigMaps
Objective
- Understand what ConfigMaps are and when to use them
- Learn three ways to create ConfigMaps (YAML,
--from-literal,--from-file) - Use ConfigMaps as environment variables (
configMapKeyRefandenvFrom) - Mount ConfigMaps as files in a volume
- Master the dry-run export pattern for generating YAML
Theory
What is a ConfigMap?
A ConfigMap is a Kubernetes API object that stores non-confidential configuration data as key-value pairs. It decouples configuration from container images, so you can change settings without rebuilding images.
ConfigMap data can be:
- Simple key-value strings (e.g.,
LOG_LEVEL=debug) - Entire configuration files (e.g.,
nginx.conf,app.properties)
Three Ways to Create a ConfigMap
| Method | Best For |
|---|---|
| YAML manifest | Version-controlled, declarative configuration |
--from-literal |
Quick creation of simple key-value pairs from the CLI |
--from-file |
Loading configuration files directly |
Two Usage Modes
graph TB
CM[ConfigMap]
CM --> ENV["As Environment Variables<br/>injected at container startup"]
CM --> VOL["As Volume Mount<br/>files appear in container filesystem"]
ENV --> E1["configMapKeyRef<br/>(single key)"]
ENV --> E2["envFrom<br/>(all keys at once)"]
VOL --> V1["Each key becomes a file"]
VOL --> V2["File content = value"]
When to Use Env Vars vs Volume Mount
flowchart TD
START["How will your app consume the config?"] --> Q1{"Is it a simple<br/>key-value pair?"}
Q1 -->|Yes| Q2{"Does the app read<br/>environment variables?"}
Q1 -->|No, it is a<br/>config file| VOL["Use Volume Mount"]
Q2 -->|Yes| ENV["Use Environment Variables"]
Q2 -->|No, it reads<br/>from a file path| VOL
ENV --> N1["Simpler setup<br/>Values set at startup<br/>No live reload"]
VOL --> N2["Files appear in container<br/>Can be multi-line content<br/>Supports live reload"]
Key Points
- ConfigMaps are namespace-scoped — they must be in the same namespace as the Pod that uses them.
- Maximum size of a ConfigMap is 1 MiB.
- When mounted as a volume, Kubernetes can update the files automatically when the ConfigMap changes (with a delay of up to 60 seconds). Environment variables are not updated.
- ConfigMaps are not encrypted — do not store passwords or secrets in them. Use Secrets instead (Exercise 08).
Practical Tasks
Task 1: Create a ConfigMap — YAML and CLI
Option A: Create from YAML
Create the file configmap-app.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: student-XX
data:
ENVIRONMENT: "staging"
LOG_LEVEL: "debug"
MAX_CONNECTIONS: "100"
kubectl apply -f configmap-app.yaml
Option B: Create from CLI with --from-literal
kubectl create configmap app-config-cli \
--from-literal=ENVIRONMENT=staging \
--from-literal=LOG_LEVEL=debug \
--from-literal=MAX_CONNECTIONS=100 \
-n student-XX
Option C: Create from a file
Create a file called app.properties:
database.host=db.internal
database.port=5432
database.pool.size=10
kubectl create configmap app-config-file --from-file=app.properties -n student-XX
Inspect the results:
# List ConfigMaps
kubectl get configmap -n student-XX
# View details
kubectl describe configmap app-config -n student-XX
# View as YAML
kubectl get configmap app-config -o yaml -n student-XX
# View the file-based ConfigMap
kubectl get configmap app-config-file -o yaml -n student-XX
Notice how --from-file creates a single key (the filename) with the entire file content as the value, while --from-literal creates individual keys.
Clean up the CLI-created ConfigMaps (keep app-config for the next task):
kubectl delete configmap app-config-cli app-config-file -n student-XX
Task 2: Use ConfigMap as Environment Variables
Using configMapKeyRef (select specific keys)
Create the file pod-env-configmap.yaml:
apiVersion: v1
kind: Pod
metadata:
name: pod-env-configmap
namespace: student-XX
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "echo ENVIRONMENT=$ENVIRONMENT LOG_LEVEL=$LOG_LEVEL && sleep 3600"]
env:
- name: ENVIRONMENT
valueFrom:
configMapKeyRef:
name: app-config
key: ENVIRONMENT
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
restartPolicy: Never
kubectl apply -f pod-env-configmap.yaml
kubectl logs pod-env-configmap -n student-XX
Expected output:
ENVIRONMENT=staging LOG_LEVEL=debug
Using envFrom (inject all keys at once)
Create the file pod-envfrom-configmap.yaml:
apiVersion: v1
kind: Pod
metadata:
name: pod-envfrom-configmap
namespace: student-XX
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "env | sort && sleep 3600"]
envFrom:
- configMapRef:
name: app-config
restartPolicy: Never
kubectl apply -f pod-envfrom-configmap.yaml
kubectl logs pod-envfrom-configmap -n student-XX | grep -E "ENVIRONMENT|LOG_LEVEL|MAX_CONNECTIONS"
Expected output:
ENVIRONMENT=staging
LOG_LEVEL=debug
MAX_CONNECTIONS=100
All three keys from the ConfigMap are injected automatically without listing them individually.
Clean up:
kubectl delete pod pod-env-configmap pod-envfrom-configmap -n student-XX
Task 3: Mount ConfigMap as a Volume
When a ConfigMap is mounted as a volume, each key becomes a file in the mount path.
Create a ConfigMap with a configuration file:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
namespace: student-XX
data:
nginx.conf: |
server {
listen 80;
server_name localhost;
location / {
return 200 'Hello from ConfigMap!\n';
}
}
settings.json: |
{
"debug": true,
"version": "1.0"
}
kubectl apply -f - <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
namespace: student-XX
data:
nginx.conf: |
server {
listen 80;
server_name localhost;
location / {
return 200 'Hello from ConfigMap!\n';
}
}
settings.json: |
{
"debug": true,
"version": "1.0"
}
EOF
Create the file pod-volume-configmap.yaml:
apiVersion: v1
kind: Pod
metadata:
name: pod-volume-configmap
namespace: student-XX
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "ls -la /etc/config/ && echo '--- nginx.conf ---' && cat /etc/config/nginx.conf && echo '--- settings.json ---' && cat /etc/config/settings.json && sleep 3600"]
volumeMounts:
- name: config-volume
mountPath: /etc/config
readOnly: true
volumes:
- name: config-volume
configMap:
name: nginx-config
restartPolicy: Never
kubectl apply -f pod-volume-configmap.yaml
kubectl logs pod-volume-configmap -n student-XX
Expected output:
total 0
lrwxrwxrwx 1 root root 17 ... nginx.conf -> ..data/nginx.conf
lrwxrwxrwx 1 root root 20 ... settings.json -> ..data/settings.json
--- nginx.conf ---
server {
listen 80;
server_name localhost;
location / {
return 200 'Hello from ConfigMap!\n';
}
}
--- settings.json ---
{
"debug": true,
"version": "1.0"
}
Notice how each key in the ConfigMap became a file in the /etc/config/ directory. The files are symlinks managed by Kubernetes.
Verify with exec:
kubectl exec pod-volume-configmap -n student-XX -- ls /etc/config/
kubectl exec pod-volume-configmap -n student-XX -- cat /etc/config/settings.json
Clean up:
kubectl delete pod pod-volume-configmap -n student-XX
kubectl delete configmap nginx-config -n student-XX
Task 4: Dry-Run Export Pattern
The --dry-run=client -o yaml pattern lets you generate YAML manifests from CLI commands without actually creating resources. This is useful for creating templates.
# Generate ConfigMap YAML from literals
kubectl create configmap my-config \
--from-literal=DB_HOST=postgres.default.svc \
--from-literal=DB_PORT=5432 \
-n student-XX \
--dry-run=client -o yaml
Output:
apiVersion: v1
data:
DB_HOST: postgres.default.svc
DB_PORT: "5432"
kind: ConfigMap
metadata:
creationTimestamp: null
name: my-config
namespace: student-XX
Save it to a file:
kubectl create configmap my-config \
--from-literal=DB_HOST=postgres.default.svc \
--from-literal=DB_PORT=5432 \
-n student-XX \
--dry-run=client -o yaml > my-config.yaml
This is the recommended pattern for generating YAML scaffolds that you can then customize and commit to version control.
Clean up all remaining resources:
kubectl delete configmap app-config --ignore-not-found -n student-XX
Common Problems
| Problem | Cause | Solution |
|---|---|---|
Pod stuck in CreateContainerConfigError |
Referenced ConfigMap does not exist | Create the ConfigMap before the Pod, or check the name |
| Env var not updating after ConfigMap change | Env vars are set at container startup only | Delete and recreate the Pod |
| Volume mount replaces entire directory | ConfigMap volume overwrites the target directory | Use subPath to mount individual files without replacing the directory |
Key name contains dots (e.g., app.properties) |
Dots are valid in ConfigMap keys but invalid as env var names | Use volume mount instead of envFrom, or rename the key |
Best Practices
- Use YAML manifests for production — Keep ConfigMaps in version control alongside your Deployment manifests.
- Use
envFromfor simple key-value configs — Avoids repetitiveconfigMapKeyRefentries. - Use volumes for configuration files — When your app reads from a file path (e.g.,
nginx.conf), mount the ConfigMap as a volume. - Set
readOnly: trueon volume mounts — Prevents accidental writes from inside the container. - Name ConfigMaps descriptively — Include the application or component name (e.g.,
frontend-config,nginx-config). - Use dry-run to generate YAML — Always use
--dry-run=client -o yamlto scaffold manifests instead of writing them from scratch.
Summary
In this exercise you learned how to:
- Create ConfigMaps using YAML manifests,
--from-literal, and--from-file - Inject ConfigMap values as environment variables using
configMapKeyRefandenvFrom - Mount ConfigMaps as files in a container using volume mounts
- Use the
--dry-run=client -o yamlpattern to generate ConfigMap YAML
Proceed to Exercise 08 to learn about Kubernetes Secrets for sensitive data.