Kubernetes
StatefulSet
Environment Variables
Pod Configuration
DevOps

Passing separate env variables to statefulset pods

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A StatefulSet creates Pods from one shared template, so literal environment variables in the manifest are identical across replicas. If each Pod needs a different value, the usual solution is to derive that value from the Pod's stable identity or load per-Pod configuration at startup.

Start With the StatefulSet Pod Identity

StatefulSet Pods have stable names such as app-0, app-1, and app-2. That naming pattern is the key to per-replica behavior.

You can inject the Pod name with the downward API:

yaml
1env:
2  - name: POD_NAME
3    valueFrom:
4      fieldRef:
5        fieldPath: metadata.name

Once the container knows its own name, it can derive the ordinal suffix and pick the correct configuration.

Derive Values in the Entrypoint

A simple and common pattern is to branch in the startup command:

yaml
1apiVersion: apps/v1
2kind: StatefulSet
3metadata:
4  name: app
5spec:
6  serviceName: app
7  replicas: 3
8  selector:
9    matchLabels:
10      app: app
11  template:
12    metadata:
13      labels:
14        app: app
15    spec:
16      containers:
17        - name: app
18          image: busybox
19          command:
20            - sh
21            - -c
22            - |
23              ordinal="${HOSTNAME##*-}"
24              if [ "$ordinal" = "0" ]; then
25                export ROLE=primary
26              else
27                export ROLE=replica
28              fi
29              echo "pod=$HOSTNAME role=$ROLE"
30              sleep 3600
31          env:
32            - name: POD_NAME
33              valueFrom:
34                fieldRef:
35                  fieldPath: metadata.name

Here the hostname encodes the ordinal, so the container can decide its own role at runtime.

Use Indexed Config for More Complex Per-Pod Values

If each Pod needs a different address list, token, or config fragment, a derived role may not be enough. In that case, keep several config files in a mounted ConfigMap and select the right one by ordinal.

For example, mount files named node-0.env, node-1.env, and node-2.env, then load the one matching the Pod:

bash
ordinal="${HOSTNAME##*-}"
cp "/config/node-${ordinal}.env" /app/runtime.env

The application can then source or parse /app/runtime.env before starting.

This pattern keeps the StatefulSet manifest generic while still allowing specific behavior for each replica.

What Kubernetes Does Not Do Automatically

Kubernetes does not have a built-in syntax that says "replica zero gets this environment variable, replica one gets another one" inside a single plain env list. The template is copied as-is. StatefulSet identity gives you the raw material, but you still provide the branching logic.

That is why most working designs fall into one of these categories:

  • derive values from Pod name or ordinal
  • load indexed config files
  • query an external configuration service using Pod identity

For clustered systems such as databases, brokers, and consensus services, this is usually a feature rather than a limitation. Replica zero can bootstrap the cluster, while later replicas join using configuration derived from their stable ordinal numbers.

Common Pitfalls

  • Expecting static env values in the StatefulSet template to differ automatically per replica.
  • Ignoring the Pod name and hostname even though they already contain the ordinal you need.
  • Creating a separate manifest per replica when one generic manifest plus ordinal-based logic would be simpler.
  • Storing sensitive per-Pod values in plain ConfigMaps instead of Secrets or external secret management.
  • Making the startup script so complex that it becomes harder to debug than an indexed config-file approach.

Summary

  • StatefulSet replicas share one Pod template, so literal env vars are the same for every Pod.
  • Stable Pod identity such as app-0, app-1, and app-2 is the normal source of per-Pod differences.
  • Use the downward API to inject the Pod name and derive the ordinal at startup.
  • For more complex cases, select indexed config files or external configuration by Pod identity.
  • Keep the StatefulSet manifest generic and make per-Pod behavior explicit.

Course illustration
Course illustration

All Rights Reserved.