03-Deployment-concepts-with-real-examples
Understand core Kubernetes building blocks — Deployment — with real-world examples, YAML manifests, and hands-on troubleshooting scenarios.
3.1 What Is a Deployment?
A Deployment is the recommended and most commonly used way to manage stateless applications in Kubernetes. It wraps a ReplicaSet and adds two critical capabilities:
- Rolling Updates — Update your application to a new version with zero downtime by gradually replacing old pods with new ones
- Rollback — If the new version has issues, instantly roll back to the previous working version
When you create or update a Deployment, here is the relationship:
Deployment
└── ReplicaSet v1 (old — scaled to 0 after update)
└── ReplicaSet v2 (new — scaled to desired replicas)
└── Pod 1
└── Pod 2
└── Pod 3
Every time you update a Deployment (e.g., change the image), Kubernetes creates a new ReplicaSet for the new version and gradually shifts traffic from the old ReplicaSet to the new one. The old ReplicaSet is kept around (with 0 replicas) to enable rollbacks.
3.2 Why Is a Deployment Used?
| Feature | Why It Matters |
|---|---|
| Rolling updates | Update your app image with zero downtime — old pods are only removed after new ones are healthy |
| Rollback | One command to revert to any previous version if something goes wrong in production |
| Self-healing | Inherits all ReplicaSet self-healing behaviour |
| Scaling | Easily scale replicas up or down |
| Revision history | Kubernetes tracks every change to the Deployment spec |
| Pause and Resume | Pause a rollout, make multiple changes, then resume |
| Update strategies | Choose between RollingUpdate (zero downtime) or Recreate (all-at-once) |
3.3 Where Is a Deployment Used?
Deployments are used for stateless applications — meaning each pod is identical and holds no unique state:
- Web applications — React frontends, Node.js APIs, Django, Flask
- REST APIs and microservices — any service behind a load balancer
- Background workers — workers consuming from Kafka, SQS, RabbitMQ
- Internal tooling — dashboards, admin panels
- Proxy/gateway layers — Nginx, Envoy, Kong API gateway
Not suitable for: Stateful applications (databases, Kafka brokers, Elasticsearch) — use StatefulSet for those, as each pod needs a stable identity and dedicated storage.
3.4 Deployment YAML Manifest — Full Breakdown
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
labels:
app: nginx
team: platform
annotations:
kubernetes.io/change-cause: "Initial deployment — nginx:1.25" # shows in rollout history
spec:
replicas: 3 # Run 3 pod replicas at all times
selector:
matchLabels:
app: nginx # Deployment manages pods with this label
strategy:
type: RollingUpdate # Default strategy — zero downtime updates
rollingUpdate:
maxSurge: 1 # Allow 1 extra pod above replicas during update (4 total)
maxUnavailable: 0 # Never allow pods to go below desired count (0 downtime)
minReadySeconds: 10 # Wait 10s after a new pod becomes ready before proceeding
revisionHistoryLimit: 5 # Keep 5 old ReplicaSets for rollback (default is 10)
progressDeadlineSeconds: 600 # Mark deployment as failed if not complete in 10 minutes
template: # Pod template
metadata:
labels:
app: nginx # MUST match selector.matchLabels
version: "1.25"
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
name: http
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
env:
- name: APP_ENV
value: "production"
- name: DB_HOST
valueFrom:
secretKeyRef: # Pull value from a Kubernetes Secret
name: db-secret
key: host
livenessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 15
periodSeconds: 20
failureThreshold: 3 # Restart container after 3 consecutive failures
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
terminationGracePeriodSeconds: 30 # Give pod 30s to finish in-flight requests on shutdown
3.5 Rolling Update Strategies Explained
Kubernetes supports two update strategies:
Strategy 1: RollingUpdate (Default — Recommended)
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # How many extra pods can exist during the update
maxUnavailable: 0 # How many pods can be unavailable during the update
Visual of a rolling update from v1 to v2 with 3 replicas:
Start: [v1] [v1] [v1] (3 running)
Step 1: [v1] [v1] [v1] [v2] (4 running — maxSurge=1)
Step 2: [v1] [v1] [v2] (v2 ready, one v1 terminated)
Step 3: [v1] [v1] [v2] [v2] (4 running)
Step 4: [v1] [v2] [v2] (another v1 terminated)
Step 5: [v1] [v2] [v2] [v2] (4 running)
Done: [v2] [v2] [v2] (all v2, v1 fully removed)
Strategy 2: Recreate
strategy:
type: Recreate
All old pods are terminated first, then new pods are created. This causes downtime but is simpler and required when your app cannot run two versions simultaneously (e.g., a breaking database schema migration):
Start: [v1] [v1] [v1]
Step 1: [ ] [ ] [ ] (all v1 terminated — DOWNTIME HERE)
Step 2: [v2] [v2] [v2] (all v2 created)
Done: [v2] [v2] [v2]
3.6 Essential Deployment Commands
# Create or update a deployment
kubectl apply -f nginx-deployment.yaml
# List all deployments
kubectl get deployments
kubectl get deploy # short form
kubectl get deploy -o wide # shows image, selector, containers
# Describe a deployment (shows strategy, events, replica status)
kubectl describe deployment nginx-deployment
# Watch rollout progress in real time
kubectl rollout status deployment/nginx-deployment
# View rollout history (all revisions)
kubectl rollout history deployment/nginx-deployment
# View details of a specific revision
kubectl rollout history deployment/nginx-deployment --revision=3
# Perform an image update (triggers a new rollout)
kubectl set image deployment/nginx-deployment nginx=nginx:1.26
# Scale up / down
kubectl scale deployment nginx-deployment --replicas=5
# Rollback to previous version
kubectl rollout undo deployment/nginx-deployment
# Rollback to a specific revision
kubectl rollout undo deployment/nginx-deployment --to-revision=2
# Pause a deployment (stop ongoing rollout)
kubectl rollout pause deployment/nginx-deployment
# Resume a paused deployment
kubectl rollout resume deployment/nginx-deployment
# Delete a deployment (also deletes the ReplicaSets and Pods it owns)
kubectl delete deployment nginx-deployment
# Edit a live deployment
kubectl edit deployment nginx-deployment
# Rolling restart all pods without changing the spec
kubectl rollout restart deployment/nginx-deployment
3.7 Real-World Troubleshooting — Deployment
Scenario 1: Rollout stuck — pods not becoming ready after an image update
Situation: You pushed a new image version (nginx:1.26) but the rollout never completes.
$ kubectl rollout status deployment/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Step 1 — Describe the deployment:
kubectl describe deployment nginx-deployment
Output includes:
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
Events:
Warning FailedCreate 2m replicaset-controller
Error creating: pods is forbidden: exceeded quota: requests.memory
Root Cause: A ResourceQuota is preventing the new ReplicaSet from creating pods because the namespace is at its memory request limit.
Fix:
# Check the quota
kubectl describe resourcequota -n default
# Either increase the quota or reduce resource requests in the deployment
kubectl edit resourcequota default-quota -n default
# Or reduce the deployment memory request
kubectl edit deployment nginx-deployment
# Change requests.memory from "256Mi" to "128Mi"
Scenario 2: New pods created but readiness probe keeps failing
Situation: After updating to myapp:v2, the rollout is stuck because new pods never become Ready.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-abc123-zxcvb 1/1 Running 0 20m # old pod v1
nginx-deployment-def456-qwert 0/1 Running 0 5m # new pod v2 — not ready
nginx-deployment-def456-asdfg 0/1 Running 0 5m # new pod v2 — not ready
Step 1 — Check why the new pod is not ready:
kubectl describe pod nginx-deployment-def456-qwert
Events:
Warning Unhealthy 3m (x18 over 5m) kubelet
Readiness probe failed: HTTP probe failed with statuscode: 404
(probe path: /ready, port: 8080)
Step 2 — Check the application logs:
kubectl logs nginx-deployment-def456-qwert
2026-01-20 10:00:00 INFO Server started on port 8080
2026-01-20 10:00:01 WARN /ready endpoint not implemented in v2
Root Cause: Version 2 of the app removed the /ready health check endpoint. The readiness probe now returns 404.
Fix options:
Option A — Fix the application code to restore the /ready endpoint
Option B — Update the readiness probe path in the deployment:
kubectl edit deployment nginx-deployment
# Change readinessProbe.httpGet.path from /ready to /health
Rollback while the fix is prepared:
kubectl rollout undo deployment/nginx-deployment
Scenario 3: Accidental bad image tag pushed to production
Situation: A team member ran:
kubectl set image deployment/nginx-deployment nginx=nginx:999-nonexistent
Now new pods are in ImagePullBackOff.
$ kubectl get pods
NAME READY STATUS RESTARTS
nginx-deployment-oldrs-abc 1/1 Running 0 # old — still serving traffic
nginx-deployment-newrs-xyz 0/1 ImagePullBackOff 0 # new — broken
Because maxUnavailable: 0 is set in the rolling update strategy, old pods are still running. The application is not down, but the rollout has stalled.
Immediate rollback:
# Check rollout status
kubectl rollout status deployment/nginx-deployment
# Error: deployment "nginx-deployment" exceeded its progress deadline
# Rollback immediately
kubectl rollout undo deployment/nginx-deployment
# Verify rollback is complete
kubectl rollout status deployment/nginx-deployment
# deployment "nginx-deployment" successfully rolled out
# Confirm all pods are healthy
kubectl get pods
kubectl get deploy
Scenario 4: All pods scheduled on the same node after scaling
Situation: You scaled from 3 to 6 replicas, but all new pods landed on the same node.
kubectl get pods -o wide
# NAME NODE STATUS
# nginx-pod-1 node-1 Running
# nginx-pod-2 node-1 Running
# nginx-pod-3 node-1 Running
# nginx-pod-4 node-1 Running # should be on node-2 or node-3
# nginx-pod-5 node-1 Running
# nginx-pod-6 node-1 Running
Fix — Add Pod Anti-Affinity to spread pods across nodes:
spec:
template:
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: "kubernetes.io/hostname"
kubectl apply -f nginx-deployment.yaml
kubectl rollout restart deployment/nginx-deployment
kubectl get pods -o wide # verify pods are now spread across nodes
The Relationship Between Pod, ReplicaSet, and Deployment
kubectl apply -f deployment.yaml
│
▼
Deployment ← You create and manage this
│ creates and manages
▼
ReplicaSet ← Kubernetes creates this automatically
│ creates and manages
▼
Pod Pod Pod ← Kubernetes creates these automatically
| Resource | Creates | Managed By | Main Feature |
|---|---|---|---|
| Pod | Nothing | You (manually) or ReplicaSet | Runs containers |
| ReplicaSet | Pods | You (manually) or Deployment | Maintains desired replica count |
| Deployment | ReplicaSet → Pods | You | Rolling updates + Rollback |
Rule of thumb: In production, always use Deployments. Never create bare Pods or ReplicaSets directly for your applications.
Master Troubleshooting Command Reference
# ===== POD DEBUGGING =====
kubectl get pods # list pods and their status
kubectl get pods -o wide # include node and IP info
kubectl describe pod <pod-name> # full details and events
kubectl logs <pod-name> # current container logs
kubectl logs <pod-name> --previous # logs from crashed container
kubectl logs <pod-name> -c <container> # specific container logs
kubectl exec -it <pod-name> -- /bin/bash # shell into the container
kubectl get events --sort-by=.metadata.creationTimestamp # all events, newest last
# ===== REPLICASET DEBUGGING =====
kubectl get rs # list ReplicaSets
kubectl describe rs <rs-name> # events and selector info
kubectl get pods -l app=nginx # find pods via label selector
# ===== DEPLOYMENT DEBUGGING =====
kubectl get deploy # list deployments
kubectl describe deploy <deploy-name> # full info and events
kubectl rollout status deployment/<name> # watch rollout progress
kubectl rollout history deployment/<name> # show revision history
kubectl rollout undo deployment/<name> # rollback to previous revision
kubectl rollout restart deployment/<name> # rolling restart same spec
kubectl set image deployment/<name> <c>=<image>:<tag> # update image (triggers rollout)
kubectl scale deployment <name> --replicas=<n> # scale replicas
Pro Tip: When debugging a Deployment issue, always follow this order:
kubectl get deploy→kubectl describe deploy→kubectl get rs→kubectl get pods→kubectl describe pod→kubectl logs. Each layer narrows down the root cause.
Next Up: Module 4 — Kubernetes Services, ConfigMaps, and Secrets