Build a Cloud-Style Fabric Lab, Part 7: Kubernetes

kubeadm the deliberate way: a load-balanced control-plane endpoint before anything else, stacked etcd split across leaf pairs, no kube-proxy by design, and the NotReady checkpoint that makes Part 8 make sense.
Fabric lab series, part 7: kubernetes

On this page

Six machines from Part 6 are on the fabric, bonded, addressed, and bored. This part turns them into a Kubernetes cluster: three control-plane nodes, three workers, a load-balanced API endpoint, and one deliberate act of restraint. We install no CNI and no kube-proxy, on purpose, so that when Cilium arrives in Part 8 you can see exactly what hole it fills rather than taking my word for it.

The endpoint comes before the cluster

The single most consequential line in a kubeadm HA build is decided before any node is touched: controlPlaneEndpoint. Every kubelet, every join, every kubeconfig will address the control plane through this value forever, and changing it later is somewhere between painful and rebuild-the-cluster. So it must be a name, never a node's address, and something has to answer on that name that outlives any single master.

Control plane anatomy: api.ocp.lab resolves to haproxy on the services node, which balances across three masters running stacked etcd, with the CNI deliberately missing
One name, two front doors, three brains, and a deliberately missing pod network.

Here that name is api.ocp.lab, and today it answers with two addresses. Each one runs haproxy in TCP mode, round-robin, health checking all three apiservers, so a master dying is something haproxy absorbs and no kubelet notices. I started with a single load balancer, which was the smallest possible HA front end and also the lab's one honest single point of failure, and later gave the name a second A record pointing at a second haproxy on another box. The two reach the masters by deliberately different paths, one across the fabric and one over the management network, so they do not share a failure. That upgrade cost nothing at the cluster level, and that is the entire argument for making the endpoint a name:

kube-proxy daemonset not found, api.ocp.lab resolving to the services node, and the haproxy backend balancing the three masters with health checks
One name answering with two load balancers that fail independently, and the daemonset that was never installed.

This post is for subscribers only

Subscribe to LevelUp I.T. newsletter and stay updated.

Don't miss anything. Get all the latest posts delivered straight to your inbox. It's free!
Great! Check your inbox and click the link to confirm your subscription.
Error! Please enter a valid email address!