Back to Kubernetes: Core Concepts
Q14Question 14 of 16

Pod, Deployment, ReplicaSet, StatefulSet, DaemonSet, and Job: The Differences

Key Concepts
  • A Pod is the smallest deployable unit in Kubernetes, wrapping one or more tightly-coupled containers that share a network namespace and volumes.
  • A ReplicaSet ensures a specified number of identical Pod replicas are always running, but you rarely create one directly.
  • A Deployment manages ReplicaSets to provide declarative rolling updates and instant rollbacks for stateless services.
  • A StatefulSet gives each Pod a stable ordinal name, a stable network identity, and its own persistent volume for stateful workloads like databases.
  • A DaemonSet ensures exactly one Pod runs on every matching node, used for node-level agents like log collectors and metrics exporters.
  • A Job runs Pods to successful completion for a finite task, and a CronJob schedules Jobs on a recurring basis.

Definition

Pod is the unit, ReplicaSet keeps N copies, Deployment adds rolling updates for stateless apps, StatefulSet gives stable identity and storage for stateful apps, DaemonSet runs one per node, and Job runs a finite task to completion.

These are Kubernetes workload objects at increasing levels of management.

  • Pod – the smallest deployable unit, one or more tightly-coupled containers sharing a network namespace and optional volumes, but ephemeral and not self-healing on its own.
  • ReplicaSet – ensures a specified number of identical Pod replicas are always running, recreating any that die.
  • Deployment – manages ReplicaSets to provide declarative rolling updates and rollbacks for stateless applications, and is the object you normally use.
  • StatefulSet – manages Pods that need a stable ordinal name, a stable network identity via a headless Service, and per-Pod persistent storage for stateful workloads.
  • DaemonSet – ensures exactly one copy of a Pod runs on every matching node, for node-level infrastructure agents.
  • Job / CronJob – Job runs Pods to successful completion for a finite task with retries; CronJob wraps a Job with a schedule.

Think of staffing at the National Bank of India. A Pod is a single teller doing a job, but if they quit nobody automatically replaces them. A ReplicaSet is a rule saying always keep exactly five tellers on duty, hiring a replacement the moment one leaves. A Deployment is the HR manager who not only keeps five tellers but can smoothly roll in a newly-trained batch and roll back if the new training was bad. A StatefulSet is for named specialists who each own a specific locked drawer and must keep the same desk and drawer even after a break. A DaemonSet is the rule that every branch must have exactly one security guard. A Job is a one-off task like run the end-of-day reconciliation until it finishes successfully.

Understanding the Concepts

What is a Pod?

A Pod is the smallest deployable unit in Kubernetes. It wraps one or more containers that share the same network namespace, meaning the same IP address and port space, and can share volumes. All containers in a Pod are co-scheduled on the same node and act as a single unit.

You rarely create bare Pods in production because a bare Pod is not replaced if its node dies. It has no controller watching over it. Pods are ephemeral by design and get a new IP each time they are recreated.

YAML
# bare-pod.yaml - a Pod with no controller (not recommended for production)
apiVersion: v1
kind: Pod
metadata:
  name: transfer-service
  labels:
    app: transfer-service
spec:
  containers:
    - name: transfer
      image: nbi-registry.example.com/transfer-service:1.0.0
      ports:
        - containerPort: 8080
BASH
kubectl apply -f bare-pod.yaml
kubectl get pods
# If the node dies, this Pod is gone forever

What is a ReplicaSet?

A ReplicaSet ensures a specified number of identical Pod replicas exist at all times. If a Pod dies, the ReplicaSet creates a replacement. You normally do not create ReplicaSets directly because they do not handle updates gracefully, but they are the mechanism a Deployment uses under the hood.

YAML
# replicaset.yaml - keeps 3 transfer-service Pods running
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: transfer-service-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: transfer-service
  template:
    metadata:
      labels:
        app: transfer-service
    spec:
      containers:
        - name: transfer
          image: nbi-registry.example.com/transfer-service:1.0.0
          ports:
            - containerPort: 8080
