Deployment vs StatefulSet vs DaemonSet: Choosing the Right Kubernetes Controller

Choose by Invariant, Not by Application Label

The useful question is not whether an application is a database or an agent. Ask what must remain true when a Pod is deleted, rescheduled, or upgraded.

ControllerReplica identityTypical placementPersistent identity/storageCommon use
DeploymentInterchangeableAny eligible nodesNo stable Pod identityAPIs, web apps, stateless workers
StatefulSetOrdered, stable ordinalsAny eligible nodesStable DNS and per-Pod claimsDatabases, brokers, clustered systems
DaemonSetUsually one per eligible nodeNode coverageNormally node-localLog, network, security, storage agents

All three manage Pods and replace failures. Their guarantees differ.

---

Deployment: Replaceable Replicas

apiVersion: apps/v1
kind: Deployment
metadata:
  name: catalog
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  selector:
    matchLabels:
      app: catalog
  template:
    metadata:
      labels:
        app: catalog
    spec:
      containers:
        - name: api
          image: registry.example.com/catalog:2.7.1
          ports:
            - containerPort: 8080
          readinessProbe:
            httpGet:
              path: /ready
              port: 8080
          resources:
            requests:
              cpu: 200m
              memory: 256Mi

A Deployment owns ReplicaSets, and a ReplicaSet maintains the replica count. Pod names and IPs change. Clients should use a Service, and application state should live outside the Pod or on storage designed for shared access.

maxUnavailable: 0 and maxSurge: 1 preserve four Ready replicas during a normal rollout but require room for a fifth Pod. A restrictive quota or a full cluster can stall that rollout.

---

StatefulSet: Stable Network and Storage Identity

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
spec:
  serviceName: redis-headless
  replicas: 3
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
        - name: redis
          image: redis:7.4
          volumeMounts:
            - name: data
              mountPath: /data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: fast-ssd
        resources:
          requests:
            storage: 20Gi

The Pods are redis-0, redis-1, and redis-2. If redis-1 is recreated, it keeps the same ordinal and reattaches its own data-redis-1 claim. A headless Service gives stable DNS such as redis-1.redis-headless.default.svc.cluster.local.

That stability does not make the application highly available. Kubernetes does not understand leader election, replication lag, quorum, or safe promotion unless an operator or the application handles them. StatefulSet also does not delete claims by default merely because a Pod or StatefulSet is deleted - a valuable data-safety behavior that requires an explicit cleanup plan.

Ordered rollout can stop at a broken ordinal. Inspect each member and the application cluster state before forcing deletion or changing update strategy.

---

DaemonSet: Node Coverage

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: log-agent
  namespace: observability
spec:
  selector:
    matchLabels:
      app: log-agent
  template:
    metadata:
      labels:
        app: log-agent
    spec:
      tolerations:
        - operator: Exists
      containers:
        - name: agent
          image: registry.example.com/log-agent:1.9.0
          resources:
            requests:
              cpu: 50m
              memory: 64Mi

A DaemonSet creates Pods on matching nodes as nodes appear and removes them as nodes disappear. Typical examples include CNI components, log collectors, node metrics exporters, and security agents.

Do not set replicas; desired count follows eligible nodes. Tolerating every taint may be correct for infrastructure agents, but it also places the Pod on control-plane or specialized nodes. Combine tolerations with node affinity when coverage should be narrower.

---

Common Wrong Turns

Use kubectl rollout status and kubectl describe for all controller rollouts, but evaluate success using the workload's own invariants. Practice stable identity in StatefulSet Redis Identity, node disruption behavior in Taints and PDB Maintenance, and one-shot semantics in Recover a Failed Job.