Build your lab cluster
Install Docker, kind, kubectl and Helm, bring up the three-node lab every task in this course runs against, and learn how to check, reset and tear it down.
After this lesson
- 01You can bring up the cka kind cluster with one command and explain what each add-on is for.
- 02You can open a shell on a lab node and say how that differs from ssh on the exam.
- 03You can diagnose the three common lab failures (Docker down, port in use, slow pulls) without re-reading this page.
Every task in this course ends with a verify script, and that script needs a cluster to look at. The lab is a kind cluster: three Kubernetes nodes running as Docker containers on your machine. It is free, it builds in a few minutes, it resets in a few minutes, and it is close enough to the exam clusters for everything except the kubeadm lifecycle work (installing, upgrading, joining nodes), which needs real VMs and gets its own optional section at the end.
Install the tools
# Option A: Docker Desktop (give it at least 4 GB memory and 2 CPUs under Settings > Resources)
brew install --cask docker
open -a Docker
# Option B: Colima, a lighter Docker runtime for macOS
brew install colima docker
colima start --cpu 4 --memory 6
# The cluster tools
brew install kind kubectl helm
docker info >/dev/null && echo "docker ok"
kind version && kubectl version --client && helm version --short# Docker Engine from Docker's apt repository
sudo apt-get update && sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
sudo apt-get update && sudo apt-get install -y docker-ce docker-ce-cli containerd.io
sudo usermod -aG docker "$USER" && newgrp docker
# kind: a single release binary (pick amd64 or arm64)
arch=amd64; [ "$(uname -m)" = aarch64 ] && arch=arm64
curl -Lo kind "https://kind.sigs.k8s.io/dl/v0.32.0/kind-linux-$arch"
chmod +x kind && sudo mv kind /usr/local/bin/kind
# kubectl: the current stable release
curl -LO "https://dl.k8s.io/release/$(curl -Ls https://dl.k8s.io/release/stable.txt)/bin/linux/$arch/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
# helm: the release tarball
curl -fsSL "https://get.helm.sh/helm-v4.2.3-linux-$arch.tar.gz" | tar -xz
sudo mv "linux-$arch/helm" /usr/local/bin/helm && rm -rf "linux-$arch"
# kind needs more inotify headroom than Ubuntu ships with
sudo sysctl fs.inotify.max_user_watches=524288 fs.inotify.max_user_instances=512Windows: install Docker Desktop with the WSL 2 backend, install Ubuntu from the Microsoft Store, enable it under Docker Desktop > Settings > Resources > WSL integration, and then do everything in this course from the Ubuntu shell using the block above (skip the Docker Engine part; Docker Desktop provides the docker command inside WSL). kubectl version: kubectl supports one minor version of skew either way from the API server. After the cluster is up, compare kubectl version client and server; if the client is more than one minor away, install the matching release from https://dl.k8s.io/release/v1.NN.0/bin/<os>/<arch>/kubectl. The exam runs v1.37, so a v1.37 kubectl on a v1.36 or v1.37 lab is ideal. Resources: three nodes plus the add-ons need about 4 GB of memory for Docker and 2 CPUs; 6 GB is comfortable.
Bring the lab up
curl -fsSL https://codewithmuh.com/labs/cka/lab-up.sh | bash
# Prefer to read it first? Same thing, two steps:
curl -fsSLO https://codewithmuh.com/labs/cka/lab-up.sh && less lab-up.sh && bash lab-up.sh
# When it finishes you should see three Ready nodes and the summary block:
kubectl get nodes -o wide
kubectl config current-context # kind-cka- A kind cluster named
ckafromkind-config.yaml: one control plane (cka-control-plane) and two workers (cka-worker,cka-worker2), kubectl contextkind-cka. kind's default CNI is disabled so Calico can take its place. - Calico as the pod network. The exam's NetworkPolicy tasks only make sense on a CNI that enforces policies; kind's built-in kindnet does not.
- metrics-server (with
--kubelet-insecure-tls, because kind's kubelet certificates are self-signed) sokubectl top nodesandkubectl top podsreturn numbers. It needs a minute of samples after install. - ingress-nginx bound to the control-plane node, with the node's ports 80 and 443 mapped to
localhost:8080andlocalhost:8443. An Ingress you create is reachable withcurl -H 'Host: shop.example.com' http://localhost:8080/. The IngressClass isnginx. - Gateway API standard CRDs so Gateway and HTTPRoute objects validate and you can practice writing them. There is no Gateway controller, so routes do not serve traffic; the exam checks the objects.
- NodePort 30080 on the control plane is mapped to
localhost:30080. A NodePort Service that asks for port 30080 is reachable from your laptop; other NodePorts are reachable from inside the cluster or from a node shell. /tmp/cka, the directory every task writes answer files into. The exam uses paths like/opt/course/3/answer.txt; same idea, different prefix.
Getting a shell on a node. kind nodes are containers, so the node shell is docker exec -it cka-control-plane bash (or cka-worker, cka-worker2). You land as root with systemctl, journalctl, crictl and /etc/kubernetes where you would expect them. On the exam the equivalent is ssh <node> from the task host followed by sudo -i; every node-level task in this course shows both. One real difference: kind nodes run kubelet under systemd inside a container, so a kubelet restart is fast and a node reboot is not a thing.
# Health check: one PASS line per component, RESULT: PASS at the end. Run it when anything looks off.
curl -fsSL https://codewithmuh.com/labs/cka/lab-check.sh | bash
# Reset: deletes the cluster and runs lab-up again (two to four minutes). Use it between mock exams
# so leftover namespaces, taints and cordoned nodes from one attempt do not pollute the next.
curl -fsSL https://codewithmuh.com/labs/cka/lab-reset.sh | bash
# Tear down: deletes the cluster. Nothing else on your machine is touched; lab-up rebuilds it.
curl -fsSL https://codewithmuh.com/labs/cka/lab-down.sh | bash
# lab-up is idempotent: re-running it on an existing cluster just re-applies the add-ons.Optional: a kubeadm VM lab for the lifecycle lessons. If you want to run an upgrade or join a node with your own hands, create two or three Ubuntu 24.04 VMs with 2 CPUs and 2 to 4 GB each. With Multipass: multipass launch 24.04 --name cp --cpus 2 --memory 4G --disk 20G and the same for w1 and w2, then multipass shell cp. With Vagrant, a bento/ubuntu-24.04 box per node on a private network does the same job. The procedure (container runtime, kubeadm packages from pkgs.k8s.io, kubeadm init, a CNI, kubeadm join, then the minor-version upgrade) is in Installing a cluster with kubeadm and Upgrading clusters and draining nodes. Do it once, slowly, the week before a mock; the kind lab covers everything else.
In the docs · the tab you get on exam day
- kind quick start ↗search: “kind quick start”
- Install and set up kubectl on Linux ↗search: “install kubectl”
- Installing Helm ↗search: “installing helm”
- Installing kubeadm ↗search: “installing kubeadm”
context · kubectl config use-context kind-cka
Prove the lab is healthy
kind-cka exists, three nodes are Ready, Calico is installed, kubectl top nodes returns data, ingress-nginx and the Gateway API CRDs are installed, docker exec cka-control-plane true works, and /tmp/cka exists.- 01
Nothing to set up
Start on a healthy lab. Check it with lab-check.sh if unsure.
- 02
Solve it in your terminal
Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under
/tmp/cka/. - 03
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/fd-lab-1/verify | bashCounts toward your readiness score.
context · kubectl config use-context kind-cka
First Pod on the lab
fd-hello. In it, create a Pod named hello running the image nginx:1.27. The Pod must be in the Running state when you are done.- 01
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/fd-lab-2/setup | bash - 02
Solve it in your terminal
Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under
/tmp/cka/. - 03
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/fd-lab-2/verify | bashCounts toward your readiness score. - 04
Clean up
curl -fsSL https://codewithmuh.com/labs/cka/t/fd-lab-2/cleanup | bash
Finished reading?
0 of 2 tasks passed. Readiness counts tasks, so run them before you move on.