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
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.
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.
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.
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.
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
Check your understanding
Use these questions to test whether the Deployment and ReplicaSet concepts made sense.
- What does a Deployment manage?
- What does a ReplicaSet try to maintain?
- Do you usually create ReplicaSets directly?
- What happens when you delete a Pod managed by a Deployment?
- Why did the standalone Pod from the previous lesson not come back after deletion?
- What command scales a Deployment to three replicas?
- What is the relationship between labels and selectors?
- What part of a Deployment acts as the blueprint for Pods?
- What command checks rollout status?
- What status might you see when Kubernetes cannot pull a bad image tag?
- What command rolls back the previous Deployment change?
- Why are Deployments safer than manually replacing Pods?
Answer key
- A Deployment manages application Pods through ReplicaSets.
- A ReplicaSet tries to maintain the desired number of matching Pods.
- No. Deployments usually create and manage ReplicaSets for you.
- Kubernetes creates a replacement Pod to restore the desired replica count.
- Because no controller was managing it.
- kubectl scale deployment nginx-deploy-lab --replicas=3.
- Selectors identify resources by matching labels.
- spec.template, the Pod template.
- kubectl rollout status deployment/<deployment-name>.
- ImagePullBackOff or ErrImagePull.
- kubectl rollout undo deployment/<deployment-name>.
- They manage desired state, replacement, scaling, rollout history, and rollback behavior.