All posts
Emire Barış profile photoEmire Barış · Member3 min read

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)

ConfigMapSecret
Use forApp settings, JSON/YAML files, non-secret envPasswords, API keys, TLS material
Kindv1 ConfigMapv1 Secret
Data fielddata: or binaryData:data: (base64-encoded values)
In logs/describeValues often visibleValues hidden in kubectl get (still protect RBAC)
Typical mistakeStoring passwords in a ConfigMapCommitting 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_PASSWORD

Mount ConfigMap as files

          volumeMounts:
            - name: config-vol
              mountPath: /etc/app/config.json
              subPath: config.json
      volumes:
        - name: config-vol
          configMap:
            name: api-config

kubectl 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_LEVEL

When 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 staging

Common 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.