Skip to content

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:

kubectl run my-pod --image=busybox --restart=Never --env="MY_VAR=hello" -- sleep 3600

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

env:
- name: MY_VAR
  value: "hello world"

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           # shell expansion — works in most cases
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'