Pods and Deployments: Desired State

First lesson of the Kubernetes course, free to read: about 18 minutes, 3 exercises and 3 quiz questions. This is the catalogue's base lesson; in the student space, it is rewritten for your profile.

Objectives

  • Understand the architecture of a Kubernetes cluster (control plane and nodes)
  • Describe an application with a Deployment manifest and apply it declaratively
  • Update an application with a rolling update and roll back

Control plane and nodesPodsDeployments and ReplicaSetsLabels and selectorsRolling update and rollback

With Docker and Compose, you know how to run containers on one machine. Kubernetes answers the following question: how do you run dozens of containers on several machines, restart them when they fall over, update them without downtime and spread them according to available resources? In this course, we start from images already built and published to a registry (see the Docker course): we don’t rewrite any Dockerfile.

A cluster’s architecture

A Kubernetes cluster consists of two parts.

  • The control plane makes the decisions: the API server receives all requests (including those from kubectl), etcd stores the cluster’s state, the scheduler chooses which node to place each pod on, the controller manager runs the controllers that correct discrepancies.
  • The nodes run the containers: on each one, the kubelet starts the requested pods through a container runtime (most often containerd) and kube-proxy handles service networking.

On a managed service (GKE, EKS, AKS…), the provider operates the control plane for you. Locally, minikube or kind create a complete cluster on your machine:

minikube start            # or: kind create cluster --name atelier
kubectl get nodes         # one node must be Ready
kubectl cluster-info

Desired state and reconciliation

You don’t tell Kubernetes “start three containers”. You describe the desired state: “I want three replicas of this image”. Controllers constantly compare this state with reality and correct the gap. If a node goes down, the missing pods are recreated elsewhere; if you delete a pod, it comes back. This is the reconciliation loop.

The pod, the smallest unit

A pod groups one or more containers that share an IP address and can share volumes. In the vast majority of cases, a pod contains a single application container. A pod is ephemeral: its IP changes each time it is recreated, and a pod created on its own is not recreated if it disappears. You therefore don’t create pods directly: you go through a Deployment.

A Deployment manifest

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: notes-api
  labels:
    app: notes-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: notes-api          # must match the template's labels
  template:
    metadata:
      labels:
        app: notes-api
    spec:
      containers:
        - name: notes-api
          image: hashicorp/http-echo:0.2.3
          args: ["-text=notes-api v1"]
          ports:
            - containerPort: 5678

Every object has the same structure: apiVersion and kind (the object type), metadata (name, labels), spec (the desired state). Labels are key-value tags; the selector is the query that finds the objects carrying these tags. The Deployment creates a ReplicaSet which, in turn, maintains the right number of pods.

kubectl apply -f deployment.yaml
kubectl get deploy notes-api          # READY 3/3
kubectl get rs,pods -l app=notes-api  # the ReplicaSet and its three pods
kubectl delete pod <one-of-the-pods>      # it is immediately replaced

The declarative approach (kubectl apply -f on files versioned in Git) is the norm: you edit the file, reapply it, and the Git history documents every change. Imperative commands (kubectl create, kubectl edit) are a quick fix but create a gap between the repository and the cluster.

Updating without downtime: the rolling update

Modifying the template (for example the image or its arguments) creates a new ReplicaSet. Kubernetes then replaces the pods gradually: by default, it can create up to 25% extra pods (maxSurge) and make at most 25% unavailable (maxUnavailable) during the switchover.

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0      # never fewer than 3 ready pods
kubectl set image deploy/web nginx=nginx:1.27   # or edit the file then apply
kubectl rollout status deploy/web               # follows progress
kubectl rollout history deploy/web              # known revisions
kubectl rollout undo deploy/web                 # back to the previous revision

The old ReplicaSet is kept (scaled to zero replicas): that is what makes rollback immediate. As with Docker, use immutable tags: with latest, you can’t tell which version is running nor reliably roll back.

Exercises

Solutions and tests stay on the server. In the student space, your code is run and checked, and the tutor gives hints before the solution.

  1. TaskDifficulty 11 hint

    First Deployment with three replicas

    Work on a local cluster: minikube start (or kind create cluster). Check with kubectl get nodes that a node is Ready before you begin.

    Create the lesson’s deployment.yaml file (Deployment notes-api, 3 replicas, image hashicorp/http-echo:0.2.3, argument -text=notes-api v1, label app: notes-api), apply it, then delete one of the pods and observe the result.

    • `kubectl apply -f deployment.yaml` prints `deployment.apps/notes-api created`
    • `kubectl get deploy notes-api` shows READY `3/3`
    • `kubectl get pods -l app=notes-api` lists exactly 3 pods with status `Running`
    • After `kubectl delete pod <name>`, a new `kubectl get pods -l app=notes-api` command lists 3 pods again, one of them with an AGE of a few seconds
  2. TaskDifficulty 22 hints

    Update then rollback

    Create a web Deployment with 2 replicas using the image nginx:1.26 (container name: nginx). Update it to nginx:1.27, follow the rollout, then go back to the previous version.

    • `kubectl rollout status deploy/web` prints `deployment "web" successfully rolled out` after the update
    • `kubectl rollout history deploy/web` shows at least 2 revisions
    • After `kubectl rollout undo deploy/web`, `kubectl get deploy web -o jsonpath='{.spec.template.spec.containers[0].image}'` prints `nginx:1.26`
    • `kubectl get rs -l app=web` shows two ReplicaSets, one of them at 0 replicas
  3. Multiple choiceDifficulty 21 hint

    The role of the selector

    In a Deployment, what is spec.selector.matchLabels for?

    • Choosing the node on which to place the pods
    • Indicating which pods belong to this Deployment, by finding them through their labels
    • Naming the image to download
    • Setting the number of replicas

End-of-lesson quiz

  1. What happens if you delete a pod managed by a Deployment?

    • The Deployment is deleted too
    • The ReplicaSet recreates a pod to return to the desired number of replicas
    • Nothing, you have to recreate it by hand
  2. Which component chooses the node a pod will run on?

    • The kubelet
    • The scheduler
    • etcd
  3. Which command goes back to a Deployment’s previous version?

    • kubectl rollout undo deploy/web
    • kubectl delete deploy/web
    • kubectl rollback web

The rest of the course

  1. Services and Ingress: Exposing an Application18 min
  2. Configuration, Secrets and Namespaces18 min
  3. Scaling and Resilience20 min
  4. Observability and Troubleshooting20 min

Kubernetes · Advanced · 1 h 34 min