Environment Variables in Kubernetes — Full Reference¶
Reference: https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/
Exam Priority — Quickest Path¶
For simple env var questions (2-4%), imperative one-liner:
For env vars sourced from ConfigMap/Secret, you need YAML — can't do that imperatively:
kubectl run my-pod --image=busybox --restart=Never --dry-run=client -o yaml > pod.yaml
# add env.valueFrom section, then:
kubectl apply -f pod.yaml
What the Raw Notes Exercise Was Actually Testing¶
The question said: "update the pod to use an environment variable with value Sony Tv Is Good."
The mistake was changing the command directly (echo 'Sony Tv Is Good'). That's hardcoding the value in the command — not using an env var. What the question wanted:
containers:
- name: product-container
image: busybox
command:
- sh
- -c
- echo $MY_VAR && sleep 3600 # command references the var, not the value directly
env:
- name: MY_VAR
value: "Sony Tv Is Good" # value lives here, in the env section
The command references $MY_VAR. At runtime the shell expands $MY_VAR to Sony Tv Is Good. The value is defined once in env, not embedded in the command string.
Why this is worth 8 points: it's testing that you understand the env var pattern — separating what a container does (the command) from what config it uses (the value). This is a real-world pattern, not just syntax.
But isn't it still hardcoded? Yes — "Sony Tv Is Good" is still written directly in the YAML. The real solution in production is sourcing from a ConfigMap or Secret. In this exam question, the value is hardcoded in env.value — that's acceptable here. The next level is valueFrom.
Recreating a Running Pod¶
You can't kubectl apply changes to most pod fields once it's running — pods are largely immutable. Options:
# Delete and recreate
kubectl delete pod product
kubectl apply -f product.yaml
# Force replace (delete + recreate in one command)
kubectl replace --force -f product.yaml
kubectl replace --force = delete the existing pod immediately, create new one from file. Faster for exam. Note: --force adds --grace-period=0 — the pod is killed instantly with no graceful shutdown.
Three Ways to Set Env Vars in a Pod¶
1. Hardcoded value¶
Simple. Value is in the YAML. Every pod created from this spec gets the same value. Fine for constants — bad for anything that changes per environment.
2. From a ConfigMap key¶
env:
- name: MY_VAR
valueFrom:
configMapKeyRef:
name: my-configmap # ConfigMap object name
key: my-key # key within that ConfigMap
Value is not in the pod spec — it's in the ConfigMap. To change the value: update the ConfigMap, recreate the pod. Different environments can have different ConfigMaps with the same key names — same pod spec works in dev and prod.
3. From a Secret key¶
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret # Secret object name
key: password # key within that Secret
Same pattern as ConfigMap, but for sensitive data. The base64 value in the Secret is decoded automatically — the container sees the plain text value.
envFrom — Inject All Keys at Once¶
Instead of mapping keys one by one, inject the entire ConfigMap or Secret:
envFrom:
- configMapRef:
name: my-configmap # every key becomes an env var
- secretRef:
name: db-secret # every key becomes an env var
Result: if my-configmap has keys APP_PORT=8080 and LOG_LEVEL=info, the container gets env vars APP_PORT and LOG_LEVEL automatically — no individual mapping.
env vs envFrom — when to use which:
env |
envFrom |
|
|---|---|---|
| Key selection | One key at a time | All keys from the source |
| Rename keys | Yes — env var name can differ from key name | No — env var name = key name |
| Safety | Explicit, no surprises | Risky if source has a key called PATH |
| Exam use | When question specifies a specific key | When question says "inject all config" |
Other env var Sources — valueFrom¶
Beyond ConfigMap and Secret, you can pull from the pod's own metadata:
env:
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name # the pod's own name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: MY_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: CPU_LIMIT
valueFrom:
resourceFieldRef:
containerName: app
resource: limits.cpu # container's own CPU limit
fieldRef = pull from pod/node metadata. resourceFieldRef = pull from the container's own resource requests/limits. Rarely needed in CKA but exists.
$VAR vs $(VAR) in Commands¶
Both work, but behave differently:
command:
- sh
- -c
- echo $(MY_VAR) # Kubernetes variable substitution — evaluated BEFORE shell runs
$MY_VAR — standard shell expansion. The shell (sh -c) evaluates $MY_VAR when it runs the string. Works as expected.
$(MY_VAR) — Kubernetes-level substitution. Kubernetes replaces $(MY_VAR) with the actual value before passing the command to the container. Useful when you want to compose values from other env vars:
env:
- name: BASE_URL
value: "http://my-service"
- name: FULL_URL
value: "$(BASE_URL)/api/v1" # Kubernetes substitutes BASE_URL here
For the exam, use $MY_VAR in sh -c commands. It works and is cleaner.
Critical: Env Vars Are Injected at Pod Start — Not Dynamic¶
When a pod starts, Kubernetes reads the env/envFrom values and injects them into the container's environment. After that, the env var is static for the lifetime of the container.
Consequence: if you update a ConfigMap, running pods do NOT see the new value. Their env vars were set at start time and don't change. You must delete/recreate the pod to pick up the new ConfigMap value.
Exception: ConfigMap mounted as a volume — Kubernetes does eventually update mounted files when the ConfigMap changes (within the sync period, ~1-2 minutes). But env vars from ConfigMap: never dynamic.
Full Pod Spec — Env Var Section Reference¶
spec:
containers:
- name: app
image: busybox
# ── INDIVIDUAL ENV VARS ───────────────────────────────────────
env:
- name: PLAIN_VALUE
value: "hello"
- name: FROM_CONFIGMAP
valueFrom:
configMapKeyRef:
name: my-cm
key: some-key
- name: FROM_SECRET
valueFrom:
secretKeyRef:
name: my-secret
key: password
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
# ── INJECT ALL KEYS FROM SOURCE ───────────────────────────────
envFrom:
- configMapRef:
name: my-cm
- secretRef:
name: my-secret
Quick Reference — All Commands¶
# Set env var imperatively (hardcoded value only)
kubectl run my-pod --image=busybox --env="KEY=VALUE" --restart=Never -- sleep 3600
# Create ConfigMap to source from
kubectl create configmap my-cm --from-literal=KEY=VALUE
kubectl create configmap my-cm --from-env-file=.env
# Create Secret to source from
kubectl create secret generic my-secret --from-literal=password=s3cr3t
# Check what env vars are running in a pod
kubectl exec my-pod -- env
kubectl exec my-pod -- printenv KEY
# Generate pod YAML with env var to edit
kubectl run my-pod --image=busybox --restart=Never --dry-run=client -o yaml > pod.yaml
# Recreate a running pod with changes
kubectl replace --force -f pod.yaml
# Check env var value inside a running pod
kubectl exec -it my-pod -- sh -c 'echo $MY_VAR'