Home/Kubernetes
Lab · Manual of Kubernetes

Kubernetes

The helmsman of the digital fleet.

28 exercises6 Parts4 appendices
The colour code shows the level:FoundationalIntermediateAdvancedCloud Architect
get the exercises
git clone --filter=blob:none --sparse https://github.com/calmict/book_labs.git
cd book_labs
git sparse-checkout set kubernetes/ed1
calm@calmict:~$ cat kubernetes/topics
Part 1

The Linux foundations

  • 01A Container Is Just a Process (See It for Yourself)Foundational
  • 02A Container by Hand, Without DockerFoundational
  • 03Limiting CPU and RAM by HandFoundational
  • 04Dissect an Image by Hand (Anatomy of a Container)Foundational
  • 05Climb the Runtime Chain (and Run a Container with runc Alone)Foundational
  • 06Wire Two Network Namespaces by Hand (veth, a Bridge and a Ping)Foundational
Part 2

Control Plane architecture

  • 07First Contact: Kill a Pod and Watch Who Resurrects ItFoundational
  • 08Kill the Leader: Quorum and Elections in etcdFoundational
  • 09Knock at the Four Gates (the API Server, Bare-Handed)Foundational
  • 10Write Your Own Controller in Twenty Lines (and Learn Why Only One May Run)Foundational
  • 11Steer the Scheduler (Then Bypass It)Foundational
  • 12The Ship's Doctor: Probes, Restarts and the Pod That Resurrects AloneFoundational
Part 3

The core objects

  • 13The Investigation: Who Touched My Pod?Intermediate
  • 14The Condo Pod: Two Tenants, One Invisible JanitorIntermediate
  • 15The Release, the Disaster and the Comeback (Rollout and Rollback)Intermediate
  • 16The Registry Office: Names, Order and Disks That SurviveIntermediate
  • 17The Three Trades: One per Node, Until Done, On ScheduleIntermediate
Part 4

Networking and storage

  • 18The Address That Does Not Exist (Services and kube-proxy)Intermediate
  • 19The Door and the Doorman (Ingress and Ingress Controller)Intermediate
  • 20The Arranged Marriage (PV, PVC, StorageClass)Intermediate
Part 5

Security

  • 21The Intern and the Robot (Authentication and RBAC)Advanced
  • 22The Vault and the Corridor (NetworkPolicy and Zero-Trust)Advanced
  • 23The Cardboard King (container security)Advanced
Part 6

Ecosystem and production

  • 24The Mould and the Casts (Helm, the package manager)Cloud Architect
  • 25The Meter Reader (Prometheus and Grafana)Cloud Architect
  • 26The Ledger and the Auditor (ArgoCD and GitOps)Cloud Architect
  • 27The Escort (Istio and the service mesh)Cloud Architect
  • 28The Doorman's Passport (Ingress-Nginx and Cert-Manager)Cloud Architect
calm@calmict:~$ ls kubernetes/exercises/
01A Container Is Just a Process (See It for Yourself)Foundational

What you build

> Exercise for Chapter 1 — The Problem Containers Solve of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • distinguish what a container actually isolates compared to a virtual machine;
  • observe a "containerized" process simultaneously from the host and from inside the container, to see firsthand that it is the same Linux process viewed from two different angles;
  • connect this hands-on observation to the chapter's theoretical concept: process isolation vs hardware virtualization.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap01/solution
./run.sh

Expected result

  • [ ] You have the process's PID as it appears on the host and as it appears inside the container, and they are different numbers.
  • [ ] Your answers.md file contains an explanation (even a brief one, 4-6 lines) of why the same process has two different PIDs, connecting it to the idea of "a Linux process seen through a different window" rather than "a separate machine".
  • [ ] You verified that the hostname seen from inside the container differs from the host's.
  • [ ] The lab container has been removed at the end of the exercise.
02A Container by Hand, Without DockerFoundational

What you build

> Exercise for Chapter 2 — Linux Namespaces: The Art of Illusion of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • build a working "container" using only basic Linux tools (unshare, chroot), with no container runtime at all;
  • recognise namespaces as the real ingredient of the illusion: PID 1, private hostname, isolated network;
  • read and compare the files under /proc/[pid]/ns to prove, inode by inode, that two processes live in different namespaces.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap02/solution
./run.sh

