Build your lab cluster

Install Docker, kind, kubectl and Helm, build the three-node lab every task in this course runs on, and learn to check, reset and delete it.

45 min 2 hands-on tasks

Key ideas in this lesson · tap one for a simple explanation

What you will be able to do

  • Build the cka lab cluster with one command and say what each extra is for.
  • Open a shell on a lab node and say how that differs from ssh on the exam.
  • Fix the common lab problems (Docker not running, a port in use, slow downloads) without rereading this page.

Every task in this course ends with a check script, and that script needs a cluster to look at. So you will build a small cluster on your own computer: the lab. It uses kind (short for Kubernetes in Docker), a tool that runs each Kubernetes as a Docker . It is free, and it builds or resets in a few minutes.

What the lab looks like

Your computer

you type kubectl here

Docker

runs each node as a container

Cluster cka

three nodes

cka-control-plane

makes the decisions

cka-worker

runs your Pods

cka-worker2

runs your Pods

kind builds the cluster out of Docker containers. kubectl on your computer reaches it through the context kind-cka.

Inside each container, kind sets the node up with , the same setup tool the exam clusters use. So the parts and the file paths match the exam. Only the kubeadm work itself (installing, upgrading, joining nodes) needs real machines; see the end of this page.

Install the tools

ToolWhat it does
DockerRuns containers. kind needs it.
kindBuilds a Kubernetes cluster out of Docker containers. You use it only for the lab.
The command you use to talk to any cluster, in the lab and on the exam.
Installs packaged apps, called . The Helm lesson uses it.
macOS: Docker Desktop or Colima, then kind, kubectl and helm
# 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
Ubuntu 24.04 (and Windows inside a WSL2 Ubuntu shell)
# 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=512
  • Windows: install Docker Desktop with the WSL 2 backend, then Ubuntu from the Microsoft Store. In Docker Desktop, turn on Settings > Resources > WSL integration for Ubuntu. Then do everything from the Ubuntu shell with the Ubuntu block above, minus its Docker Engine part: Docker Desktop already gives Ubuntu the docker command.
  • kubectl version: kubectl works with an at most one minor version older or newer. Once the lab is up, run kubectl version and compare the Client and Server versions. If they are further apart, install the matching kubectl from the install page. The exam runs v1.37, so kubectl v1.37 on a v1.36 or v1.37 lab is ideal.
  • Memory and CPU: give Docker at least 4 GB of memory and 2 CPUs for the three nodes and the extras. 6 GB is comfortable.

Build the lab

One command, three to six minutes on first run
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

The script builds the cluster, then adds the extras the exam topics need:

PartWhat it is for
The cluster ckaBuilt from kind-config.yaml: one node, cka-control-plane, and two workers, cka-worker and cka-worker2. Its kubectl context is kind-cka.
The pod network. The script turns off kind's own network plugin and installs Calico instead. Calico enforces , which the exam's NetworkPolicy tasks need.
Makes kubectl top nodes and kubectl top pods show numbers. It needs about a minute after install before it has data. It runs with --kubelet-insecure-tls, because kind's certificates are self-signed.
The controller, with IngressClass nginx. It runs on the control plane node. That node's ports 80 and 443 reach your computer as localhost:8080 and localhost:8443.
Let you create Gateway and HTTPRoute objects. There is no Gateway controller, so routes do not carry traffic. The exam checks the objects, so that is enough to practice.
30080Port 30080 on the control plane node reaches your computer as localhost:30080. Other NodePorts work only from inside the cluster or from a node shell.
The folder /tmp/ckaWhere every task writes its answer files. The exam uses paths like /opt/course/3/answer.txt: same idea, different folder.

A shell on a node

Some tasks need a shell on a node, for example to read a file under /etc/kubernetes. kind nodes are containers, so in the lab you open that shell with docker exec. On the exam, nodes are real machines, so you use ssh. Every node task in this course shows both.

One node shell, two ways in

In the lab

you are root at once

docker exec -it cka-control-plane bash

On the exam

then sudo -i to become root

ssh <node>

  • Use cka-worker or cka-worker2 instead of cka-control-plane to reach the other nodes.
  • Inside, systemctl, journalctl, crictl and /etc/kubernetes are where you would find them on an exam node.
  • One difference: here the kubelet runs inside a container. Restarting it is quick, and you cannot reboot a kind node.

Check, reset, delete

Three more scripts look after the lab. Run the check whenever something looks wrong. Reset before each mock exam, so leftovers from one attempt do not spoil the next.

Check, reset, tear down
# 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.

When the lab misbehaves

What you seeWhyFix
lab-up says "Docker is not running", or docker info hangsDocker is not runningStart Docker: open Docker Desktop, run colima start, or on Linux run sudo systemctl start docker.
"port is already allocated" for 8080, 8443 or 30080Another program already uses that portFind it with lsof -i :8080 (or ss -ltnp) and stop it. Or download kind-config.yaml, change its hostPort values, and run lab-up.sh in the same folder: it uses that local file.
calico-node or ingress-nginx stay in ContainerCreating for minutesImages are still downloading, which is slow the first timeWait, and watch with kubectl -n kube-system get pods -w. Then run lab-up again: it carries on where it stopped.
Nodes stay NotReady for more than two minutesThe pod network is not up yet, or the Linux inotify limits are too lowLook at kubectl -n kube-system get pods, then raise the inotify limits (the last line of the Ubuntu block), then run lab-up again.
kubectl top says metrics are not availablemetrics-server has no data yetWait 60 seconds and try again.
After a reboot the cluster exists, but the context is goneThe entry was removed, or Docker restarted the containersRun kind export kubeconfig --name cka, then lab-check.
Everything acts strangely and you do not know whyLeftovers from earlier tasksRun lab-reset.sh.

Optional: a kubeadm lab on virtual machines

The kind lab cannot upgrade a cluster with kubeadm or join a new node. To do those once with your own hands, build a small lab of virtual machines (VMs) the week before a mock. You need it for two lessons only; the kind lab covers everything else.

In the official docs· open on exam day too

Hands-on task 1 of 2fd-lab-1
~3 min2% weightArchitecture

Prove the lab is healthy

Bring the lab up and make every line of the lab check pass: context 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.

Cluster:kubectl config use-context kind-cka

  1. 1

    Start from a healthy lab

    No setup needed for this one.

  2. 2

    Solve it in your terminal

    Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under /tmp/cka/.

  3. 3

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/fd-lab-1/verify | bash
    Got FAIL? Read which check failed, fix it, run it again.
Hands-on task 2 of 2fd-lab-2
~3 min2% weightWorkloads

First Pod on the lab

Create a namespace named 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.

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/fd-lab-2/setup | bash
  2. 2

    Solve it in your terminal

    Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under /tmp/cka/.

  3. 3

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/fd-lab-2/verify | bash
    Got FAIL? Read which check failed, fix it, run it again.
  4. 4

    Clean up (optional)

    curl -fsSL https://codewithmuh.com/labs/cka/t/fd-lab-2/cleanup | bash

Finished this lesson?

0 of 2 tasks passed. Your readiness counts tasks, so run them before you move on.