BASH
kubectl apply -f replicaset.yaml
kubectl get rs
# Delete one Pod and watch the ReplicaSet recreate it
kubectl delete pod transfer-service-rs-abc12
kubectl get pods   # back to 3 within seconds

What is a Deployment?

A Deployment is the standard object for stateless services. It manages ReplicaSets to give declarative rolling updates. When you change the image tag, the Deployment creates a new ReplicaSet and scales it up while scaling the old one down. It keeps the old ReplicaSet so you can roll back instantly.

YAML
# deployment.yaml - the standard way to run a stateless banking API
apiVersion: apps/v1
kind: Deployment
metadata:
  name: transfer-service
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: transfer-service
  template:
    metadata:
      labels:
        app: transfer-service
    spec:
      containers:
        - name: transfer
          image: nbi-registry.example.com/transfer-service:2.0.0
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: 500m
              memory: 512Mi
            limits:
              cpu: "1"
              memory: 512Mi
BASH
# Update the image to trigger a rolling update
kubectl set image deployment/transfer-service \
  transfer=nbi-registry.example.com/transfer-service:2.1.0

# Watch the rollout progress
kubectl rollout status deployment/transfer-service

# Roll back to the previous revision if the new version is broken
kubectl rollout undo deployment/transfer-service

What is a StatefulSet?

A StatefulSet is for workloads that need identity and storage stability. Each Pod gets a stable ordinal name like ledger-db-0, ledger-db-1, a stable network identity via a headless Service, and its own PersistentVolumeClaim that stays bound to that specific Pod. Pods are created, scaled, and terminated in a predictable order.

YAML
# statefulset.yaml - a clustered database for the banking ledger
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: ledger-db
spec:
  serviceName: ledger-db-headless
  replicas: 3
  selector:
    matchLabels:
      app: ledger-db
  template:
    metadata:
      labels:
        app: ledger-db
    spec:
      containers:
        - name: postgres
          image: postgres:16
          ports:
            - containerPort: 5432
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 100Gi
BASH
kubectl get pods
# NAME          READY   STATUS
# ledger-db-0   1/1     Running
# ledger-db-1   1/1     Running
# ledger-db-2   1/1     Running
# Each Pod owns its own PVC: data-ledger-db-0, data-ledger-db-1, data-ledger-db-2

How is a Deployment different from a StatefulSet?

This is the most common comparison in interviews. The core difference is whether replicas are interchangeable.

| Aspect | Deployment | StatefulSet |
|---|---|---|
| Pod names | Random suffix (e.g. abc12) | Stable ordinal (e.g. db-0, db-1) |
| Pod identity | Interchangeable | Unique and persistent |
| Storage | Shared or none | Per-Pod PersistentVolumeClaim |
| Scaling order | Parallel (all at once) | Sequential (0, 1, 2...) |
| Network identity | Via Service ClusterIP | Stable DNS per Pod via headless Service |
| Use case | Stateless APIs | Databases, message brokers |

BASH
# WRONG - running a database as a Deployment
# Pods are interchangeable, so replication state breaks
kubectl get pods -l app=ledger-db
# NAME                         READY   STATUS
# ledger-db-6d4f9c7b8a-x9k2m  1/1     Running   <- random name, no stable storage

# CORRECT - running a database as a StatefulSet
kubectl get pods -l app=ledger-db
# NAME          READY   STATUS
# ledger-db-0   1/1     Running   <- stable name, owns data-ledger-db-0 PVC
# ledger-db-1   1/1     Running   <- stable name, owns data-ledger-db-1 PVC

What is a DaemonSet?

A DaemonSet ensures one Pod per node. As nodes join or leave the cluster, the DaemonSet automatically adds or removes its Pod. This is for node-level infrastructure such as log collectors, metrics agents, or network plugins.