Expected result

  • [ ] Inside the container, ps aux shows your shell as PID 1 and an almost empty process list.
  • [ ] The hostname inside is "hand-made-container" and the host's hostname is untouched.
  • [ ] You have the /proc/[pid]/ns inode comparison: pid, uts and net differ between container and host. And you noticed the user case: identical in the sudo variant (we did not isolate it), different in the rootless variant (it is the namespace that makes all the others possible without root).
  • [ ] Your answers.md file answers the three questions of step 6.
  • [ ] The lab folder has been removed.
03Limiting CPU and RAM by HandFoundational

What you build

> Exercise for Chapter 3 — Cgroups: The Resource Accountant of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • create a cgroup v2 by hand and read/write its control files, with no runtime involved;
  • cage a running process and watch the two opposite fates: CPU gets slowed down (throttling), memory kills (OOM kill);
  • connect cpu.max and memory.max to what Kubernetes calls requests/limits, and understand where the OOMKilled status comes from.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap03/solution
./run.sh

Expected result

  • [ ] You saw the same loop first close to 100% of a core and then pinned at 20%, with nr_throttled growing in cpu.stat.
  • [ ] The glutton process was killed (Killed / exit 137) and memory.events records oom_kill 1, with memory.peak stopped just above 64M.
  • [ ] Your answers.md file answers the three questions of step 6.
  • [ ] The cage was removed with rmdir and no lab processes are left around.
04Dissect an Image by Hand (Anatomy of a Container)Foundational

What you build

> Exercise for Chapter 4 — Anatomy of a Container of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • open an OCI image and recognise its three ingredients: manifest, config and layers (which are plain filesystem tarballs);
  • mount an OverlayFS by hand and watch copy-on-write at work: where changes end up, how a file dies (whiteout), why a container's layer is disposable;
  • prove that root in the container is not root on the host (capabilities) and that there is one single, shared kernel.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap04/solution
./run.sh

Expected result

  • [ ] You identified the config path and the layer path in the manifest, and inside the extracted layer there is a complete root filesystem.
  • [ ] The change of step 4 exists only in upper, the deletion produced a whiteout, and the original layer is untouched.
  • [ ] You have the two CapEff masks (different) and the failure of date -s in the container.
  • [ ] uname -r inside and outside match, and answers.md answers the three questions.
  • [ ] Overlay unmounted and lab folder removed.
05Climb the Runtime Chain (and Run a Container with runc Alone)Foundational

What you build

> Exercise for Chapter 5 — The Runtime War: Docker, containerd, CRI-O of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • climb the real process chain of a running container and discover who is actually there (and who is NOT) between it and init;
  • query containerd directly, bypassing Docker, to see firsthand that the docker command is just a client;
  • read an OCI bundle (the config.json that containerd prepares for runc) and recognise in it the namespaces, cgroups and capabilities of chapters 2-4;
  • start a container with runc alone: no daemons, no API, just the spec and a rootfs.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap05/solution
./run.sh

Expected result

  • [ ] You have the parent chain written down: process → containerd-shim → PID 1, with dockerd and containerd alive but outside the chain.
  • [ ] You saw your container listed by ctr in the moby namespace, without going through docker.
  • [ ] In config.json you located the namespaces, resources (cgroup) and capabilities sections.
  • [ ] The container started with runc run came up, you entered it (PID 1) and closed it with exit.
  • [ ] answers.md answers the three questions and the lab is torn down.
06Wire Two Network Namespaces by Hand (veth, a Bridge and a Ping)Foundational

What you build

> Exercise for Chapter 6 — Linux Networking from the Ground Up of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • create network namespaces, virtual cables (veth) and a virtual switch (bridge), and wire them up the way a container runtime would;
  • follow a ping across your switch and read the evidence it leaves behind (ARP table, bridge forwarding);
  • recognise in docker0 the very same layout you just built by hand.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap06/solution
./run.sh

Expected result

  • [ ] The ping from blue to red gets replies across the bridge.
  • [ ] ip neigh inside blue shows red's MAC, and the br-lab fdb shows on which ports it learned the addresses.
  • [ ] You recognised the bridge+veth layout in docker0 (or you did everything in the rootless variant).
  • [ ] answers.md answers the three questions.
  • [ ] Namespaces and bridge removed, no orphan veth interfaces left (ip link | grep veth does not show yours).
07First Contact: Kill a Pod and Watch Who Resurrects ItFoundational

What you build

