Skip to content

Lab 2: Deployments, Services, Rolling Updates

Pairs with Phase 2. You'll deploy whoami (a tiny HTTP server that echoes its own hostname), watch self-healing and load balancing with your own eyes, then do a rolling update and roll it back.

Step 1: Try writing the Deployment yourself

Before copying anything: open a blank lab-2/deployment.yaml and try to write a Deployment named whoami, 3 replicas, image traefik/whoami:v1.10, container port 80. Use kubectl explain deployment.spec --recursive | less when stuck. Give it ten honest minutes.

Solution: deployment.yaml
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: whoami
spec:
  replicas: 3
  selector:
    matchLabels:
      app: whoami
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
        - name: whoami
          image: traefik/whoami:v1.10
          ports:
            - containerPort: 80

The part everyone gets wrong first: spec.selector.matchLabels must match spec.template.metadata.labels. The selector is how the Deployment finds its own pods - labels, not names.

bash
kubectl apply -f lab-2/deployment.yaml
kubectl get pods

Expected:

NAME                      READY   STATUS    RESTARTS   AGE
whoami-7d4b9c8f6d-4kx2p   1/1     Running   0          15s
whoami-7d4b9c8f6d-9mwlz   1/1     Running   0          15s
whoami-7d4b9c8f6d-tr8vn   1/1     Running   0          15s

Note the names: whoami (Deployment) + 7d4b9c8f6d (ReplicaSet hash) + random pod suffix. The layers are visible in the naming.

Step 2: The self-healing demo

bash
kubectl get pods -w

In a second terminal, delete one pod (use a real name from your output):

bash
kubectl delete pod whoami-7d4b9c8f6d-4kx2p

Watch the first terminal: the pod goes Terminating, and a new pod with a new name immediately appears. You declared 3 replicas; the ReplicaSet noticed 2 and fixed it. This is the difference from Lab 1's bare pod. Ctrl-C when done.

Step 3: The Service

Try writing lab-2/service.yaml yourself: a ClusterIP Service named whoami, port 80, selecting the app's pods.

Solution: service.yaml
yaml
apiVersion: v1
kind: Service
metadata:
  name: whoami
spec:
  selector:
    app: whoami
  ports:
    - port: 80
      targetPort: 80

No type: means ClusterIP. The selector matches the pod labels - the same duct tape again.

bash
kubectl apply -f lab-2/service.yaml
kubectl get svc whoami
kubectl get endpoints whoami

The endpoints output shows three IPs - the Service found all three pods via the label selector. If endpoints is empty, your selector doesn't match the pod labels: that's the #1 Service bug in the wild.

Step 4: See load balancing + cluster DNS

port-forward tunnels to a single pod, so it can't show load balancing. Instead, run a client inside the cluster:

bash
kubectl run client --image=curlimages/curl --rm -it --restart=Never -- sh

Inside, call the service by name a few times:

sh
curl -s http://whoami | grep Hostname
curl -s http://whoami | grep Hostname
curl -s http://whoami | grep Hostname
exit

Expected: the Hostname changes between requests - different pods answering. You just used cluster DNS (whoami resolves because the client pod is in the same namespace) and load balancing in one step.

Step 5: Rolling update and rollback

Watch in one terminal:

bash
kubectl get pods -w

In the other, upgrade the image:

bash
kubectl set image deployment/whoami whoami=traefik/whoami:v1.11
kubectl rollout status deployment/whoami

Watch old pods terminate one by one while new ones start - never all at once. Then check history and roll back:

bash
kubectl rollout history deployment/whoami
kubectl rollout undo deployment/whoami
kubectl get pods -o jsonpath='{.items[*].spec.containers[*].image}'

Expected: all pods back on traefik/whoami:v1.10.

In real life

kubectl set image is for labs and emergencies. The real workflow is: edit the YAML, kubectl apply. The YAML in git is the source of truth.

Verify it worked

  • [ ] Killing a pod resulted in automatic replacement, and you can say which component noticed (the ReplicaSet)
  • [ ] kubectl get endpoints whoami lists 3 pod IPs
  • [ ] You saw different hostnames answering requests to one service name
  • [ ] You rolled forward to v1.11 and back to v1.10

Keep these two files - Lab 6 reuses them. You can leave the app running.

Next: Lab 3: Config and State

A VineLab lab. Released under the MIT License.