03-Deployment-concepts-with-real-examples
KubernetesPodReplicaSetDeploymentKubectlDevOpsTroubleshooting Beginner 9 min read

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:

  1. Rolling Updates — Update your application to a new version with zero downtime by gradually replacing old pods with new ones
  2. 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?

FeatureWhy It Matters
Rolling updatesUpdate your app image with zero downtime — old pods are only removed after new ones are healthy
RollbackOne command to revert to any previous version if something goes wrong in production
Self-healingInherits all ReplicaSet self-healing behaviour
ScalingEasily scale replicas up or down
Revision historyKubernetes tracks every change to the Deployment spec
Pause and ResumePause a rollout, make multiple changes, then resume
Update strategiesChoose 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:
  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
ResourceCreatesManaged ByMain Feature
PodNothingYou (manually) or ReplicaSetRuns containers
ReplicaSetPodsYou (manually) or DeploymentMaintains desired replica count
DeploymentReplicaSet → PodsYouRolling 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 deploykubectl describe deploykubectl get rskubectl get podskubectl describe podkubectl logs. Each layer narrows down the root cause.

Next Up: Module 4 — Kubernetes Services, ConfigMaps, and Secrets