> Exercise for Chapter 7 — The Architecture at a Glance of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • start a local cluster and recognise at a glance the control plane components (the brain) and what runs on the workers (the arms);
  • experience the declarative model firsthand: you declare the desired state, the reconciliation loop chases it — even against your sabotage;
  • read a Kubernetes object the way the API sees it: spec (desired) versus status (observed), and discover that everything really is a resource.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap07/solution
./run.sh

Expected result

  • [ ] kubectl get nodes answers and you identified the 4 brain components in kube-system.
  • [ ] In the watch you saw the deleted Pod and its replacement being born with another name, with no intervention of yours.
  • [ ] You can point at where the wish lives (spec) and where reality lives (status) in the Deployment YAML.
  • [ ] answers.md answers the three questions.
  • [ ] The lab Deployment has been removed.
08Kill the Leader: Quorum and Elections in etcdFoundational

What you build

> Exercise for Chapter 8 — Etcd and Distributed Consensus of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • start a cluster with 3 control planes and query the 3 etcd members that hold its memory;
  • see that every Kubernetes object is literally a key inside etcd (/registry/...);
  • assassinate the leader and witness the successor's election, with the cluster not missing a beat;
  • break the quorum and experience firsthand what "the cluster is frozen" means — then bring it back to life.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap08/solution
./run.sh

Expected result

  • [ ] You saw 3 etcd members with exactly one IS LEADER=true and noted who it was.
  • [ ] You found the raft-lab namespace as a /registry/... key inside etcd.
  • [ ] After pausing the leader you saw a new leader and kubectl still working.
  • [ ] With 2 nodes frozen you got the lost-quorum error, and after the unpause the cluster came back whole, raft-lab included.
  • [ ] answers.md answers the three questions and the book-labs-ha cluster has been deleted.
09Knock at the Four Gates (the API Server, Bare-Handed)Foundational

What you build

> Exercise for Chapter 9 — API Server: The Single Source of Truth of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • talk to the API server without kubectl, with plain curl, and recognise groups, versions and resources of the REST API;
  • consciously walk a request through its gates: rejected at authentication (401), rejected at authorization (403), rejected by admission (quota) and finally accepted;
  • use a watch to see, streamed live, the events that keep the cluster in sync.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap09/solution
./run.sh

Expected result

  • [ ] You browsed /api and /apis via curl and recognised groups and versions.
  • [ ] You collected the full sequence: rejected as anonymous → 200 with certificates → Forbidden while impersonating → exceeded quota.
  • [ ] You saw watch-lab's ADDED and DELETED events in the watch stream.
  • [ ] answers.md answers the three questions.
  • [ ] quota-lab namespace removed, extracted certificates deleted, proxy closed.
10Write Your Own Controller in Twenty Lines (and Learn Why Only One May Run)Foundational

What you build

> Exercise for Chapter 10 — Controller Manager and the Reconciliation Loop of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • recognise the heartbeat of the real controllers: the leader-election Leases in kube-system;
  • write a working controller yourself (observe–diff–act in twenty lines of shell) and watch it repair your sabotage;
  • discover its two structural flaws — polling and the duel between copies — and understand why client-go answers with informers and leader election.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap10/solution
./run.sh

Expected result

  • [ ] You saw the controller-manager lease's renewTime move forward.
  • [ ] Your minictl.sh recreates the deleted pod with no human intervention and prunes the excess.
  • [ ] You provoked and described the duel between two copies.
  • [ ] answers.md answers the three questions.
  • [ ] No app=minictl pods left and scripts stopped.
11Steer the Scheduler (Then Bypass It)Foundational

What you build

> Exercise for Chapter 11 — The Scheduler of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • demonstrate what the scheduler actually does (it chooses and writes the node) and what it does not — to the point of bypassing it entirely with a Pod that never meets it;
  • see filtering in action: a Pod rejected by every node stays Pending, with the reason written in its events;
  • steer the choices with nodeSelector and anti-affinity, and understand taints as repulsion (with the toleration reopening the door).

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap11/solution
./run.sh

Expected result

  • [ ] You have the Scheduled event signed by default-scheduler for witness, and its absence for bypass.
  • [ ] You saw picky Pending with the filter's reason, then Running on the labelled node.
  • [ ] The 2 spread replicas sit on different workers, and the third went from Pending to the control plane thanks to the toleration.
  • [ ] answers.md answers the three questions.
  • [ ] The book-labs-sched cluster has been deleted.
