Sets and Controllers

Kubernetes organizes Pods into logical “Sets” and then uses specialized Controllers to manage their lifecycle. At its core, a Set is simply a group of resources most commonly Pods—that share a common purpose. Under the hood, Controllers constantly observe the cluster’s actual state and compare it to your declared desired state, spinning up or tearing down Pods to match. Let’s walk through each major Set type, starting with the foundational ReplicaSet.

1apiVersion: apps/v1
2kind: ReplicaSet
3metadata:
4  name: my-app-replicaset
5spec:
6  replicas: 3
7  selector:
8    matchLabels:
9      app: my-app
10  template:
11    metadata:
12      labels:
13        app: my-app
14    spec:
15      containers:
16      - name: my-app-container
17        image: nginx:1.23

A ReplicaSet ensures exactly N identical Pods exist at all times. Think of it as your application’s insurance policy if a Pod crashes or is evicted, the ReplicaSet immediately spins up a replacement. In practice, you rarely hand-craft ReplicaSets; instead, you declare a Deployment, and Kubernetes creates a ReplicaSet on your behalf. Deployments add rolling-update, rollback, and pause-resume capabilities, orchestrating ReplicaSets behind the scenes.

Moving beyond stateless replicas, a StatefulSet adds stable identities and durable storage to each Pod. It’s the go-to for databases, message queues, or any service that needs a persistent disk and predictable network name (e.g. pod-0, pod-1, ...). StatefulSet Pods start and terminate in a strict order, guaranteeing data consistency across restarts.

1apiVersion: apps/v1
2kind: StatefulSet
3metadata:
4  name: my-stateful-app
5spec:
6  serviceName: "my-stateful-service"
7  replicas: 3
8  selector:
9    matchLabels:
10      app: my-app
11  template:
12    metadata:
13      labels:
14        app: my-app
15    spec:
16      containers:
17      - name: my-app-container
18        image: redis:latest
19        volumeMounts:
20        - name: my-app-storage
21          mountPath: /data
22  volumeClaimTemplates:
23  - metadata:
24      name: my-app-storage
25    spec:
26      accessModes: ["ReadWriteOnce"]
27      resources:
28        requests:
29          storage: 1Gi

Where StatefulSets guarantee one-to-one identity with storage, a DaemonSet guarantees one-to-one Pod distribution across nodes. Perfect for cluster-wide agents like log shippers or monitoring daemons—any time a node joins, the DaemonSet Controller schedules a new Pod there; when a node leaves, the Pod follows.

1apiVersion: apps/v1
2kind: DaemonSet
3metadata:
4  name: my-logging-agent
5spec:
6  selector:
7    matchLabels:
8      app: logging-agent
9  template:
10    metadata:
11      labels:
12        app: logging-agent
13    spec:
14      containers:
15      - name: my-logging-agent-container
16        image: fluentd:latest

Not all work is ongoing, though. Jobs handle finite, one-off tasks: database migrations, ETL processes, or batch imports. A Job creates Pods that run to completion, retrying until success or hitting a backoffLimit.

1apiVersion: batch/v1
2kind: Job
3metadata:
4  name: my-job
5spec:
6  template:
7    spec:
8      containers:
9      - name: my-job-container
10        image: busybox
11        command: ["echo", "Hello Kubernetes!"]
12      restartPolicy: Never
13  backoffLimit: 4

And when you need that batch to recur on a schedule—say nightly backups or weekly reports—you reach for a CronJob. It layers cron-style scheduling atop the Job controller, spinning up Jobs at your chosen times.

1apiVersion: batch/v1
2kind: CronJob
3metadata:
4  name: my-cronjob
5spec:
6  schedule: "0 0 * * *"
7  jobTemplate:
8    spec:
9      template:
10        spec:
11          containers:
12          - name: my-cronjob-container
13            image: busybox
14            command: ["echo", "Daily Backup"]
15          restartPolicy: OnFailure

In every case, the pattern is the same: you declare the desired state in YAML, Kubernetes controllers watch the cluster, and they act in a continuous control loop to reconcile reality with your specification. Understanding how Sets and Controllers pair up lets you choose the right abstraction for stateless services, stateful workloads, cluster-wide agents, one-off tasks, or scheduled jobs—giving you both flexibility and reliability in managing your applications.