Kubernetes ConfigMap vs Secret: what beginners need to know
ConfigMap vs Secret in Kubernetes: when to use each, env vars and volume mounts, kubectl get/describe, common beginner mistakes, and optional kprompt examples.
You know Deployments run your app and labels connect Deployments to Services — see labels and selectors explained if you need a refresher. The next question: where does configuration live? Kubernetes stores non-sensitive settings in ConfigMaps and sensitive values in Secrets.
This guide explains ConfigMap vs Secret, how Pods consume them, the kubectl commands that make misconfigurations visible, and the mistakes that cause CrashLoopBackOff on startup.
The one-sentence version
- ConfigMap — non-sensitive key/value config (URLs, feature flags, config files).
- Secret — sensitive data (passwords, tokens, TLS certs) — base64 in etcd is not encryption.
- Pods read both via environment variables or mounted files — wrong key names fail fast at startup.
ConfigMap vs Secret (side by side)
| ConfigMap | Secret | |
|---|---|---|
| Use for | App settings, JSON/YAML files, non-secret env | Passwords, API keys, TLS material |
| Kind | v1 ConfigMap | v1 Secret |
| Data field | data: or binaryData: | data: (base64-encoded values) |
| In logs/describe | Values often visible | Values hidden in kubectl get (still protect RBAC) |
| Typical mistake | Storing passwords in a ConfigMap | Committing Secret YAML to Git in plain text |
What is a ConfigMap?
A ConfigMap holds configuration data as key/value pairs or file contents. It does not run anything — you reference it from a Pod or Deployment template.
Minimal ConfigMap YAML
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
namespace: staging
data:
LOG_LEVEL: info
APP_ENV: staging
config.json: |
{"timeoutSeconds": 30, "featureX": true}What is a Secret?
A Secret stores sensitive bytes. Kubernetes encodes values as base64 in the API — that protects casual glances, not a determined attacker with etcd access. Use RBAC, external secret managers, and never paste production secrets into tickets or chat.
Minimal Secret YAML (demo only — use sealed-secrets or ESO in prod)
apiVersion: v1
kind: Secret
metadata:
name: api-secret
namespace: staging
type: Opaque
stringData: # plain text on apply; API stores base64
DB_PASSWORD: "change-me"
API_TOKEN: "demo-token"How Pods consume ConfigMaps and Secrets
Two common patterns: inject as environment variables, or mount as files under a volume. Deployments reference ConfigMap/Secret names in the Pod template — the same place you set container image and labels.
Env vars from ConfigMap and Secret
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: staging
spec:
replicas: 2
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: myapp:1.0
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: api-config
key: LOG_LEVEL
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: api-secret
key: DB_PASSWORDMount ConfigMap as files
volumeMounts:
- name: config-vol
mountPath: /etc/app/config.json
subPath: config.json
volumes:
- name: config-vol
configMap:
name: api-configkubectl commands that stick
Inspect ConfigMaps and Secrets
kubectl get configmaps -n staging
kubectl describe configmap api-config -n staging
kubectl get secrets -n staging
kubectl describe secret api-secret -n staging
# See which env a Pod actually got
kubectl get pod -l app=api -n staging -o yaml | grep -A20 "env:"
kubectl exec -it deploy/api -n staging -- env | grep LOG_LEVELWhen a bad config breaks your Pod
Missing ConfigMap key, wrong Secret name, or a typo in configMapKeyRef.key often produces CrashLoopBackOff with a short log: file not found or required env unset. That is configuration archaeology — not a mystery bug. For the full restart loop ladder, see the CrashLoopBackOff guide.
Updating config: what beginners miss
- Changing a ConfigMap does not always restart running Pods — apps may cache old values until rollout restart
- kubectl apply a fixed ConfigMap then kubectl rollout restart deployment/api — common fix pattern
- subPath mounts do not auto-update when the ConfigMap changes — plan for restart
- Secrets referenced by env vars require Pod recreate to pick up new values
Rollout after config change
kubectl apply -f api-config.yaml
kubectl rollout restart deployment/api -n staging
kubectl rollout status deployment/api -n stagingCommon beginner mistakes
- Storing DB passwords in a ConfigMap because it is easier than a Secret
- Secret in Git with stringData in plain text — use sealed-secrets, SOPS, or a secret manager
- ConfigMap in namespace staging but Deployment in default — get finds nothing
- Wrong key name in configMapKeyRef — Pod starts, app exits immediately
- Assuming base64 on a Secret means encrypted at rest without etcd encryption enabled
Same checks in natural language (optional)
kprompt can list and describe ConfigMaps and Secrets as reads. Mutations still show a plan and ask for approval on a TTY.
Soft kprompt examples
kprompt "list configmaps in staging"
kprompt "describe configmap api-config in staging"
kprompt "describe secret api-secret in staging"
kprompt "describe pod for deployment api in staging"What to learn next
ConfigMaps and Secrets feed your Deployment. Next, learn to read kubectl describe output when Pods misbehave, then resource requests and limits before you hit OOMKilled in production.
Related posts
Kubernetes labels and selectors explained (the glue between objects)
Labels and selectors in Kubernetes: how Deployments label Pods, how Services find them, kubectl -l and endpoints checks, common mistakes, and optional kprompt examples.
Read articleKubernetes Service vs Deployment: roles, not rivals
Service vs Deployment in Kubernetes: Deployments run and update Pods; Services give those Pods a stable network identity. When you need each, how they connect via labels, and kubectl checks that stick.
Read articlekubectl get pods explained: STATUS, restarts, and next commands
How to read kubectl get pods output — READY, STATUS, RESTARTS, AGE — what CrashLoopBackOff and Pending mean, and which kubectl command to run next.
Read article