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.

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:
