HA Kubernetes Cluster Playground
A multi-node, highly available Kubernetes cluster provisioned with kubeadm.
๐ Overview
This playground provides a complete HA Kubernetes cluster with:
- 3 Control Plane Nodes:
cplane-01,cplane-02,cplane-03 - 1 Worker Nodes:
worker-01 - IP Failover: Keepalived for moving the virtual IP address between control plane nodes
๐ ๏ธ Tools
kubectl(alias:k): Kubernetes cluster management and debuggingnerdctl: Docker-compatible CLI forcontainerdkrew:kubectlplugin manager for extending functionality
๐ฅ Testing High Availability and Failover
One of the key benefits of an HA cluster is its resilience to node failures. Here are several tests you can perform to verify your cluster's fault tolerance:
Test 1: Control Plane Node Failure
Figure out which control plane node is active
# On each control plane node
ip a | grep inet | grep vip
# If you see the VIP address, it means the node is active
Stop kubelet on the Active Control Plane Node
# On the active control plane node (e.g., cplane-02)
sudo systemctl stop kubelet
# From another node, verify the cluster still functions
kubectl get nodes
kubectl get pods --all-namespaces
# The failed node should show as "NotReady" (may take a few minutes)
# but the cluster should remain operational
Stop API Server Container
# On the same control plane node, stop the API server container
# List containers in the k8s.io namespace
nerdctl --namespace k8s.io ps
# Stop the API server containers
nerdctl --namespace k8s.io stop $(nerdctl --namespace k8s.io ps -a --format "{{json .}}" | jq -r --arg name "k8s://kube-system/kube-apiserver-$(hostname)" 'select(.Names == $name or .Names == $name+"/kube-apiserver") | .ID')
# Verify from another node that the API is still accessible
kubectl cluster-info
kubectl get componentstatuses
# Find the new active control plane node
ip a | grep inet | grep vip
Recovery
# Start kubelet service
sudo systemctl start kubelet
# Verify node returns to Ready state
kubectl get nodes
Test 2: Worker Node Failure
# Deploy a test application
kubectl create deployment podinfo --image=ghcr.io/stefanprodan/podinfo --port=9898
# Figure out which node the pod is running on
kubectl get pods -o wide
# Stop kubelet on that worker node
sudo systemctl stop kubelet
# Watch pods get rescheduled to other nodes (it may take a few minutes)
kubectl get pods -o wide --watch
# Pods should be automatically rescheduled to healthy worker nodes
๐งฉ Related Content
๐งช Playgrounds
- Kubernetes Playgrounds (official)
- Kubernetes Cluster (official)
- kubeadm
Happy learning! ๐
A real VM, not a container
Get root on a VM with its own kernel, so Docker, Kubernetes, and systemd just work.
Read the docs โ
SSH from browser or CLI
Use the built-in web terminal, or connect with labctl ssh, plain ssh, scp, or rsync.
Read the docs โ
Drive it with AI
Let Claude, Codex, or any MCP client start this playground and run commands in it.
Read the docs โ
Expose HTTP(S) ports
Give any web app running inside the VM a public URL - for yourself or to share with others.
Read the docs โ
Share terminals
Invite others into your terminal session, or open it yourself from another device.
Read the docs โ
Customize with init scripts
Add shell scripts that run at boot to install packages, clone repos, or seed test data.
Read the docs โ
Private networking
VMs reach the internet via NAT with no public IP; several VMs share bridge networks.
Read the docs โ
Ephemeral or persistent
By default, VMs are destroyed when the session ends; enable persistence to keep the disks for next time.
Read the docs โ
Built-in container registry
A private registry.iximiuz.com for every playground to share images across services and VMs.
Read the docs โ