12The Ship's Doctor: Probes, Restarts and the Pod That Resurrects AloneFoundational

What you build

> Exercise for Chapter 12 — The Worker Node Components of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • watch the kubelet play doctor: a failing liveness probe and the container restarted, with the restart count and the growing back-off;
  • tell the two fates apart: liveness (restart) versus readiness (out of the traffic rotation, no restart) — watching a Service's endpoints empty and refill;
  • prove that the kubelet needs nobody: a static pod created by placing a file on the node, which resurrects even if you delete it from the API.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap12/solution
./run.sh

Expected result

  • [ ] liar's RESTARTS climbed at least twice and the events show Unhealthy, Killing and the Back-off.
  • [ ] moody's endpoints emptied and refilled without any pod restart.
  • [ ] hello-static appeared without an apply, resurrected after the delete, and vanished when the file was removed from the node.
  • [ ] answers.md answers the three questions.
  • [ ] Lab pod and Service removed.
13The Investigation: Who Touched My Pod?Intermediate

What you build

> Exercise for Chapter 13 — The Life of a Pod: From kubectl apply to the Running Container of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • reconstruct the whole relay race of a kubectl apply from the evidence: four different signatures on the events (deployment-controller, replicaset-controller, default-scheduler, kubelet);
  • follow the chain of ownership Deployment → ReplicaSet → Pod written in the ownerReferences, and descend below the API down to the Linux process — meeting the namespaces and cgroups of Phases 1-2 again;
  • tell the two cures apart: the kubelet restarting a dead container (same Pod, RESTARTS climbing) and the controller replacing a deleted Pod (new name).

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap13/solution
./run.sh

Expected result

  • [ ] You have the timeline with the four signatures and the reconstructed logical order.
  • [ ] You have the chain Pod → ReplicaSet → Deployment read from the ownerReferences.
  • [ ] You found the PID on the node and its kubepods cgroup with the QoS class in the path.
  • [ ] You observed both cures: RESTARTS at 1 after the kill -9, a new name after the delete.
  • [ ] answers.md answers the three questions and the Deployment has been removed.
14The Condo Pod: Two Tenants, One Invisible JanitorIntermediate

What you build

> Exercise for Chapter 14 — The Pod in Depth of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • demonstrate why the unit is the Pod and not the container: two containers talking over localhost and passing files on a shared volume;
  • unmask the pause container: first from the namespace inodes on the node, then — turning the condo into glass — watching it appear as PID 1 inside the Pod;
  • watch an init container play gatekeeper (the Init:0/1 phase live) and read the QoS class of three Pods from their resources — finding it again in chapter 3's cgroup hierarchy.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap14/solution
./run.sh

Expected result

  • [ ] The wget from the writer returns the date written by the other container (shared localhost + volume).
  • [ ] You have the inodes: identical net between the two containers, different pid, and you found the /pause process on the node.
  • [ ] In condo-glass you saw /pause as PID 1 from inside the Pod.
  • [ ] You observed the Init:0/1 phase and the three QoS verdicts (BestEffort, Burstable, Guaranteed).
  • [ ] answers.md answers the three questions and the six Pods have been removed.
15The Release, the Disaster and the Comeback (Rollout and Rollback)Intermediate

What you build

> Exercise for Chapter 15 — ReplicaSet and Deployment of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • read the division of labour: the ReplicaSet as guardian of the count, the Deployment as orchestrator of ReplicaSets — with the old ReplicaSets kept at zero as historical memory;
  • perform a zero-downtime rolling update and watch it pod by pod (maxSurge 1, maxUnavailable 0);
  • survive a broken release: the rollout gets stuck but the service stays up, and kubectl rollout undo brings you back in an instant — understanding it is no magic, just the reconciliation loop again.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap15/solution
./run.sh

Expected result

  • [ ] You watched the rolling update pod by pod, never below 3 active.
  • [ ] After the release you have two ReplicaSets (3 and 0) and the history with the change-causes.
  • [ ] In the disaster: rollout stuck in ImagePullBackOff while the 3 pods of the previous version kept Running.
  • [ ] After the undo the image is back to alpine:3.20 and the revision was reborn with a new number.
  • [ ] answers.md answers the three questions and the Deployment has been removed.
16The Registry Office: Names, Order and Disks That SurviveIntermediate

What you build

