Kubernetes Core Concepts

Deployments and ReplicaSets Explained Practically

A standalone Pod disappears when you delete it. A Deployment changes that model. Deployments tell Kubernetes how many copies of a workload should exist, how to update them, and how to recover when Pods fail.

What this lesson covers

In the Pods lesson, you created standalone Pods and saw that they do not come back after deletion. In this lesson, you move one level up and learn how Kubernetes keeps workloads running with Deployments and ReplicaSets.

By the end, you should understand:

  • What a Deployment is
  • What a ReplicaSet is
  • How Deployments create and manage Pods
  • Why standalone Pods are not normally used for production workloads
  • How to scale a Deployment
  • How Kubernetes replaces deleted Pods
  • How to update an image
  • How to check rollout status
  • How to roll back a bad change
  • How to clean up the lab resources
Field note: Pods are the workload unit, but Deployments are usually how you manage application workloads. The Deployment is what keeps the desired number of Pods running.

The short version

A Deployment is a Kubernetes object that manages application Pods.

You tell the Deployment what you want:

  • Which container image to run
  • How many copies should exist
  • Which labels identify the workload
  • How updates should roll out

Kubernetes then works to make the actual state match that desired state.

Deployment, ReplicaSet, and Pod relationship

The relationship looks like this:

Deployment
  controls ReplicaSet
    controls Pods
      run containers

You usually interact with the Deployment. The Deployment creates a ReplicaSet. The ReplicaSet creates and maintains the Pods.

What is a ReplicaSet?

A ReplicaSet makes sure a specified number of matching Pods are running.

For example, if a ReplicaSet expects three Pods and one Pod disappears, the ReplicaSet creates another Pod to bring the count back to three.

You usually do not create ReplicaSets directly. Deployments create and manage ReplicaSets for you.

Field note: Think of the Deployment as the object you manage and the ReplicaSet as the object Kubernetes uses underneath to maintain Pod count.

Before you start the lab

This lab assumes:

  • Docker Desktop is running
  • Your kind cluster exists
  • kubectl is installed
  • Your current context is kind-stealth-k8s-lab

Check your context:

kubectl config current-context

You should see:

kind-stealth-k8s-lab

Check your node:

kubectl get nodes

If your cluster no longer exists, recreate it:

kind create cluster --name stealth-k8s-lab

Step 1: Create a Deployment imperatively

Create a simple nginx Deployment:

kubectl create deployment nginx-deploy-lab --image=nginx:latest

This creates a Deployment named nginx-deploy-lab.

What this command does

  • Creates a Deployment object
  • Defines the container image as nginx:latest
  • Creates a ReplicaSet
  • Creates one Pod through that ReplicaSet

Step 2: Inspect the Deployment

Run:

kubectl get deployments

You should see something like:

NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy-lab   1/1     1            1           30s

What to look for

  • READY: How many desired Pods are ready.
  • UP-TO-DATE: How many Pods match the current Deployment spec.
  • AVAILABLE: How many Pods are available to serve traffic.
  • AGE: How long the Deployment has existed.

Step 3: Inspect the ReplicaSet

Run:

kubectl get replicasets

You should see a ReplicaSet with a name that starts with nginx-deploy-lab and ends with a generated suffix.

NAME                          DESIRED   CURRENT   READY   AGE
nginx-deploy-lab-xxxxxxxxxx    1         1         1       1m

That ReplicaSet was created by the Deployment.

Step 4: Inspect the Pod

Run:

kubectl get pods

You should see a Pod with a generated name.

NAME                                READY   STATUS    RESTARTS   AGE
nginx-deploy-lab-xxxxxxxxxx-yyyyy   1/1     Running   0          1m

The generated Pod name is a clue that this Pod is managed by higher-level Kubernetes objects.

Step 5: Describe the Deployment

Run:

kubectl describe deployment nginx-deploy-lab

Look for:

  • Labels
  • Selector
  • Replicas
  • Pod template
  • Container image
  • Events

The selector is important because it tells the Deployment which Pods belong to it.

Step 6: Scale the Deployment

Scale the Deployment to three replicas:

kubectl scale deployment nginx-deploy-lab --replicas=3

Check the Deployment:

kubectl get deployments

Check the Pods:

kubectl get pods

You should see three Pods for the same Deployment.

Field note: Scaling a Deployment changes the desired state. Kubernetes then creates or removes Pods until the actual state matches that desired state.

Step 7: Delete one Pod and watch it come back

Get the Pod names:

kubectl get pods

Delete one of the Pods. Replace <pod-name> with one actual Pod name:

kubectl delete pod <pod-name>

Immediately check Pods again:

kubectl get pods

You should see Kubernetes create a replacement Pod.

Why this happens

The Deployment still wants three replicas. The ReplicaSet sees that one Pod disappeared, so it creates another Pod to restore the desired count.

This is the key difference from a standalone Pod. A standalone Pod does not come back after deletion. A Pod managed by a Deployment does.

Step 8: View ownership

Pick one current Pod and describe it:

kubectl describe pod <pod-name>

Look for a line like:

Controlled By:  ReplicaSet/nginx-deploy-lab-xxxxxxxxxx

This tells you the Pod is controlled by a ReplicaSet, not manually managed by you.

Step 9: Scale back down

Scale the Deployment back to one replica:

kubectl scale deployment nginx-deploy-lab --replicas=1

Check Pods:

kubectl get pods

Kubernetes removes extra Pods until only one remains.

Step 10: Create a Deployment from YAML

Create a file named:

deployment-lab.yaml

Paste this into the file:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-yaml-deploy-lab
  labels:
    app: nginx-yaml-deploy-lab
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-yaml-deploy-lab
  template:
    metadata:
      labels:
        app: nginx-yaml-deploy-lab
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80

