learnclaude .dev
← Kubernetes Operators, Istio, Incident Response & AI

Lesson 5 of 16

Bootstrap the lab cluster

doc

We need a multi-node cluster so later lessons can simulate node-level failures (drain a worker, corrupt a kubelet, watch the operator react). One node is not enough.

Working directory check

Every command in this lesson runs from ~/incident-cluster/ — the workspace you set up in the previous lesson. If your terminal is somewhere else:

cd ~/incident-cluster

The cluster config

Create kind-incident.yaml in ~/incident-cluster/:

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: incident-lab
nodes:
  - role: control-plane
  - role: worker
  - role: worker

Three things this declares:

  • kind: Cluster here is the kind CLI's schema, not Kubernetes's — kind borrows the API-style format on purpose, but the Cluster resource is parsed by the kind binary itself.
  • name: incident-lab becomes the kubectl context name (kind-incident-lab) and the prefix for every node container.
  • Three nodes — one control plane and two workers — each backed by a Docker container running kubeadm inside.

Create it

kind create cluster --config kind-incident.yaml
kubectl cluster-info --context kind-incident-lab

First run pulls the kindest/node image (~1GB) and takes a couple of minutes. Subsequent runs are seconds.

What's actually running

Open a second terminal:

docker ps --format '{{.Names}}\t{{.Image}}'

You'll see three containers: incident-lab-control-plane, incident-lab-worker, incident-lab-worker2, all running kindest/node:v1.35.0. Inside each, kubeadm has bootstrapped a real Kubernetes node — etcd on the control plane, kubelet everywhere, CNI plugged in.

The mental model:

┌───────── your laptop ─────────┐
│ ┌─────────────────────────┐   │
│ │  Docker daemon          │   │
│ │  ┌──────────────────┐   │   │
│ │  │ control-plane    │◄──┼───┼── kubectl talks here
│ │  └──────────────────┘   │   │   (port-forwarded to localhost)
│ │  ┌──────────────────┐   │   │
│ │  │ worker           │   │   │
│ │  └──────────────────┘   │   │
│ │  ┌──────────────────┐   │   │
│ │  │ worker2          │   │   │
│ │  └──────────────────┘   │   │
│ └─────────────────────────┘   │
└───────────────────────────────┘

kubectl is talking to the API server inside the control-plane container; pods in the cluster will land on either of the two worker containers. They share a Docker network so cluster networking just works.

Acceptance test

kubectl get nodes

You should see three Ready nodes — one control-plane (with control-plane in the ROLES column) and two workers. If a node is NotReady, give it ~30 seconds; the kubelet may still be coming up.

The cluster is disposable

We'll cover the full teardown (cluster + port-forward + Docker Desktop) at the end of this section — until then, leave the cluster running. But internalise the principle now: this thing is meant to be thrown away. When something gets weird in a later lesson, deleting and recreating is a legitimate first move, not a defeat. Recreating from the config you just wrote takes seconds because the node image is cached in Docker.

View source documentation →