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.
First Deployment with three replicas
Work on a local cluster:
minikube start(orkind create cluster). Check withkubectl get nodesthat a node isReadybefore you begin.Create the lesson’s
deployment.yamlfile (Deploymentnotes-api, 3 replicas, imagehashicorp/http-echo:0.2.3, argument-text=notes-api v1, labelapp: 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
Update then rollback
Create a
webDeployment with 2 replicas using the imagenginx:1.26(container name:nginx). Update it tonginx: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
The role of the selector
In a Deployment, what is
spec.selector.matchLabelsfor?- 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
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
Which component chooses the node a pod will run on?
- The kubelet
- The scheduler
- etcd
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
- Services and Ingress: Exposing an Application18 min
- Configuration, Secrets and Namespaces18 min
- Scaling and Resilience20 min
- Observability and Troubleshooting20 min