# When to Use Kubernetes Deployments, StatefulSets, or DaemonSets in Production

> Learn when to use Kubernetes Deployments for stateless apps, StatefulSets for stateful apps needing stable identities, and DaemonSets for node-level agents. Master production workload choices.

- Repository: [Arie Bregman/devops-exercises](https://github.com/bregman-arie/devops-exercises)
- Tags: deep-dive
- Published: 2026-02-28

---

**Choose Deployments for stateless horizontally-scalable services, StatefulSets for stateful applications requiring stable network identities and ordered startup, and DaemonSets for node-level agents that must run on every node.**

Selecting the appropriate Kubernetes workload controller is critical for production stability and scalability. According to the `bregman-arie/devops-exercises` repository, the choice between Deployments, StatefulSets, and DaemonSets depends on three core characteristics: statefulness, pod identity requirements, and node distribution patterns. Understanding these differences ensures your applications run efficiently while maintaining data integrity and high availability.

## Understanding the Three Primary Workload Controllers

### Deployments for Stateless Services

Use **Deployments** for stateless or loosely-coupled services where pods can be freely recreated without data loss. As documented in [`topics/kubernetes/README.md`](https://github.com/bregman-arie/devops-exercises/blob/main/topics/kubernetes/README.md) at line 726, Deployments provide declarative rollout, rollback, and horizontal scaling capabilities ideal for front-end APIs, web applications, and microservices. Each replica is interchangeable, and the normal scheduler distributes pods across nodes based on selectors, affinity rules, and taints/tolerations without guaranteeing specific placement.

### StatefulSets for Persistent Identities

Choose **StatefulSets** when your workload requires stable network identities, ordered startup/termination, and persistent storage. The [`topics/kubernetes/README.md`](https://github.com/bregman-arie/devops-exercises/blob/main/topics/kubernetes/README.md) file at line 1112 explains that StatefulSets guarantee a **stable ordinal index** (`0…N-1`) and unique hostnames, which is essential for databases like PostgreSQL, Cassandra, or clustered services like Kafka and ZooKeeper that require leader election or quorum formation. Each pod maintains its own PersistentVolumeClaim, ensuring data survives rescheduling.

### DaemonSets for Node-Level Coverage

Deploy **DaemonSets** when you need exactly one pod per node (or per nodes matching specific selectors). As described in [`topics/kubernetes/README.md`](https://github.com/bregman-arie/devops-exercises/blob/main/topics/kubernetes/README.md) at line 720, DaemonSets are designed for node-level agents such as log collectors (Fluentd), monitoring exporters (Prometheus node-exporter), or networking plugins (CNI). These pods are typically stateless, using `hostPath` volumes or external storage rather than PersistentVolumeClaims, and run independently without ordering guarantees.

## Decision Criteria for Production Workloads

### Statefulness and Storage Requirements

- **Stateless/Loosely-coupled**: Choose **Deployments** when pods hold no persistent identity or data and can be replaced arbitrarily.
- **Stateful with Stable Storage**: Choose **StatefulSets** when each pod must maintain unique state via PersistentVolumeClaims and requires persistent identity across rescheduling.
- **Node-local State**: Choose **DaemonSets** for agents that access node-local resources (logs, system metrics) but do not require persistent pod-specific storage.

### Pod Identity and Ordering Guarantees

- **Interchangeable Replicas**: **Deployments** treat all pods as identical; any pod can handle any request, and ordering is not guaranteed during scaling.
- **Ordinal Index and Hostname Stability**: **StatefulSets** assign predictable names (e.g., `pg-0`, `pg-1`) and respect creation/termination order, crucial for cluster formation protocols.
- **Per-Node Independence**: **DaemonSets** create pods named after the node itself, with no ordering constraints between different nodes.

### Node Distribution Patterns

- **Scheduler-Based Placement**: Both **Deployments** and **StatefulSets** rely on the Kubernetes scheduler for placement decisions, allowing complex affinity and anti-affinity rules.
- **Mandatory Per-Node Execution**: **DaemonSets** bypass the standard scheduler to ensure execution on every selected node, making them ideal for infrastructure-level services that must run regardless of resource constraints.

## Practical Implementation Examples

The `bregman-arie/devops-exercises` repository provides concrete manifest examples in `topics/kubernetes/exercises/kustomize_common_labels/` and related sections. Here are production-ready patterns:

```yaml

# Deployment – Stateless web service (nginx)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:alpine

```

```yaml

# StatefulSet – PostgreSQL with persistent storage

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: pg
spec:
  serviceName: "pg"
  replicas: 2
  selector:
    matchLabels:
      app: pg
  template:
    metadata:
      labels:
        app: pg
    spec:
      containers:
      - name: postgres
        image: postgres:13
        volumeMounts:
        - name: pgdata
          mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
  - metadata:
      name: pgdata
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 10Gi

```

```yaml

# DaemonSet – Node-level log collector

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
spec:
  selector:
    matchLabels:
      name: fluentd
  template:
    metadata:
      labels:
        name: fluentd
    spec:
      containers:
      - name: fluentd
        image: fluent/fluentd:v1.11
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      volumes:
      - name: varlog
        hostPath:
          path: /var/log

```

## Decision Workflow for Engineers

Follow this three-step process from the `devops-exercises` analysis to select the correct controller:

1. **Does the workload require stable pod identity or persistent storage?**
   - Yes → **StatefulSet**
   - No → Continue to step 2

2. **Must a pod run on every node (or a specific subset of nodes)?**
   - Yes → **DaemonSet**
   - No → Continue to step 3

3. **Is the workload stateless and horizontally scalable?**
   - Yes → **Deployment**

## Summary

- **Deployments** manage stateless applications where pod replacement does not affect service integrity, offering simple scaling and rolling updates as shown in [`topics/kubernetes/exercises/kustomize_common_labels/deployment.yml`](https://github.com/bregman-arie/devops-exercises/blob/main/topics/kubernetes/exercises/kustomize_common_labels/deployment.yml).
- **StatefulSets** provide guaranteed ordering, stable network identities, and persistent storage for applications like databases and message queues, documented at line 1112 of the main README.
- **DaemonSets** ensure node-level coverage for infrastructure agents like log shippers and monitoring tools, detailed at line 720 of the repository's Kubernetes documentation.
- The [`topics/kubernetes/CKA.md`](https://github.com/bregman-arie/devops-exercises/blob/main/topics/kubernetes/CKA.md) file provides additional troubleshooting context for these workload controllers.

## Frequently Asked Questions

### Can I use a Deployment instead of a StatefulSet for a database?

No, using a Deployment for a database risks data loss and split-brain scenarios. Deployments recreate pods with random names and do not guarantee ordered startup, which can break replication protocols. StatefulSets provide the stable network identity and persistent volume binding required for consistent database clustering.

### Do DaemonSets support rolling updates?

Yes, DaemonSets support rolling updates through the `updateStrategy` field, allowing you to update the pod template while maintaining one pod per node. However, unlike Deployments, you cannot scale a DaemonSet to multiple replicas per node; it strictly enforces a one-to-one relationship with selected nodes.

### How do StatefulSets handle storage when scaling down?

StatefulSets do **not** delete PersistentVolumeClaims when scaling down or deleting pods. This safety mechanism prevents accidental data loss. When you scale back up, the new pod reattaches to the existing PVC with its previous data intact. You must manually delete PVCs if you want to remove the storage permanently.

### Can I run a DaemonSet on only specific nodes?

Yes, DaemonSets support node selectors, node affinity, and taints/tolerations to limit execution to specific nodes. For example, you can deploy GPU monitoring agents only on nodes with GPU hardware by specifying `nodeSelector` in the pod template, ensuring the DaemonSet skips irrelevant nodes.