> Exercise for Chapter 16 — StatefulSet and State Management of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • feel the difference between fungible Pods and Pods with an identity: the crowd is reborn with random names, diary-1 is reborn as diary-1;
  • observe the strict ordering (0 → 1 → 2 going up, reverse going down) and the predictable DNS via a headless Service;
  • prove that with volumeClaimTemplates each replica gets its OWN disk, and that the disk outlives the Pod — and even the deletion of the whole StatefulSet.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap16/solution
./run.sh

Expected result

  • [ ] You have the name contrast: random in the crowd, diary-N in the registry, born in 0→1→2 order.
  • [ ] diary-1 was reborn as diary-1 and its diary held the line from its previous life.
  • [ ] You saw the 3 personal PVCs, still alive after the StatefulSet's deletion, and the full diary after the recreation.
  • [ ] The nslookup of the stable name resolves from inside.
  • [ ] answers.md answers the three questions and the cleanup includes the PVCs.
17The Three Trades: One per Node, Until Done, On ScheduleIntermediate

What you build

> Exercise for Chapter 17 — DaemonSet, Job and CronJob of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • read the DaemonSet as a geographic contract: no replicas field — the cluster decides the count, one watchman per node (with chapter 11's toleration to cover the control plane too);
  • meet the first object that wants to finish: the Job, with the difference between restarting a container and retrying a Pod (backoffLimit), and the honest failure of a Job that cannot make it;
  • watch a CronJob punch the clock: the CronJob → Job → Pod chain, one minute after the apply.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap17/solution
./run.sh

Expected result

  • [ ] watchman: 2 watchmen before the toleration, 3 after, and the same-node rebirth.
  • [ ] countdown Completed with the counting logs; flaky Failed with BackoffLimitExceeded after 3 pods.
  • [ ] The CronJob's first punch: a tick-<timestamp> Job with the date in its logs.
  • [ ] answers.md answers the three questions (trades table included).
  • [ ] The book-labs-crew cluster has been deleted.
18The Address That Does Not Exist (Services and kube-proxy)Intermediate

What you build

> Exercise for Chapter 18 — Services and the Magic of kube-proxy of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • feel the problem Services solve: ephemeral Pods, IPs that change at every rebirth;
  • use a stable, balanced ClusterIP — then unmask it: it exists on no interface, it is an iptables trick (DNAT plus a netfilter coin, chapter 6 in full glory);
  • follow the chain that keeps the list fresh: EndpointSlice noticing every birth and death, and CoreDNS giving it all the only truly stable name.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap18/solution
./run.sh

Expected result

  • [ ] You experienced the death of the direct number (pod IP changed after the rebirth).
  • [ ] The switchboard answers with both voices (balancing seen through repeated wgets).
  • [ ] You have the proof that the ClusterIP exists on no interface, plus the KUBE-SVC/KUBE-SEP rules with probability and DNAT.
  • [ ] You watched the EndpointSlices chase the scale, and DNS resolve the name to the ClusterIP.
  • [ ] answers.md answers the three questions and the lab is torn down.
19The Door and the Doorman (Ingress and Ingress Controller)Intermediate

What you build

> Exercise for Chapter 19 — Ingress and Ingress Controller of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • understand why Services (L4) are not enough: the Ingress reads what they cannot see — host and path;
  • feel the separation of roles through an experiment: Ingress rules applied WITHOUT a controller do nothing — the object is the written request, the controller is who executes it;
  • install ingress-nginx on kind and watch L7 routing live: two hosts on the same IP and port, each to its own app, and the default backend for strangers.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap19/solution
./run.sh

Expected result

  • [ ] With the rules applied but no controller: curl refused and ADDRESS empty.
  • [ ] After the installation: uno.labs.local → app-uno, due.labs.local → app-due, unknown host → 404.
  • [ ] You recognised your requests in the controller's logs.
  • [ ] answers.md answers the three questions.
  • [ ] The book-labs-ingress cluster has been deleted.
20The Arranged Marriage (PV, PVC, StorageClass)Intermediate

What you build

> Exercise for Chapter 20 — Storage: PV, PVC, StorageClass and CSI of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • arrange a static marriage: a hand-made PV, a PVC asking for it, the 1:1 binding — and the spinster stuck Pending when the volumes run out;
  • unleash dynamic provisioning: a PVC with a StorageClass and a PV born out of nowhere, signed by the provisioner;
  • read the reclaim policies in practice: the dynamic PV dying with its claim (Delete) and the manual one left a widow, still guarding the dowry (Retain, Released state).

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap20/solution
./run.sh

Expected result

  • [ ] bride Bound to manual-pv, writer Running, spinster Pending forever.
  • [ ] cloud Bound to a pvc-<uid> PV born from the provisioner, with RECLAIM POLICY Delete against the manual one's Retain.
  • [ ] After the massacre of the claims: dynamic PV gone, manual-pv Released, and the dowry still readable on the node.
  • [ ] answers.md answers the three questions.
  • [ ] Released PV and node folder removed by hand.
21The Intern and the Robot (Authentication and RBAC)Advanced

What you build

> Exercise for Chapter 21 — Authentication and RBAC of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • hire a real user: private key, CertificateSigningRequest signed by the cluster CA, dedicated kubeconfig — discovering that human users are not API objects: they exist only in certificates (CN = name, O = groups);
  • apply least privilege with Role and RoleBinding, and verify its borders: the intern reads pods in default and nothing else — cannot create them, cannot see secrets, cannot leave the namespace;
  • give a Pod an identity (ServiceAccount) and use it from inside: the mounted token, the API call from the container, the 403 that becomes a 200 with the right binding.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap21/solution
./run.sh

Expected result

  • [ ] The CSR was approved and whoami recognises the intern (tirocinanti group) from her kubeconfig.
  • [ ] Before the Role: Forbidden on everything; after: get pods yes, create/secrets/kube-system still Forbidden.
  • [ ] The robot got the 403 without the binding and the PodList with it, using the mounted token.
  • [ ] answers.md answers the three questions.
  • [ ] CSR, RBAC objects, robot and local files removed.
22The Vault and the Corridor (NetworkPolicy and Zero-Trust)Advanced

What you build

> Exercise for Chapter 22 — NetworkPolicy and the Zero-Trust Approach of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • feel the default-allow problem: in the Kubernetes condo every pod reaches every pod, vault included;
  • invert the rule with a three-line default deny, then reopen ONLY the right door: labels as firewall rules, ports as a contract;
  • close the exit too (egress): a vault that receives but never phones out — and discover who actually realises the policies (the CNI), with the enforcement test as a hygiene habit.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap22/solution
./run.sh

Expected result

  • [ ] Before any policy: jewels for everyone (default allow, felt firsthand).
  • [ ] With deny-all: timeout for everyone — and the enforcement test passed.
  • [ ] With allow-app: app in, guest out; with no-exfiltration: the vault makes no calls.
  • [ ] answers.md answers the three questions.
  • [ ] The vault namespace has been deleted.
23The Cardboard King (container security)Advanced

What you build

> Exercise for Chapter 23 — Container security of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • feel firsthand why root inside a container is a cardboard king: uid 0, yes, but the real power lives in the capabilities, the privileges and the filesystem — and in the kernel it shares with the host;
  • harden a pod with the SecurityContext: non-root user, no escalation, read-only filesystem, all capabilities dropped, seccomp on — and verify each defence from the inside;
  • move from pod-by-pod defence to defence at scale with Pod Security Standards: one label on the namespace, and admission refuses non-compliant pods before they are even born.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap23/solution
./run.sh

Expected result

  • [ ] The naked king: uid 0, CapEff a80425fb, Seccomp 0, writable root — seen with your own eyes.
  • [ ] The stripped king: non-root uid, CapEff all zeros, Seccomp 2, write refused.
  • [ ] Under restricted: the root intruder refused at admission, the hardened pod admitted.
  • [ ] answers.md answers the three questions.
  • [ ] The throne namespace has been deleted.
24The Mould and the Casts (Helm, the package manager)Cloud Architect

What you build

> Exercise for Chapter 24 — Helm, the Kubernetes package manager of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • feel the problem Helm solves: keeping dozens of near-identical manifests by hand, differing by two lines — the copy-paste cramp;
  • build a local chart: one mould (the templates) plus a settings sheet (values), and watch the same mould cast different manifests as the values change;
  • manage releases as numbered casts: install, upgrade with new values, read the history and roll back — and understand why a config-only change does not restart the pods.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap24/solution
./run.sh

Expected result

  • [ ] Templates completed: helm lint clean and helm template renders manifests with your values.
  • [ ] Revision 1 installed: one replica, "revision one" served.
  • [ ] Revision 2 after the upgrade: three replicas and "revision two" (the pods were rolled).
  • [ ] Rollback: the history has three lines and the ConfigMap is back to "revision one".
  • [ ] answers.md answers the three questions; release and namespace removed.
25The Meter Reader (Prometheus and Grafana)Cloud Architect

What you build

> Exercise for Chapter 25 — Prometheus and Grafana: eyes on the cluster of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • understand the pull model: Prometheus does not wait to be sent data, it goes and knocks on each target's /metrics door, like a meter reader walking house to house;
  • bolt the meters on (node-exporter), write the reader's round (the scrape config) and confirm with the up metric that someone answered at each door;
  • query the ledger of readings with PromQL through the Prometheus API, tell a gauge from a counter (and why rate is needed), and see that an alert is just a query crossing a threshold — and where Grafana fits.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap25/solution
./run.sh

Expected result

  • [ ] Saw the meter face: node-exporter metrics as plain text over HTTP.
  • [ ] Completed the round: up is 1 for both prometheus and node.
  • [ ] Queried the ledger: count(up==1), a node gauge and a rate over a counter.
  • [ ] answers.md answers the three questions.
  • [ ] The monitoring namespace has been deleted.
26The Ledger and the Auditor (ArgoCD and GitOps)Cloud Architect

What you build

> Exercise for Chapter 26 — ArgoCD and GitOps of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • understand the GitOps principle: Git is the ledger, the single source of truth for what must exist in the cluster; nobody touches the world by hand, you write in the ledger;
  • give the assignment to a tireless auditor (ArgoCD) with the Application object, and watch it make the cluster match the ledger (sync), notice any divergence (drift) and correct it on its own (self-heal);
  • roll back the declarative way: you do not fix the world, you correct the ledger with git revert, and the auditor propagates the correction.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap26/solution
./run.sh

Expected result

  • [ ] ArgoCD installed and the git server (the ledger) running on the dedicated cluster.
  • [ ] Application completed: web Synced and Healthy, 1 replica, created by ArgoCD.
  • [ ] Drift and self-heal: the manual scale to 3 is undone, back to 1.
  • [ ] git revert: the bad commit takes the world to 5, the revert brings it back to 1.
  • [ ] answers.md answers the three questions; the dedicated cluster has been deleted.
27The Escort (Istio and the service mesh)Cloud Architect

What you build

> Exercise for Chapter 27 — Istio and the service mesh of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • understand the problem a service mesh solves: encryption, retries, routing and traces today live inside every application, rewritten in every language; the mesh pulls them out and hands them to an escort;
  • watch the escort attach itself to every pod (sidecar injection): the data plane is all the escorts (Envoy), the control plane (istiod) is the head office that briefs them;
  • turn on automatic mTLS (identity and encryption without touching the app or managing a single certificate) and steer traffic from above: an 80/20 canary between two versions, decided by decree.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap27/solution
./run.sh

Expected result

  • [ ] Injection: every pod in the mesh namespace has two containers (app + istio-proxy).
  • [ ] mTLS STRICT: the outside client is refused, the in-mesh client gets through.
  • [ ] Canary: about 80/20 between v1 and v2 over some thirty requests.
  • [ ] answers.md answers the three questions; the dedicated cluster has been deleted.
28The Doorman's Passport (Ingress-Nginx and Cert-Manager)Cloud Architect

What you build

> Exercise for Chapter 28 — Ingress-Nginx and Cert-Manager: automatic TLS of the > *Kubernetes Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • frame the TLS certificate problem: the doorman (Ingress-Nginx from chapter 19) must prove the building's identity to every visitor over HTTPS, but certificates have to be generated, installed and — above all — they expire;
  • stand up an automatic passport office with Cert-Manager: an authority (CA), and certificates issued and renewed on their own;
  • get end-to-end HTTPS with a single annotation on the Ingress, and validate the certificate against your CA — understanding where, in production, Let's Encrypt via ACME would step in.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd kubernetes/ed1/cap28/solution
./run.sh

Expected result

  • [ ] ingress-nginx and cert-manager running; the issuer chain ready (CA Ready).
  • [ ] The completed Ingress makes Cert-Manager issue the shop-tls Secret on its own.
  • [ ] curl HTTPS validated against the local CA answers secure shop; the certificate has the host's SAN.
  • [ ] answers.md answers the three questions; the dedicated cluster has been deleted.