ConfigMaps & Secrets
The same image should run in dev, staging, and production — that's the whole point of images. But those environments need different database URLs, feature flags, and credentials. Baking config into the image breaks the "same image everywhere" promise; Kubernetes' answer is to store configuration as cluster objects — ConfigMaps for plain settings, Secrets for sensitive ones — and inject them into pods at runtime.
💡 The Bottom Line
Build one image; keep everything environment-specific outside it. ConfigMaps hold non-sensitive key/values, Secrets hold credentials, and pods consume either as environment variables or mounted files. Change the config object, restart the pods, same image — new behavior.
A ConfigMap, consumed two ways
apiVersion: v1
kind: ConfigMap
metadata:
name: web-config
data:
LOG_LEVEL: "info"
CACHE_TTL: "300"
Injected into the Deployment's pod template as environment variables:
spec:
containers:
- name: web
image: myapp:1.0
envFrom:
- configMapRef:
name: web-config
envFrom turns every key into an env var. For a single value, use
env: with valueFrom: configMapKeyRef. ConfigMaps can also be
mounted as files (a volumes: + volumeMounts: pair) — the
right shape when the app expects a whole config file rather than variables.
Secrets: same idea, guarded harder
kubectl create secret generic db-cred \
--from-literal=DB_USER=app \
--from-literal=DB_PASSWORD=s3cr3t
Consumed identically (secretRef instead of configMapRef):
envFrom:
- secretRef:
name: db-cred
What actually makes a Secret different from a ConfigMap: it can be encrypted at rest in the cluster's database, access to it is separately controllable via RBAC, and tooling treats it as sensitive (not shown by default in various UIs). What does not make it different: the base64 you see in its YAML — that's encoding, not encryption.
🙋 There Are No Dumb Questions
Q: If base64 isn't encryption, are Secrets even safe?
A: Out of the box they're access-controlled, not strongly protected — anyone with
read access to Secrets in the namespace can decode them instantly. Production hardening
means enabling encryption at rest, restricting RBAC tightly, and often using an external
secret manager (Vault, cloud secret stores) with an operator syncing into the cluster.
For this track: use Secrets for credentials because it's the correct shape, and know the
hardening exists.
⚠️ Watch Out
Pods read ConfigMaps/Secrets injected as env vars once, at startup.
Editing the ConfigMap does not change running pods — a classic "why didn't my config apply?"
moment. Restart the pods to pick it up
(kubectl rollout restart deployment/web). File mounts do update in
place eventually, but only if the app re-reads the file. When config "isn't applying,"
this is almost always why.
🔧 Try It Yourself
Add the ConfigMap above to your Lesson 3 Deployment with envFrom, apply
both, then prove the injection:
kubectl exec deploy/web -- env | grep -E "LOG_LEVEL|CACHE_TTL"
Now edit the ConfigMap's LOG_LEVEL to "debug", re-apply, and
run the same exec — unchanged, as the Watch Out predicted. Then
kubectl rollout restart deployment/web and check once more.
✅ Quick Check
What actually protects a Kubernetes Secret's contents?
Last lesson: the error states every Kubernetes user meets —
CrashLoopBackOff, ImagePullBackOff, Pending — and the
debugging path through each.