Apply it:

kubectl apply -f deployment-lab.yaml

Check the Deployment, ReplicaSet, and Pods:

kubectl get deployments
kubectl get replicasets
kubectl get pods

You should see the YAML-created Deployment running two Pods.

Step 11: Understand labels and selectors

In the YAML, this selector:

selector:
  matchLabels:
    app: nginx-yaml-deploy-lab

matches this Pod template label:

template:
  metadata:
    labels:
      app: nginx-yaml-deploy-lab

This relationship matters. The Deployment uses the selector to identify which Pods belong to it.

Field note: Selector and label mismatches are a common source of Kubernetes confusion. The controller needs a reliable way to know which Pods it owns.

Step 12: Update the Deployment image

Update the image from nginx:1.25 to nginx:1.27:

kubectl set image deployment/nginx-yaml-deploy-lab nginx=nginx:1.27

Watch the rollout:

kubectl rollout status deployment/nginx-yaml-deploy-lab

Check ReplicaSets:

kubectl get replicasets

You may see an older ReplicaSet and a newer ReplicaSet. Deployments use ReplicaSets to manage rollout history.

Step 13: Check rollout history

Run:

kubectl rollout history deployment/nginx-yaml-deploy-lab

This shows rollout revisions for the Deployment.

Step 14: Simulate a bad image update

Now intentionally set a bad image name:

kubectl set image deployment/nginx-yaml-deploy-lab nginx=nginx:badtag-lab

Check rollout status:

kubectl rollout status deployment/nginx-yaml-deploy-lab

This may wait because the new Pods cannot become healthy.

In another PowerShell window, inspect the Pods:

kubectl get pods
kubectl describe pod <pod-name>

You should see image pull errors such as ImagePullBackOff or ErrImagePull.

Step 15: Roll back the bad update

Undo the rollout:

kubectl rollout undo deployment/nginx-yaml-deploy-lab

Check rollout status:

kubectl rollout status deployment/nginx-yaml-deploy-lab

Check Pods:

kubectl get pods

Kubernetes should move back to the previous working version.

Field note: Rollbacks are one reason Deployments matter. They provide a safer way to change application versions than manually replacing Pods.

Step 16: View Deployment YAML

Run:

kubectl get deployment nginx-yaml-deploy-lab -o yaml

Again, do not try to memorize the whole output. Look for:

  • metadata
  • spec.replicas
  • spec.selector
  • spec.template
  • status

The Pod template inside the Deployment is the blueprint used to create Pods.

Step 17: Clean up

Delete the imperative Deployment:

kubectl delete deployment nginx-deploy-lab

Delete the YAML-created Deployment:

kubectl delete -f deployment-lab.yaml

Confirm cleanup:

kubectl get deployments
kubectl get replicasets
kubectl get pods

You should not see the lab Deployments or their Pods anymore.

Common Deployment troubleshooting commands

Use this flow when a Deployment does not look right:

kubectl get deployments
kubectl describe deployment <deployment-name>
kubectl get replicasets
kubectl get pods
kubectl get pods -o wide
kubectl describe pod <pod-name>
kubectl logs <pod-name>
kubectl rollout status deployment/<deployment-name>
kubectl rollout history deployment/<deployment-name>
kubectl get events --sort-by=.metadata.creationTimestamp

This usually tells you:

  • Whether the Deployment exists
  • How many replicas are desired
  • How many replicas are available
  • Whether Pods are being created
  • Whether images are pulling successfully
  • Whether containers are starting
  • Whether the rollout is stuck

What you just learned

In this lesson, you:

  • Created a Deployment
  • Inspected the Deployment, ReplicaSet, and Pods
  • Scaled a Deployment up and down
  • Deleted a Pod and watched Kubernetes replace it
  • Created a Deployment from YAML
  • Updated a Deployment image
  • Checked rollout status
  • Simulated a bad image update
  • Rolled back a failed change
  • Cleaned up the lab resources
Bottom line: A Deployment is the normal way to manage stateless application Pods. It gives Kubernetes enough information to create, replace, scale, update, and roll back workloads.

Check your understanding

Use these questions to test whether the Deployment and ReplicaSet concepts made sense.

  1. What does a Deployment manage?
  2. What does a ReplicaSet try to maintain?
  3. Do you usually create ReplicaSets directly?
  4. What happens when you delete a Pod managed by a Deployment?
  5. Why did the standalone Pod from the previous lesson not come back after deletion?
  6. What command scales a Deployment to three replicas?
  7. What is the relationship between labels and selectors?
  8. What part of a Deployment acts as the blueprint for Pods?
  9. What command checks rollout status?
  10. What status might you see when Kubernetes cannot pull a bad image tag?
  11. What command rolls back the previous Deployment change?
  12. Why are Deployments safer than manually replacing Pods?
Answer key
  1. A Deployment manages application Pods through ReplicaSets.
  2. A ReplicaSet tries to maintain the desired number of matching Pods.
  3. No. Deployments usually create and manage ReplicaSets for you.
  4. Kubernetes creates a replacement Pod to restore the desired replica count.
  5. Because no controller was managing it.
  6. kubectl scale deployment nginx-deploy-lab --replicas=3.
  7. Selectors identify resources by matching labels.
  8. spec.template, the Pod template.
  9. kubectl rollout status deployment/<deployment-name>.
  10. ImagePullBackOff or ErrImagePull.
  11. kubectl rollout undo deployment/<deployment-name>.
  12. They manage desired state, replacement, scaling, rollout history, and rollback behavior.
← Previous: Pods Series index Next: Services →