YAML
# daemonset.yaml - a log collector on every node
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: log-collector
spec:
  selector:
    matchLabels:
      app: log-collector
  template:
    metadata:
      labels:
        app: log-collector
    spec:
      containers:
        - name: fluentbit
          image: fluent/fluent-bit:2.2
          volumeMounts:
            - name: varlog
              mountPath: /var/log
              readOnly: true
      volumes:
        - name: varlog
          hostPath:
            path: /var/log
BASH
kubectl get ds
# NAME             DESIRED   CURRENT   READY
# log-collector    5         5         5     <- one per node in a 5-node cluster

# Add a new node and the DaemonSet automatically schedules a Pod on it

What is a Job and a CronJob?

A Job runs one or more Pods to successful completion for a finite task. It retries on failure up to a backoff limit. A CronJob wraps a Job with a cron schedule.

YAML
# job.yaml - nightly end-of-day reconciliation
apiVersion: batch/v1
kind: Job
metadata:
  name: eod-reconciliation
spec:
  backoffLimit: 3
  completions: 1
  template:
    spec:
      containers:
        - name: reconciler
          image: nbi-registry.example.com/eod-reconciler:1.0.0
          env:
            - name: RECONCILIATION_DATE
              value: "2025-01-15"
      restartPolicy: Never
YAML
# cronjob.yaml - schedule the reconciliation every night at 11:30 PM
apiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly-reconciliation
spec:
  schedule: "30 23 * * *"
  jobTemplate:
    spec:
      backoffLimit: 3
      template:
        spec:
          containers:
            - name: reconciler
              image: nbi-registry.example.com/eod-reconciler:1.0.0
          restartPolicy: Never
BASH
kubectl get jobs
# NAME                 COMPLETIONS   DURATION
# eod-reconciliation   1/1           45s

kubectl get cronjobs
# NAME                      SCHEDULE       LAST SCHEDULE
# nightly-reconciliation    30 23 * * *    2m ago

What are common mistakes?

The most frequent mistake is using a Deployment for a database. A Deployment treats all replicas as interchangeable and does not provide stable names or per-Pod storage, so database replication state breaks when Pods are replaced.

YAML
# WRONG - database as a Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ledger-db
spec:
  replicas: 3
  template:
    spec:
      containers:
        - name: postgres
          image: postgres:16
          # No stable identity, no per-Pod volume
          # Replication state corrupts on Pod replacement
YAML
# CORRECT - database as a StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: ledger-db
spec:
  serviceName: ledger-db-headless
  replicas: 3
  template:
    spec:
      containers:
        - name: postgres
          image: postgres:16
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 100Gi

Another mistake is not making Job tasks idempotent. A Job Pod can be retried, and for financial batch work an accidentally-double-run reconciliation is dangerous. Always design the task so running it twice produces the same result.

When should you use each workload object?

The decision is based on the nature of the workload.

  • Deployment for stateless services where any replica is interchangeable: the Transfer API, the Loan Calculator, the API Gateway.
  • StatefulSet for stateful workloads that need stable identity and per-Pod storage: a clustered Postgres database, a Kafka broker, a Redis cluster.
  • DaemonSet for node-level agents that must run on every node: Fluent Bit for logs, Prometheus Node Exporter for metrics, a CNI plugin.
  • Job for one-off finite tasks: a database migration, an end-of-day reconciliation, a data export.
  • CronJob for scheduled finite tasks: nightly interest accrual, weekly report generation, daily backup.
BASH
# Quick summary of what is running in the banking namespace
kubectl get deployments,statefulsets,daemonsets,jobs,cronjobs -n banking

What should a senior engineer know?

A senior engineer should understand that even StatefulSets in banking are often avoided for the primary ledger in favour of a managed database service like Amazon RDS, keeping stateful risk out of the cluster. Running a database in Kubernetes is operationally complex, so many teams use StatefulSets only for workloads like Kafka or Redis where the operational tooling is mature.

