Frontend Labs
⋯

16. Configuration: ConfigMaps, Secrets, and the Downward API

16.1 ConfigMaps

apiVersion: v1
kind: ConfigMap
metadata:
  name: orders-config
data:
  LOG_LEVEL: info
  DB_MAX_CONNS: "10"
  DRAIN_DELAY: 5s
  features.yaml: |
    new_checkout: false
# consume as env vars (read at start only) ...
envFrom:
  - configMapRef: { name: orders-config }
# ... or as files (updated in place ~1 min after the ConfigMap changes, unless mounted via subPath)
volumeMounts:
  - { name: config, mountPath: /etc/orbit, readOnly: true }
volumes:
  - name: config
    configMap: { name: orders-config, items: [{ key: features.yaml, path: features.yaml }] }

Best practice: changing a ConfigMap does not restart pods. Make config changes roll out like code changes. Kustomize's configMapGenerator (and Helm's checksum-annotation pattern) put a hash in the name or annotation, so a config change produces a new pod template and a normal rolling update, with rollback (§26).

16.2 Secrets: what they are and are not

kubectl create secret generic orders-db --from-literal=DATABASE_URL='postgres://...' --dry-run=client -o yaml

A Secret is a ConfigMap with base64 encoding (not encryption), tighter default handling (tmpfs mounts, not printed by describe), and separate RBAC. To make Secrets actually secret:

  1. Encryption at rest in etcd (managed clusters: enable envelope encryption with your KMS key).
  2. RBAC: get/list secrets is effectively read access to every credential in the namespace. list returns values too.
  3. Never commit Secret YAML to Git. Use the External Secrets Operator (pulls from Vault/AWS Secrets Manager/GCP Secret Manager) or Sealed Secrets / SOPS (encrypted in Git). Covered in §34.4.
  4. Prefer files over env vars for secrets. Env vars leak into crash dumps, /proc/<pid>/environ, and child processes, and get logged by "print config at startup" code.

16.3 Image pull secrets

kubectl create secret docker-registry ghcr --docker-server=ghcr.io \
  --docker-username=$USER --docker-password=$GHCR_TOKEN -n orbit
kubectl patch serviceaccount default -n orbit -p '{"imagePullSecrets":[{"name":"ghcr"}]}'

On EKS/GKE/AKS, prefer node or workload identity to the cloud registry: no static credentials to rotate.

16.4 The Downward API: tell the pod about itself

env:
  - name: POD_NAME
    valueFrom: { fieldRef: { fieldPath: metadata.name } }       # worker consumer name
  - name: POD_NAMESPACE
    valueFrom: { fieldRef: { fieldPath: metadata.namespace } }
  - name: NODE_NAME
    valueFrom: { fieldRef: { fieldPath: spec.nodeName } }
  - name: POD_IP
    valueFrom: { fieldRef: { fieldPath: status.podIP } }
  - name: MEMORY_LIMIT
    valueFrom: { resourceFieldRef: { resource: limits.memory } }
  - name: OTEL_RESOURCE_ATTRIBUTES          # telemetry knows which pod/node it came from
    value: "k8s.pod.name=$(POD_NAME),k8s.namespace.name=$(POD_NAMESPACE),k8s.node.name=$(NODE_NAME)"

$(VAR) references only work for variables defined earlier in the same env list.


Generated from real-life-k8s-guide.md · 8 Oct 2026 16:36