Lab: Simulating Deployment Strategies with Kubernetes

LAB 4 min read

Prerequisites

  • kubectl configured against a running Kubernetes cluster (local clusters like minikube, kind, or k3d work perfectly)
  • minikube version 1.30 or later (if using minikube)
  • Basic familiarity with kubectl get and kubectl apply

Setup: Create a Working Directory

mkdir -p ~/devops-labs/deployment-strategies
cd ~/devops-labs/deployment-strategies

Part 1: Rolling Update in Action

Step 1: Deploy Version 1

Create the initial deployment file:

cat > rolling-deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
spec:
  replicas: 6
  selector:
    matchLabels:
      app: webapp
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
      - name: webapp
        image: nginx:1.24
        ports:
        - containerPort: 80
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 3
          periodSeconds: 3
EOF
kubectl apply -f rolling-deployment.yaml

Expected output:

deployment.apps/webapp created

Step 2: Watch the pods come up

kubectl get pods -l app=webapp --watch

Expected output (after ~15 seconds):

NAME                      READY   STATUS    RESTARTS   AGE
webapp-7d9f8b6c4-2xkpq   1/1     Running   0          12s
webapp-7d9f8b6c4-4mnvr   1/1     Running   0          12s
webapp-7d9f8b6c4-6bqwt   1/1     Running   0          12s
webapp-7d9f8b6c4-8hzpl   1/1     Running   0          12s
webapp-7d9f8b6c4-k9rts   1/1     Running   0          12s
webapp-7d9f8b6c4-p3vjx   1/1     Running   0          12s

Press Ctrl+C to stop watching.

Step 3: Trigger a rolling update to Version 2

Open a second terminal and run the watch command so you can observe the rollout live:

# Terminal 2: watch pods
kubectl get pods -l app=webapp --watch

In your first terminal, update the image:

kubectl set image deployment/webapp webapp=nginx:1.25

Expected output:

deployment.apps/webapp image updated

In Terminal 2, you will see pods being terminated and replaced one at a time:

webapp-7d9f8b6c4-2xkpq   1/1     Terminating   0          2m
webapp-8c6f9d7b5-nqwvz   0/1     Pending       0          0s
webapp-8c6f9d7b5-nqwvz   0/1     Running       0          3s
webapp-8c6f9d7b5-nqwvz   1/1     Running       0          6s
webapp-7d9f8b6c4-4mnvr   1/1     Terminating   0          2m
...

Step 4: Check rollout status

kubectl rollout status deployment/webapp

Expected output:

deployment "webapp" successfully rolled out

Step 5: Simulate a rollback

kubectl rollout undo deployment/webapp

Expected output:

deployment.apps/webapp rolled back

Verify the image reverted:

kubectl get deployment webapp -o jsonpath='{.spec.template.spec.containers[0].image}'

Expected output:

nginx:1.24

Part 2: Simulating Blue/Green with Two Deployments

Step 1: Create the Blue deployment (v1)

cat > blue-deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: webapp
      version: blue
  template:
    metadata:
      labels:
        app: webapp
        version: blue
    spec:
      containers:
      - name: webapp
        image: nginx:1.24
        ports:
        - containerPort: 80
EOF
kubectl apply -f blue-deployment.yaml

Step 2: Create the Service pointing to Blue

cat > webapp-service.yaml << 'EOF'
apiVersion: v1
kind: Service
metadata:
  name: webapp-svc
spec:
  selector:
    app: webapp
    version: blue
  ports:
  - port: 80
    targetPort: 80
EOF
kubectl apply -f webapp-service.yaml

Expected output:

service/webapp-svc created

Step 3: Deploy Green (v2) — no traffic yet

cat > green-deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-green
spec:
  replicas: 3
  selector:
    matchLabels:
      app: webapp
      version: green
  template:
    metadata:
      labels:
        app: webapp
        version: green
    spec:
      containers:
      - name: webapp
        image: nginx:1.25
        ports:
        - containerPort: 80
EOF
kubectl apply -f green-deployment.yaml

Verify both deployments are running:

kubectl get deployments

Expected output:

NAME           READY   UP-TO-DATE   AVAILABLE   AGE
webapp-blue    3/3     3            3           2m
webapp-green   3/3     3            3           30s

Step 4: Switch traffic from Blue to Green (the "flip")

kubectl patch service webapp-svc -p '{"spec":{"selector":{"version":"green"}}}'

Expected output:

service/webapp-svc patched

Step 5: Verify the switch

kubectl get service webapp-svc -o jsonpath='{.spec.selector}'

Expected output:

{"app":"webapp","version":"green"}

Step 6: Instant rollback — switch back to Blue

kubectl patch service webapp-svc -p '{"spec":{"selector":{"version":"blue"}}}'

Expected output:

service/webapp-svc patched

Verify It Worked

kubectl get deployments
kubectl get service webapp-svc -o jsonpath='{.spec.selector}'

You should see both Blue and Green deployments running, and the service selector showing blue after the rollback — confirming that traffic is back on the original version.

What Just Happened?

In Part 1, you observed Kubernetes' rolling update controller replacing pods one at a time, respecting the maxUnavailable and maxSurge constraints, and you practiced an instant rollback using kubectl rollout undo. In Part 2, you simulated a Blue/Green deployment by running two separate Deployments simultaneously and switching traffic between them by patching a single Service selector — a change that takes effect in milliseconds. This is the core mechanism behind Blue/Green: the "switch" is just a label selector update on a Service, not a redeployment of any application code.


Cleanup

kubectl delete deployment webapp webapp-blue webapp-green
kubectl delete service webapp-svc

You're viewing a free demo lesson

Take the 4-min skill check to get your personalized roadmap, then sign up to save it.

See my roadmap