Skip to content

Intermediate · Kubernetes fundamentals · topic 21 of 53 · 35 min

Pods, ReplicaSets and Deployments

Explanation

A Pod is the smallest thing Kubernetes runs: one or more containers that share an IP address and storage. Pods are temporary, so you run them through a Deployment, which keeps the right number of copies alive using a ReplicaSet. A Deployment updates your app gradually with a rolling update, and kubectl rollout lets you watch, inspect and undo it.

Pods: the smallest unit

A Pod is a wrapper around one or more containers that always run together on the same node. The containers in a pod share one network identity (one IP address, so they can talk to each other on localhost) and can share storage volumes. Most pods have one main container. Sometimes a helper container runs next to it, called a sidecar, for example to ship logs or act as a network proxy.

Pods are ephemeral, which means temporary. If a node dies, its pods are gone; they are not moved. A new pod is created elsewhere with a new name and a new IP. So you should never depend on a pod's name or IP, and you should almost never create bare pods for an app. Let a controller such as a Deployment create them.

yaml
apiVersion: v1
kind: Pod
metadata:
  name: hello
  labels:
    app: hello
spec:
  containers:
    - name: web
      image: nginx:1.27
      ports:
        - containerPort: 80
A single pod. Fine for a quick test, but nothing restarts it on another node if its node dies.

Labels and selectors

Labels are key-value tags you stick on objects, such as app: payments-api, tier: backend or env: prod. A selector is a query that picks objects by their labels. This is how Kubernetes objects find each other: a Deployment finds its pods by label, and a Service finds the pods to send traffic to by label. You can use them too: kubectl get pods -l app=payments-api.

ReplicaSets and Deployments

A ReplicaSet keeps a set number of identical pods running. A Deployment sits on top: it creates and manages ReplicaSets, and adds rolling updates and a history you can roll back to. In practice you write Deployments and let them handle ReplicaSets for you.

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payments-api
  namespace: payments
  labels:
    app: payments-api
spec:
  replicas: 4
  selector:
    matchLabels:
      app: payments-api          # must match the template labels below
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25%               # up to 1 extra pod during an update (25% of 4)
      maxUnavailable: 25%         # at most 1 pod below 4 during an update
  template:                       # the blueprint for every pod
    metadata:
      labels:
        app: payments-api
    spec:
      containers:
        - name: api
          image: registry.example.com/payments-api:1.4.2
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              memory: 512Mi
          readinessProbe:
            httpGet:
              path: /ready
              port: 8080
A complete Deployment. apps/v1 is the API group and version; template is the pod that gets copied replicas times.

Rolling updates

When you change the pod template, for example a new image tag, the Deployment creates a new ReplicaSet and moves pods over a few at a time: start some new pods, wait until they are ready, stop some old ones, repeat. Users keep being served throughout. Two settings control the speed and safety:

  • maxSurge: how many pods above the desired replicas may exist during the update. A percentage is rounded up.
  • maxUnavailable: how many pods below the desired replicas may be unavailable. A percentage is rounded down.
  • Both default to 25%. They cannot both be 0, or the update could never make progress.

Worked example: replicas is 10 with the defaults. Surge is 25% of 10 = 2.5, rounded up to 3, so at most 13 pods exist. Unavailable is 2.5 rounded down to 2, so at least 8 pods stay available. With replicas 4 you get at most 5 pods and at least 3 available.

The other strategy is Recreate: stop all old pods first, then start the new ones. It causes downtime, but it is needed when two versions must never run at the same time, for example when the app takes an exclusive lock on a file or database.

bash
kubectl apply -f deployment.yaml                    # after changing the image tag in the file
kubectl rollout status deployment/payments-api -n payments    # wait and watch
kubectl rollout history deployment/payments-api -n payments   # list revisions
kubectl rollout undo deployment/payments-api -n payments      # back to the previous revision
kubectl rollout undo deployment/payments-api -n payments --to-revision=3
kubectl scale deployment/payments-api -n payments --replicas=8
kubectl rollout works on Deployments, DaemonSets and StatefulSets.

Scaling automatically

kubectl scale changes replicas by hand. A HorizontalPodAutoscaler (HPA) changes them for you, for example to keep average CPU use near 70% of the requested CPU, between a minimum and a maximum. The HPA needs a metrics source, usually metrics-server, installed in the cluster.

yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: payments-api
  namespace: payments
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: payments-api
  minReplicas: 4
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

Pod statuses and how to debug them

The STATUS column of kubectl get pods shows either the pod phase (Pending, Running, Succeeded, Failed) or, when a container is stuck, the reason it is waiting, such as CrashLoopBackOff.

