Lesson 01 of 32 · Level 1 — Foundations
Set up your practice lab
Build a free, disposable Kubernetes cluster on your own laptop in about five minutes, so every lesson after this is hands-on.
Why start with a lab
You can read about Kubernetes for weeks and still freeze the first time a pod won't start. The fix is to touch it. Every lesson in this course has commands you run yourself, and at least one thing you break on purpose.
Learning Kubernetes from slides is like learning to ride a bike from a book. We're going to build a bike in your garage, one that's free, fits on your laptop, and that you're allowed to crash.
We will use kind (Kubernetes IN Docker). It runs each Kubernetes "server" as a Docker container on your laptop. It's the same tool the Kubernetes project uses to test itself, so what you learn here is real Kubernetes, not a toy.
| Option | Good for | Why not here |
|---|---|---|
| kind | Multi-node clusters on one laptop, fast rebuilds | ✅ Our choice |
| minikube | Single-node learning, lots of add-ons | Multi-node is less natural |
| k3d / k3s | Lightweight clusters, edge | Slightly different from upstream |
| Managed (EKS, GKE, AKS) | Real production | Costs money, slower to rebuild |
What you need
- Docker (Docker Desktop on Mac/Windows, Docker Engine on Linux) and about 4 GB of free RAM.
- A terminal. On Windows, use WSL2.
Check Docker works first:
$ docker run --rm hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
Install kubectl and kind
macOS (Homebrew):
$ brew install kubectl kind
Linux (x86-64):
$ curl -LO "https://dl.k8s.io/release/$(curl -Ls https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
$ sudo install -m 0755 kubectl /usr/local/bin/kubectl
$ curl -Lo kind https://kind.sigs.k8s.io/dl/v0.24.0/kind-linux-amd64
$ sudo install -m 0755 kind /usr/local/bin/kind
Check the versions
Run kubectl version --client and kind version. v0.24.0 above is an example: check the kind releases page on GitHub for the newest version and swap it into the URL.
Create a 3-node cluster
A single-node cluster hides important behaviour (scheduling, node failures). We'll use one control-plane node and two workers. Save this as kind-lab.yaml:
# kind-lab.yaml: a small but realistic practice cluster
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
$ kind create cluster --name lab --config kind-lab.yaml
Creating cluster "lab" ...
✓ Ensuring node image (kindest/node:v1.31.0) 🖼
✓ Preparing nodes 📦 📦 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
✓ Joining worker nodes 🚜
Set kubectl context to "kind-lab"
Your version numbers may be newer. That's fine.
Say hello to your cluster
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
lab-control-plane Ready control-plane 60s v1.31.0
lab-worker Ready <none> 40s v1.31.0
lab-worker2 Ready <none> 40s v1.31.0
Three nodes, all Ready. Now look at what those "nodes" really are:
$ docker ps --format '{{.Names}}\t{{.Image}}'
lab-control-plane kindest/node:v1.31.0
lab-worker kindest/node:v1.31.0
lab-worker2 kindest/node:v1.31.0
Each "computer" in your cluster is really a box inside Docker, like three toy houses on one table. Kubernetes doesn't know or care that they're toys. It treats them exactly like real servers.
How kubectl found the cluster
kind wrote connection details into your kubeconfig file (~/.kube/config). A kubeconfig holds three things:
- clusters: where the API server is (address + CA certificate)
- users: how to log in (here, a client certificate)
- contexts: a named pairing of cluster + user (+ default namespace)
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kind-lab kind-lab kind-lab
Always know which cluster you're pointing at
At work you'll have contexts for dev, staging and production in the same file. Many outages start with "I thought I was in dev". Put the current context in your shell prompt, or run kubectl config current-context before anything destructive.
Quality-of-life setup (2 minutes, saves hours)
$ echo 'alias k=kubectl' >> ~/.bashrc
$ echo 'source <(kubectl completion bash)' >> ~/.bashrc
$ echo 'complete -o default -F __start_kubectl k' >> ~/.bashrc
$ source ~/.bashrc
Now k get no<TAB> completes to k get nodes. On zsh, use kubectl completion zsh instead.
The single most useful command you'll learn is kubectl explain: built-in documentation for every field, matched to your cluster's version.
$ kubectl explain pod.spec.containers.image
KIND: Pod
VERSION: v1
FIELD: image <string>
DESCRIPTION:
Container image name. More info:
https://kubernetes.io/docs/concepts/containers/images
Try it: break it and rebuild it
- Delete the cluster:
kind delete cluster --name lab - Run
kubectl get nodes. Read the error carefully. What is kubectl complaining about? - Recreate it with the same
kind create clustercommand.
You've just learned that clusters are cattle, not pets: rebuildable from a file. That idea runs through everything in platform engineering.
Going deeper: what's inside a kind node
Run docker exec -it lab-control-plane bash. You're now "on" the control-plane node. Try crictl ps (containers the kubelet is running), ls /etc/kubernetes/manifests (the control plane runs as static pods), and systemctl status kubelet. It's a real kubeadm-built node, which makes kind excellent for practising kubeadm upgrades, certificate rotation and static-pod debugging before you touch real servers.
Recap
- kind gives you a real, multi-node Kubernetes cluster inside Docker, for free.
- kubectl talks to the cluster's API server using the kubeconfig.
- A context = cluster + user. Always know which one you're in.
- Rebuilding is cheap, so experiment boldly.
This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.