Kind Installation and Cluster Configuration
SummaryStep-by-step installation of Docker, kubectl, and Kind. Detailed...
Step-by-step installation of Docker, kubectl, and Kind. Detailed...
Step-by-step installation of Docker, kubectl, and Kind. Detailed walkthrough of a 3-node kind-cluster.yaml with port mappings, kubeadmConfigPatches, and node labels. Covers cluster lifecycle, image loading, and verification.
Kind Installation and Cluster Configuration
A working local cluster is the foundation of every exercise in this book. This section takes you from zero to a fully operational 3-node Kubernetes cluster running inside Docker containers, with ingress ports mapped to your host machine.
Installing Docker
Kind runs Kubernetes nodes as Docker containers, so Docker is the first dependency. If Docker is already installed and running (docker ps returns without error), skip ahead to kubectl.
On Ubuntu/Debian:
# Remove old versions
sudo apt-get remove docker docker-engine docker.io containerd runc 2>/dev/null
# Install prerequisites
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker Engine
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin
# Allow your user to run Docker without sudo
sudo usermod -aG docker $USER
newgrp docker
On macOS, install Docker Desktop from https://docs.docker.com/desktop/install/mac-install/. On Windows, install Docker Desktop with WSL2 backend enabled.
Verify the installation:
docker run --rm hello-world
You should see “Hello from Docker!” confirming that the Docker daemon is running and your user has permission to interact with it.
Installing kubectl
kubectl is the command-line tool for interacting with Kubernetes clusters. The CKAD exam provides kubectl pre-installed, but you need it locally to practice.
# Download the latest stable release
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
# Install it
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
# Verify
kubectl version --client
Expected output (version numbers will vary):
Client Version: v1.30.2
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Exam relevance: The exam environment provides a specific
kubectlversion. Always checkkubectl version --clientat the start of the exam to know what flags and features are available.
Installing Kind
Kind is a single Go binary. Installation is one command:
# For Linux amd64
[ $(uname -m) = x86_64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.24.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
# Verify
kind version
For macOS with Homebrew:
brew install kind
For other platforms or the latest version, check https://kind.sigs.k8s.io/docs/user/quick-start/#installation.
Understanding What Kind Does
When you run kind create cluster, Kind does the following:
- Pulls a node image. This is a Docker image (
kindest/node:v1.30.0) that containskubelet,kubeadm, a container runtime (containerd), and all Kubernetes system components. - Starts Docker containers. Each “node” in your cluster is a Docker container running this image. The container runs
systemd, which startskubelet, which runs Kubernetes system Pods. - Bootstraps the cluster with kubeadm. Inside the containers,
kubeadm init(on the control-plane) andkubeadm join(on workers) execute the same bootstrap process used on real machines. - Writes a kubeconfig. Kind generates a kubeconfig file and merges it into your
~/.kube/config, setting it as the current context.
The result: kubectl commands you run on your host talk to the Kubernetes API server running inside the control-plane container. From Kubernetes’ perspective, each container is a node. From Docker’s perspective, they are containers. This duality is what makes Kind lightweight — no virtual machines, no hypervisors, no cloud bills.
The Cluster Configuration File
A default kind create cluster gives you a single-node cluster. For CKAD prep, you need multiple nodes. Create a file called kind-cluster.yaml:
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
- containerPort: 443
hostPort: 443
- role: worker
- role: worker
Let’s break this down field by field.
kind: Cluster and apiVersion
This is a Kind-specific resource, not a Kubernetes resource. The apiVersion: kind.x-k8s.io/v1alpha4 tells Kind which configuration schema to use. This has nothing to do with the Kubernetes API version running inside the cluster.
nodes
An array defining the cluster topology. Each entry creates one Docker container that acts as a Kubernetes node. This configuration creates three nodes:
- One
control-planenode running the API server, etcd, controller-manager, and scheduler - Two
workernodes where your application Pods will be scheduled
kubeadmConfigPatches
This injects configuration into the kubeadm init process on the control-plane node. The patch adds a label ingress-ready=true to the control-plane node. This label is used by the NGINX Ingress Controller’s DaemonSet to know which node should receive external traffic.
The kubeletExtraArgs field passes arguments directly to the kubelet process on the node. The node-labels argument sets labels on the node at registration time — before any workloads are scheduled.
extraPortMappings
This maps ports from the Docker container to your host machine. When traffic arrives at localhost:80 on your host, Docker forwards it to port 80 on the control-plane container. This is how you access Ingress resources from your browser or curl.
Without port mappings, services inside the cluster are unreachable from your host unless you use kubectl port-forward. Port mappings give you a more realistic networking setup that mirrors production ingress flows.
Creating the Cluster
With kind-cluster.yaml saved, create the cluster:
kind create cluster --config kind-cluster.yaml --name ckad-lab
Kind will:
- Pull the
kindest/nodeimage (first time only, ~900MB) - Create three Docker containers
- Bootstrap the control-plane with
kubeadm init - Join the two worker nodes with
kubeadm join - Install the CNI (kindnet) for Pod networking
- Write the kubeconfig to
~/.kube/config
Expected output:
Creating cluster "ckad-lab" ...
✓ Ensuring node image (kindest/node:v1.30.0) 🖼
✓ Preparing nodes 📦 📦 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
✓ Joining worker nodes 🚜
Set kubectl context to "kind-ckad-lab"
You can now use your cluster with:
kubectl cluster-info --context kind-ckad-lab
Verifying the Cluster
Run the following commands to confirm everything is working:
# Check the current context
kubectl config current-context
# Expected: kind-ckad-lab
# List all nodes
kubectl get nodes
Expected output:
NAME STATUS ROLES AGE VERSION
ckad-lab-control-plane Ready control-plane 45s v1.30.0
ckad-lab-worker Ready <none> 30s v1.30.0
ckad-lab-worker2 Ready <none> 30s v1.30.0
All three nodes should show STATUS: Ready. If a node shows NotReady, wait 30 seconds and check again — the kubelet may still be initializing.
Check system Pods:
kubectl get pods -n kube-system
You should see Pods for coredns, etcd, kube-apiserver, kube-controller-manager, kube-proxy, kube-scheduler, and kindnet. All should be Running or Completed.
Verify the control-plane node has the ingress label:
kubectl get nodes --show-labels | grep ingress-ready
You should see ingress-ready=true in the labels of the control-plane node.
Loading Docker Images into Kind
Kind clusters run inside Docker and have their own container image registry that is separate from your host’s Docker daemon. When you build a Docker image locally, it exists in your host’s Docker image cache — but Kind’s nodes cannot see it. You need to explicitly load images into Kind.
# Build an image on your host
docker build -t my-app:v1 .
# Load it into the Kind cluster
kind load docker-image my-app:v1 --name ckad-lab
After loading, any Pod in the cluster can use image: my-app:v1 with imagePullPolicy: Never or imagePullPolicy: IfNotPresent. Without loading the image first, the Pod will fail with ErrImagePull because Kind’s nodes cannot pull from your host’s Docker daemon.
Tip: When testing with locally-built images, always set
imagePullPolicy: IfNotPresentin your Pod spec. The default pull policy forlatesttags isAlways, which will try to reach a remote registry and fail.
Verify an image was loaded:
docker exec -it ckad-lab-control-plane crictl images | grep my-app
This runs crictl (the container runtime CLI) inside the control-plane container to list its local images.
Resetting the Cluster
When you want a clean slate — maybe you broke networking, filled up etcd, or want to test a fresh setup:
# Delete the cluster
kind delete cluster --name ckad-lab
# Recreate it
kind create cluster --config kind-cluster.yaml --name ckad-lab
The entire cycle takes under 60 seconds. Keep your kind-cluster.yaml file in a consistent location (the book uses ~/ckad-lab/kind-cluster.yaml) so recreation is always one command away.
Exam strategy: In the real exam, you do not control cluster creation. But the habit of destroying and rebuilding builds confidence — you learn that Kubernetes state is reproducible from manifests. If you store your YAML files, you can recreate any workload in seconds. That mindset is critical when you are under time pressure.
Multiple Clusters
Kind supports running multiple clusters simultaneously. Each cluster is a separate set of Docker containers with its own kubeconfig context:
# Create a second cluster
kind create cluster --name ckad-practice
# List clusters
kind get clusters
# Switch between clusters
kubectl config use-context kind-ckad-lab
kubectl config use-context kind-ckad-practice
This is useful for simulating multi-cluster exam scenarios, though for most CKAD prep a single 3-node cluster is sufficient.
Summary
You now have three tools installed (Docker, kubectl, Kind) and a 3-node Kubernetes cluster running locally. The cluster has a control-plane node with ingress port mappings and two worker nodes — enough to practice node selectors, affinity rules, taints, tolerations, and multi-replica deployments. You know how to create, verify, load images into, and destroy clusters. The next section configures your shell for maximum speed.