StatusWhat it meansFirst thing to check
PendingAccepted but not running yet: no node has enough free CPU or memory, or a volume is not readykubectl describe pod: read the Events
RunningBound to a node and at least one container is runningIs it Ready? Check the READY column
SucceededAll containers finished with exit code 0 (typical for Jobs)Nothing, it worked
FailedContainers ended with an error and will not be restartedkubectl logs
CrashLoopBackOffThe container starts, crashes, and is restarted with longer and longer waitskubectl logs <pod> --previous
ImagePullBackOff / ErrImagePullThe node cannot download the image: wrong name or tag, or a private registry without credentialskubectl describe pod: the Events show the pull error
bash
kubectl get pods -n payments
kubectl describe pod payments-api-6c9f-zt4qp -n payments    # Events at the bottom
kubectl logs payments-api-6c9f-zt4qp -n payments --previous # output of the crashed run
kubectl get events -n payments --sort-by=.metadata.creationTimestamp
describe, logs, logs --previous and events solve most pod problems.
Careful: Common mistakes. (1) The selector does not match the template labels: the API server rejects the Deployment, so copy the labels exactly. (2) Using the :latest tag: you cannot tell which version is running, and re-applying the same YAML does not trigger a rollout. Use a version or git SHA tag. (3) Reading kubectl logs of a CrashLoopBackOff pod and seeing nothing: the useful output is from the previous crashed run, so add --previous. (4) Fixing production with kubectl rollout undo and forgetting to fix the YAML in Git, so the next deploy brings the bug back.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Pods, ReplicaSets and Deployments · 1/8

Pods and Deployments

In this lesson you will learn how Kubernetes runs your app: pods, ReplicaSets and Deployments.

Prefer a video by a teacher? Find free videos on “kubernetes pods deployments rolling update tutorial” on YouTube ↗

In real life: Updating a UPI payments API without downtime

A payments company runs its UPI collect API as a Deployment with 10 replicas and the default 25% rolling update settings. On Tuesday at 11 am, the CI pipeline changes the image tag from 3.8.1 to 3.8.2 and applies the Deployment. Kubernetes starts 3 new pods (surge) while at most 2 old ones are taken away, so at least 8 pods serve traffic at all times. A new pod receives traffic only when its readiness probe passes. Ten minutes later the error rate rises, so the on-call engineer runs kubectl rollout undo, and the old ReplicaSet scales back up in under a minute.

bash
kubectl rollout status deployment/upi-collect -n payments
# Waiting for deployment "upi-collect" rollout to finish: 6 of 10 updated replicas are available...
# deployment "upi-collect" successfully rolled out
kubectl rollout undo deployment/upi-collect -n payments
Watching the rollout, then rolling back.

Practice (0/3 done)

Task 1 · Question

A pod shows CrashLoopBackOff and kubectl logs prints nothing useful. What should you run next?

Task 2 · Code · Python

Write rolling_bounds(replicas, max_surge, max_unavailable). Each setting is either a whole number (like 1) or a percentage string (like "25%"). Turn percentages into pod counts the way Kubernetes does: surge rounds UP, unavailable rounds DOWN. Return a tuple (min_available, max_total): the fewest pods that must stay available and the most pods that may exist during the update.

Task 3 · Practice

Write a Deployment YAML for a college results website: image registry.example.com/results-web:2.1.0, 3 replicas, container port 3000, label app: results-web, a rolling update that never drops below 3 available pods, and a CPU request of 100m with a memory request and limit of 128Mi and 256Mi.

Quick quiz

Question 1

1.What do containers in the same pod share?

Question 2

2.What are the default maxSurge and maxUnavailable of a Deployment?

Question 3

3.Which strategy stops all old pods before starting new ones?

Question 4

4.A pod stays Pending and its events say "0/3 nodes are available: insufficient memory". What is the cause?

Question 5

5.How does a Deployment know which pods belong to it?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What do containers in the same pod share?

Answer: A network identity (one IP) and optionally volumes

Containers in a pod share the network namespace, so they reach each other on localhost, and can mount the same volumes.

What are the default maxSurge and maxUnavailable of a Deployment?

Answer: 25% and 25%

Both default to 25%. Surge is rounded up, unavailable is rounded down.

Which strategy stops all old pods before starting new ones?

Answer: Recreate

Recreate causes a short outage but guarantees that two versions never run together.

A pod stays Pending and its events say "0/3 nodes are available: insufficient memory". What is the cause?

Answer: No node has enough free memory for the pod's memory request

The scheduler cannot find a node with room for the request. Lower the request, free capacity, or add nodes.

How does a Deployment know which pods belong to it?

Answer: By its label selector

spec.selector.matchLabels picks the pods; the template must carry the same labels.

A Deployment wants 3 replicas. You delete one of its pods by hand. What happens?Related

Answer: A new pod is created to get back to 3

The ReplicaSet controller sees 2 of 3 and creates a replacement. That is self-healing.

From Why Kubernetes, and how a cluster works

You changed a ConfigMap that a Deployment reads with envFrom. Why do the pods still see the old values?Related

Answer: Environment variables are read when the container starts, so the pods must be restarted

Run kubectl rollout restart deployment/<name> to start fresh pods with the new values.

From Namespaces, ConfigMaps, Secrets, resources and probes

Which object replaced PodSecurityPolicy (removed in Kubernetes 1.25) for enforcing Pod Security Standards?Related

Answer: Pod Security Admission, configured with namespace labels

The built-in Pod Security Admission controller enforces privileged, baseline or restricted per namespace.

From Kubernetes security

In Kubernetes, which part picks a node for each new pod?Related

Answer: The scheduler in the control plane

The scheduler is a control plane component that assigns pods to nodes.

From Managed Kubernetes: EKS, AKS and GKE

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 3 more topics in “Kubernetes fundamentals” before its exam: Services, Ingress and the Gateway API, Namespaces, ConfigMaps, Secrets, resources and probes, Helm and Kustomize.
  2. Module 5 exam: Kubernetes fundamentals · 13 questions · 20 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, CI/CD pipelines. 53 topics left in the course before the final exam.

← Previous: Why Kubernetes, and how a cluster works