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:
- Encryption at rest in etcd (managed clusters: enable envelope encryption with your KMS key).
- RBAC:
get/list secretsis effectively read access to every credential in the namespace.listreturns values too. - 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.
- 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.