Job semantics must be set carefully. The backoffLimit controls retries, completions controls how many Pods must succeed, and parallelism controls how many run at once. For financial batch work, the task must be idempotent because retries mean the code runs more than once.

DaemonSets respect taints and tolerations, so a DaemonSet can be scoped to a subset of nodes using a node selector or toleration rather than running on every single node.

BASH
# Check the QoS and controller of each Pod
kubectl get pods -o custom-columns=NAME:.metadata.name,CONTROLLER:.metadata.ownerReferences[0].kind,QOS:.status.qosClass

Visual Overview

DIAGRAM
  Kubernetes Workload Object Hierarchy
  =====================================

  ┌─────────────────────────────────────────────────┐
  │                  Deployment                      │
  │  (manages rolling updates and rollbacks)         │
  │                                                  │
  │  ┌───────────────────┐  ┌───────────────────┐   │
  │  │  ReplicaSet v2    │  │  ReplicaSet v1    │   │
  │  │  (current)        │  │  (previous)       │   │
  │  │  ┌─────┐ ┌─────┐ │  │  (scaled to 0)    │   │
  │  │  │Pod A│ │Pod B│ │  │                    │   │
  │  │  └─────┘ └─────┘ │  └───────────────────┘   │
  │  └───────────────────┘                           │
  └─────────────────────────────────────────────────┘

  ┌─────────────────────────────────────────────────┐
  │                StatefulSet                       │
  │  (stable names, ordered, per-Pod PVCs)           │
  │                                                  │
  │  ┌──────────┐  ┌──────────┐  ┌──────────┐      │
  │  │ db-0     │  │ db-1     │  │ db-2     │      │
  │  │ PVC: d-0 │  │ PVC: d-1 │  │ PVC: d-2 │      │
  │  └──────────┘  └──────────┘  └──────────┘      │
  └─────────────────────────────────────────────────┘

  ┌─────────────────────────────────────────────────┐
  │                  DaemonSet                       │
  │  (one Pod per node)                              │
  │                                                  │
  │  Node-1: [log-collector]                         │
  │  Node-2: [log-collector]                         │
  │  Node-3: [log-collector]                         │
  └─────────────────────────────────────────────────┘

  ┌─────────────────────────────────────────────────┐
  │               CronJob → Job                      │
  │  (schedule triggers a Job, Job runs Pods)        │
  │                                                  │
  │  CronJob: 30 23 * * *                            │
  │    └─→ Job: eod-reconciliation-28456             │
  │          └─→ Pod: eod-reconciliation-28456-xk9   │
  │               status: Completed                  │
  └─────────────────────────────────────────────────┘

Key Takeaway

These six workload objects sit at increasing levels of management, and the key skill is picking the right one for the nature of the workload. A Pod is the smallest unit, but it is ephemeral and not self-healing, so you rarely run bare Pods. A ReplicaSet keeps a specified number of replicas alive, but it does not handle updates, so you use a Deployment instead. A Deployment manages ReplicaSets to give rolling updates and instant rollback, and it is the standard choice for any stateless service where replicas are interchangeable, like the Transfer API at the National Bank of India.

A StatefulSet is for workloads that need stability. Each Pod gets a stable ordinal name, a stable DNS identity through a headless Service, and its own PersistentVolumeClaim that stays bound across restarts and reschedules. That is what a clustered database or a Kafka broker needs. A DaemonSet ensures one Pod per node for infrastructure agents like log collectors and metrics exporters. A Job runs a finite task to completion with retries, and a CronJob schedules Jobs on a recurring basis for batch work like nightly reconciliation.

The classic mistake is running a database as a Deployment. The interchangeable, unordered Pods break replication state, so databases belong in a StatefulSet or a managed external service. For Job-based financial batch work, the task must be idempotent because retries mean the code can run more than once.

Remember one sentence: use a Deployment for stateless services, a StatefulSet for stateful workloads that need identity and storage, a DaemonSet for one-per-node agents, and a Job for finite tasks.

---

Share
Use ← → arrow keys to navigate