Skip to content
C Codeloom
DevOps

Kubernetes Pods vs Deployments

How Pods, ReplicaSets, and Deployments relate, why you almost never create Pods directly, and how rolling updates and rollbacks actually happen.

·5 min read · By Codeloom
Intermediate 10 min read

What you'll learn

  • What a Pod actually is in Kubernetes
  • How ReplicaSets sit between Pods and Deployments
  • How rolling updates and rollbacks happen
  • When to choose Deployments over StatefulSets or DaemonSets
  • Common Deployment misconfigurations to avoid

Prerequisites

  • Basic Kubernetes concepts

What and why

A Pod is the smallest deployable unit in Kubernetes: one or more containers that share network, storage, and a lifecycle. A Deployment is a higher-level controller that manages Pods through ReplicaSets, handling scaling, rolling updates, and rollbacks for you.

You almost never create Pods directly. A bare Pod has no self-healing: if the node it runs on dies, the Pod is gone. A Deployment ensures that the desired number of identical Pods is always running, replacing them when they fail, when nodes drain, or when you change the image.

Mental model

A Deployment owns ReplicaSets. A ReplicaSet owns Pods. When you change the Deployment’s pod template, it creates a new ReplicaSet, scales it up while scaling the old one down, and keeps the old one around for rollback.

apply Deployment v1
 |
 v
+----------------- Deployment: api -----------------+
|  ReplicaSet api-abc (v1, image=app:1.0)           |
|    Pod api-abc-1  Pod api-abc-2  Pod api-abc-3    |
+---------------------------------------------------+

kubectl set image deploy/api app=app:1.1
 |
 v
+----------------- Deployment: api -----------------+
|  ReplicaSet api-abc (v1, scaling down)            |
|    Pod api-abc-1                                  |
|  ReplicaSet api-def (v2, scaling up)              |
|    Pod api-def-1  Pod api-def-2                   |
+---------------------------------------------------+
 |
 v  rollout finishes
+----------------- Deployment: api -----------------+
|  ReplicaSet api-abc (v1, 0 pods, kept for undo)   |
|  ReplicaSet api-def (v2)                          |
|    Pod api-def-1  Pod api-def-2  Pod api-def-3    |
+---------------------------------------------------+
Deployment manages ReplicaSets which manage Pods

Hands-on example

A typical Deployment manifest:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: ghcr.io/acme/api:1.4.0
          ports:
            - containerPort: 8000
          readinessProbe:
            httpGet: { path: /healthz, port: 8000 }
            periodSeconds: 5
          livenessProbe:
            httpGet: { path: /healthz, port: 8000 }
            initialDelaySeconds: 10
          resources:
            requests: { cpu: 100m, memory: 128Mi }
            limits:   { cpu: 500m, memory: 256Mi }

Apply it:

kubectl apply -f api.yaml
kubectl rollout status deploy/api

When you bump the image to 1.5.0 and apply again, Kubernetes creates a new ReplicaSet, scales it up one Pod at a time (maxSurge: 1), and scales the old one down only after the new Pod’s readiness probe passes (maxUnavailable: 0). Zero downtime, controlled blast radius.

Roll back when something is wrong:

kubectl rollout undo deploy/api
kubectl rollout undo deploy/api --to-revision=3

The old ReplicaSet is still around because Kubernetes keeps revisionHistoryLimit (default 10) ReplicaSets per Deployment.

Bare Pods exist mostly for one-off debugging:

kubectl run debug --image=busybox --rm -it -- sh

That is appropriate for a transient shell. For anything that should survive, use a Deployment, Job, CronJob, or StatefulSet.

Common pitfalls

Missing readiness probes. Without one, Kubernetes considers a Pod ready as soon as the container is running, even if the application is still starting up. The rolling update declares the rollout complete and routes traffic to a Pod that returns 503.

Identical liveness and readiness probes. A failed liveness probe restarts the container; a failed readiness probe just stops routing traffic to it. Conflating the two can cause crash loops during transient slowness.

maxUnavailable: 25% (the default) on a 4-replica Deployment with stateful in-flight requests can drop one replica during deploys. For critical services, set maxUnavailable: 0.

Changing immutable fields. The Deployment’s selector cannot change after creation; if you need to, delete and recreate the Deployment.

Resource requests too low. Kubernetes schedules based on requests, not limits. Pods with no requests get scheduled anywhere and trampled when nodes fill up. Always set both requests and limits.

Production tips

Use kubectl rollout pause and kubectl rollout resume for canary-style validation between scaling steps.

Set progressDeadlineSeconds so the Deployment surfaces a failure if a rollout stalls. Without it, a broken image silently hangs.

spec:
  progressDeadlineSeconds: 600

Watch for ImagePullBackOff and CrashLoopBackOff early. kubectl describe pod shows events; kubectl logs --previous shows the prior container’s logs.

For applications that need stable identities or ordered startup (databases, brokers), use a StatefulSet, not a Deployment. For one-pod-per-node agents (log shippers, metric exporters), use a DaemonSet.

Pair Deployments with a HorizontalPodAutoscaler to scale on CPU, memory, or custom metrics. A single Deployment plus an HPA covers most stateless workloads.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: api }
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource: { name: cpu, target: { type: Utilization, averageUtilization: 60 } }

Wrap-up

A Pod is a runnable unit; a Deployment is the controller that keeps the right number of Pods alive and rolls them over safely. Always run Pods via a higher-level controller, set readiness probes that match reality, configure conservative rolling update parameters, and pair with HPAs for elasticity. Bare Pods are for debug shells; Deployments are for everything else stateless.