The same image should run in every environment; only its configuration should differ.
A ConfigMap holds non-secret key-value configuration; a Secret holds sensitive data such as passwords, tokens and TLS keys. Both are namespaced and consumed by pods in two ways:
- as environment variables: one key with
valueFrom.configMapKeyRef/secretKeyRef, or all keys withenvFrom, - as files: mount the object as a volume and each key becomes a file.
Mounted files are updated automatically (after a short delay) when the object changes; environment variables are fixed at container start, so a change needs a rollout (kubectl rollout restart deploy/web). Mounts using subPath don't update either.
About Secrets: values are base64-encoded, not encrypted. Anyone who can read the Secret object can read the password. Protection comes from RBAC (restrict get/list on secrets), encryption at rest in etcd (configured by the cluster admin; managed services often provide it), and keeping secrets out of git (External Secrets Operator, Sealed Secrets, or a cloud secret manager with the CSI driver).
Create them from literals or files: kubectl create configmap app-config --from-file=app.conf or kubectl create secret generic db --from-literal=password=.... In manifests, stringData lets you write plain text that the API stores base64-encoded.
Mark a ConfigMap or Secret immutable: true when it should never change.
Example
apiVersion: v1
kind: ConfigMap
metadata: {name: app-config}
data: {LOG_LEVEL: info, app.conf: "workers = 4"}
---
apiVersion: v1
kind: Secret
metadata: {name: db}
stringData: {password: s3cr3t} # stored base64-encoded
---
apiVersion: v1
kind: Pod
metadata: {name: app}
spec:
containers:
- name: app
image: busybox:1.37
command: ["sh", "-c", "env; cat /etc/app/app.conf; sleep 3600"]
env:
- {name: LOG_LEVEL, valueFrom: {configMapKeyRef: {name: app-config, key: LOG_LEVEL}}}
- {name: DB_PASSWORD, valueFrom: {secretKeyRef: {name: db, key: password}}}
volumeMounts: [{name: conf, mountPath: /etc/app}]
volumes:
- {name: conf, configMap: {name: app-config}}Remember
- Inject config as env vars or mounted files
- Env vars need a restart to change; mounted files update
- Secrets are base64, not encrypted: protect them with RBAC and encryption at rest
Watch out for
- Committing Secret manifests with real passwords to git because they look encoded.