Workloads II: StatefulSet & DaemonSet
StatefulSet exists for workloads where Deployment's 'all replicas are interchangeable' assumption is false: databases, message brokers needing stable identity (predictable name, dedicated storage, fix
StatefulSet exists for workloads where Deployment's 'all replicas are interchangeable' assumption is false: databases, message brokers needing stable identity (predictable name, dedicated storage, fixed ordinal). DaemonSet solves a different problem: exactly one Pod on every eligible node for log collectors, monitoring agents, CNI/CSI components.
-
StatefulSet Pods get stable ordinal names like postgres-0, postgres-1 that persist across rescheduling.
-
Each StatefulSet Pod gets its own PVC from a volumeClaimTemplate. That PVC is NOT deleted when the Pod is deleted -- the replacement reattaches to the same PVC.
-
By default, Pods are created/scaled in strict ordinal order (OrderedReady). Switch to Parallel when ordering is not needed.
-
A DaemonSet controller watches nodes (not replica count) -- adding a node schedules a Pod there; removing a node removes it.
-
DaemonSet Pods need explicit tolerations to run on tainted nodes including control plane nodes.
For StatefulSet:
-
Create a headless Service (clusterIP: None) matching the StatefulSet's Pod labels first -- this provides the per-Pod stable DNS records the StatefulSet depends on.
-
Define the StatefulSet with volumeClaimTemplates so each replica gets its own dynamically-provisioned PVC, not a shared one.
-
Apply the StatefulSet; Kubernetes creates Pods in ordinal order (name-0, then name-1, ...), waiting for each to be Running and Ready before creating the next (unless podManagementPolicy: Parallel is set).
-
Each Pod gets a predictable DNS name: ...svc.cluster.local, used by peers for stable addressing (e.g. Postgres replication targets, Kafka broker discovery).
-
Scaling down removes the highest-ordinal Pod first, but its PVC survives -- scaling back up reattaches the same PVC to the same ordinal.
For DaemonSet:
-
Define the DaemonSet with a Pod template and, if it needs to run on control-plane/tainted nodes, matching tolerations.
-
Apply it -- the DaemonSet controller compares desired vs actual against every eligible node, not a target replica count.
-
Adding a new node to the cluster automatically schedules a Pod there; no manual scheduling step.
-
Use nodeSelector/affinity if only a subset of nodes should run the DaemonSet Pod (e.g. GPU-node-only agents).
-
StatefulSet: running a self-managed PostgreSQL or MySQL replica set where each replica needs a stable identity and its own persistent volume for WAL/data files.
-
StatefulSet: deploying a Kafka or Zookeeper cluster, where each broker's ordinal identity is baked into cluster configuration (broker.id, ensemble membership).
-
DaemonSet: running a log-shipping agent like Fluent Bit or Filebeat on every node to tail container logs.
-
DaemonSet: running a CNI plugin (Calico, Cilium) or a CSI node-driver, which must exist on literally every node to function.
-
DaemonSet: running a node-level monitoring agent (node-exporter) or a security/runtime agent (Falco) for uniform coverage.
-
Always front a StatefulSet with a headless Service -- without one, the stable per-Pod DNS records that make StatefulSet useful don't exist.
-
Size volumeClaimTemplates deliberately; growing them later usually needs a StorageClass with allowVolumeExpansion or manual PVC surgery, not a simple StatefulSet edit.
-
Use podManagementPolicy: Parallel for stateless-but-storage-heavy workloads that don't need ordered startup, to cut deployment time.
-
Give DaemonSet Pods tight resource requests/limits -- they run on every node including ones already busy with application workloads, so an oversized DaemonSet Pod steals capacity cluster-wide.
-
Add tolerations for control-plane taints on DaemonSets that must run everywhere (e.g. CNI, log shipping), otherwise they silently skip control-plane nodes.
-
Use updateStrategy: RollingUpdate with a sensible maxUnavailable for both StatefulSet and DaemonSet so upgrades don't take down the whole fleet in one step.
-
Deleting a StatefulSet's headless Service while Pods still run -- breaks peer-to-peer DNS resolution the application relies on (Kafka/Zookeeper members losing each other).
-
Assuming StatefulSet Pod deletion also deletes its PVC -- it doesn't; forgotten PVCs from decommissioned StatefulSets quietly consume storage and cost.
-
Running a stateful, ordered application as a plain Deployment because it 'already worked in testing' -- ReplicaSet gives no ordinal identity or stable storage per replica, so it silently breaks under real failover/restart scenarios.
-
Setting a DaemonSet's resource requests too high, so it doesn't fit on smaller nodes and leaves nodes without the agent it's supposed to run everywhere.
-
Forgetting tolerations on a DaemonSet that must run on tainted nodes (e.g. GPU nodes, control-plane) -- the Pod is silently never scheduled there.
-
Using OrderedReady (the default) for a StatefulSet with dozens of replicas where startup order doesn't actually matter -- adds unnecessary deployment latency.
-
StatefulSet Pod startup is serialized by default (OrderedReady) -- for large clusters where members don't strictly need sequential bootstrap, podManagementPolicy: Parallel cuts total rollout time significantly.
-
Per-Pod PVCs from volumeClaimTemplates mean storage I/O scales linearly with replica count but also means no shared-volume contention between replicas -- pick a StorageClass with performance characteristics matching what each stateful replica actually needs.
-
DaemonSet Pods compete for node resources with whatever application Pods land on the same node -- keep them lightweight so they don't distort bin-packing decisions the scheduler makes for everything else.
-
For DaemonSets doing log/metric collection, batch and buffer output rather than shipping on every event -- per-node fan-out to a central collector can become a bottleneck at cluster scale.
-
Back up StatefulSet PVCs independently of the StatefulSet object itself (via volume snapshots or an application-level backup job) -- deleting the StatefulSet won't delete PVCs, but a mistaken PVC deletion has no Kubernetes-level undo.
-
Monitor StatefulSet rollout status explicitly (kubectl rollout status statefulset/) in CI/CD -- a stuck ordinal (e.g. Pod 2 never becomes Ready) blocks all higher-ordinal Pods silently.
-
Run DaemonSets with a PriorityClass set high enough that they aren't evicted under node pressure before the workloads they support.
-
Test StatefulSet scale-down/scale-up cycles in staging before relying on them in production -- reattachment to the same PVC is expected behavior but easy to be surprised by in an incident.
-
Deploy a 3-replica StatefulSet running Postgres or a simple stateful app, with a headless Service, and confirm each Pod resolves via
<pod>.<service>.default.svc.cluster.local. -
Delete the middle-ordinal Pod (e.g. pod-1) and observe it comes back with the same name and reattaches to the same PVC.
-
Scale a StatefulSet down then back up and check
kubectl get pvcbefore/after to confirm PVCs from removed ordinals aren't deleted. -
Deploy a DaemonSet (e.g. a simple log-tailer) across a multi-node cluster and confirm exactly one Pod lands per node with
kubectl get pods -o wide.
-
StatefulSet provides stable per-Pod identity, stable network addressing via headless Service, and persistent PVCs per ordinal.
-
PVCs from volumeClaimTemplates are NOT deleted on Pod deletion or scale-down by default.
-
DaemonSets reconcile toward one Pod per eligible node -- no replica count to manage.
-
DaemonSets need explicit tolerations for tainted nodes including control plane nodes.
Want a visual for this concept?
Generate a diagram tailored to “Workloads II: StatefulSet & DaemonSet” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.
Sign in to generate a visual →