Skip to main content
RunBook Academy

KubernetesXX · ConfigurationConfiguration

Environment variables — ConfigMap keys as Pod env vars

Advanced⏱ ~17 minkubectlkubeadm

What you'll learn

  • Configure `envFrom` for bulk ConfigMap injection
  • Configure `valueFrom.configMapKeyRef` for selective injection
  • Explain why env vars do not update on ConfigMap change
  • Reason about the secret-leakage risk of env-var consumption

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

ConfigMap keys can be exposed to a container as environment variables. This is the most common consumption pattern for small, simple configuration — feature flags, log levels, external service URLs. The pattern has a critical production caveat: env vars do not update when the ConfigMap changes; the Pod must be restarted. This lesson covers the two injection modes, the runtime semantics, and the patterns that work.

Two modes of injection

envFrom — all keys at once

spec:
  containers:
  - name: web
    image: web:v1
    envFrom:
    - configMapRef:
        name: web-config

Every key in the ConfigMap becomes an env var. With a ConfigMap containing log_level: info, the container sees LOG_LEVEL=info. Kubernetes replaces invalid env-var characters (-, .) with _.

A ConfigMap like:

data:
  log_level: info
  database.url: postgres://db.prod/data
  feature-checkout_v2: "true"

Becomes env vars:

LOG_LEVEL=info
DATABASE_URL=postgres://db.prod/data
FEATURE_CHECKOUT_V2=true

valueFrom — specific keys

spec:
  containers:
  - name: web
    image: web:v1
    env:
    - name: LOG_LEVEL
      valueFrom:
        configMapKeyRef:
          name: web-config
          key: log_level
    - name: DATABASE_URL
      valueFrom:
        configMapKeyRef:
          name: web-config
          key: database_url

This is selective. The container sees only the env vars declared, with the exact names. Useful when the application expects a specific env var name that does not match the ConfigMap key.

Required vs optional

env:
- name: DATABASE_URL
  valueFrom:
    configMapKeyRef:
      name: web-config
      key: database_url
      optional: false   # default

If optional: false (default), the Pod stays in ContainerCreating until the ConfigMap and key exist. Setting optional: true allows the Pod to start without the key (the env var is unset).

flowchart TB
    A[Pod created] --> B{ConfigMap<br/>exists?}
    B -->|no, optional=true| C["Pod starts<br/>env var unset"]
    B -->|no, optional=false| D["Pod stuck<br/>ContainerCreating"]
    B -->|yes| E{Key exists?}
    E -->|no, optional=true| C
    E -->|no, optional=false| D
    E -->|yes| F["Pod starts<br/>env var set"]

Runtime update semantics

flowchart LR
    A[ConfigMap updated] --> B[Kubelet observes change]
    B --> C{Container env vars<br/>updated?}
    C -->|no| D["Env vars set at container<br/>start, frozen"]
    C -->|n/a, env vars are<br/>read from /proc at start| D

Environment variables are part of the container’s initial process state. They are set by the container runtime when the container starts and are read from /proc/<pid>/environ by the application. Subsequent updates to the ConfigMap do not modify the running container’s environ.

Triggering a rollout from a ConfigMap change

A ConfigMap change does not automatically roll the Pods. The Deployment’s controller does not watch ConfigMaps by default. The patterns:

flowchart TB
    A[ConfigMap changed] --> B{How is it<br/>consumed?}
    B -->|env vars| C["Manual rollout<br/>kubectl rollout restart"]
    B -->|files| D["App reload<br/>or manual rollout"]
    B -->|sha in annotation| E["Deployment annotates<br/>template with sha"]
    E --> F["Hash changes<br/>new template hash<br/>rollout triggered"]

The hash annotation pattern:

spec:
  template:
    metadata:
      annotations:
        config-checksum: <computed sha256 of the ConfigMap>

A controller (Reloader, Argo CD, Flux) computes the hash and updates the annotation; the Deployment’s template hash changes; the rollout triggers.

Security: env vars in /proc

# On any Pod that has env vars from a ConfigMap
cat /proc/1/environ | tr '\0' '\n'
# LOG_LEVEL=info
# DATABASE_URL=postgres://db.prod/data

Env vars are visible in /proc/<pid>/environ. Any process in the Pod can read them. Any process with access to the node (root, kubelet, sidecar with hostPath) can read them.

This is a non-secret consumption pattern. Database URLs are typically OK; passwords are not. Secrets should be mounted as files, not env vars, when possible — the file content can have stricter file permissions, and the process can mmap it without writing it to a log.

Production patterns

Pattern: feature flags

apiVersion: v1
kind: ConfigMap
metadata:
  name: feature-flags
data:
  checkout_v2: "true"
  new_search: "false"
---
spec:
  containers:
  - name: web
    env:
    - name: FF_CHECKOUT_V2
      valueFrom:
        configMapKeyRef:
          name: feature-flags
          key: checkout_v2
    - name: FF_NEW_SEARCH
      valueFrom:
        configMapKeyRef:
          name: feature-flags
          key: new_search

The application reads FF_CHECKOUT_V2 and FF_NEW_SEARCH at startup. A change to the ConfigMap requires a rollout.

Pattern: external service URLs

apiVersion: v1
kind: ConfigMap
metadata:
  name: backend-urls
data:
  postgres_url: postgres://db.prod/data
  redis_url: redis://cache.prod:6379
  auth_url: https://auth.prod/issuer
envFrom:
- configMapRef:
    name: backend-urls

All three URLs available as env vars. A change to postgres_url (e.g., failover) requires a rollout.

Pattern: log level

data:
  log_level: info
  log_format: json

A LOG_LEVEL=info change requires a restart. Production typically does not roll a Deployment for a log level change; the operator accepts that the change takes effect on the next rollout.

Quiz

Knowledge check · 4 questions

  1. Q1. What is the difference between envFrom and valueFrom in a Pod's env spec?

  2. Q2. Mounting a Secret as an environment variable is more secure than mounting it as a file because env vars are isolated to the process.

  3. Q3. Your team changes a ConfigMap to enable a feature flag. The Pod does not pick up the change. Diagnose.

    ConfigMap feature-flags updated to checkout_v2 true. The Deployment's Pod template consumes the ConfigMap via envFrom. The Pod is running; the feature flag is not enabled.

  4. Q4. Why is mounting a Secret as an env var a security risk, and what is the safer pattern?

Passing score: 75%. Answers are checked in this browser.

Production discipline

  • Use envFrom for bulk config; valueFrom for specific keys. Both are valid; the choice is the application’s preference.
  • Document the rollout trigger. A ConfigMap change does not roll the Deployment automatically. The runbook must spell out how to trigger a rollout.
  • Don’t put secrets in env vars. A database URL without credentials is fine; a database URL with a password is a Secret.
  • Verify env-var visibility. /proc/<pid>/environ is readable by any process in the Pod. The consumption pattern is part of the security review.
  • Use a hash annotation for automatic rollouts. A controller that hashes the ConfigMap and updates the Deployment annotation triggers a rollout on change; the operator does not need to remember.

Env vars are the simplest way to inject ConfigMap data into a container. They are also the most error-prone — the runtime-update gap is the source of many “I changed the config but nothing happened” tickets. Operators who understand the gap have ConfigMaps that work.