I'm running an IPv6-only Kubernetes cluster on-premises with globally routable addresses, BGP available, and Cilium as the CNI. Because of a temporary networking limitation in my KVM/OVN setup, I can't currently advertise service addresses directly from the cluster or rely on IPv6 NDP and gratuitous solicitations working correctly. For now, traffic has to bind to the first address on the Kubernetes hosts.
I need an external system to provide L4 load balancing to Kubernetes NodePorts, track eligible worker nodes, perform health checks, and handle services exposed as type LoadBalancer. My current idea is to run a highly available HAProxy fleet on separate VMs and build a controller in the Cluster API management cluster that watches workload-cluster Services, mirrors their configuration into HAProxy, and manages address allocation. Local anycast DNS may also be part of the design.
Does an existing project support this model, or is a small custom controller plus HAProxy the most practical solution? This is intended as a two- or three-month workaround; afterward, I plan to fix the underlying network design and use Cilium's BGP-based service advertisement directly.
2 Answers
For a short-lived stopgap, an external HAProxy pair or fleet with a small Kubernetes-aware controller is a reasonable approach. Watch Node and Service changes from the management plane, generate HAProxy backends for the Kubernetes API and the relevant NodePorts, and use health checks so failed workers are removed automatically. Keep the controller deliberately narrow and treat it as temporary infrastructure rather than trying to reproduce all of a full in-cluster load-balancer implementation.
If the network path allows it, tools such as MetalLB, kube-vip, or Cilium’s own service advertisement can provide this functionality from inside the cluster. They can announce service addresses and direct traffic to healthy nodes, but they won’t solve a situation where the hypervisor or OVN layer prevents the required IPv6 neighbor discovery and routing behavior.
That’s the eventual direction. My current OVN setup uses directly attached ports for the Kubernetes VMs, but IPv6 NDP updates and gratuitous solicitations aren’t working reliably. I need an external workaround until I can revisit the hypervisor and network architecture.

That’s essentially what I implemented. The operator runs alongside Cluster API, updates HAProxy when nodes change, and currently balances the Kubernetes API on port 6443 plus the Cilium gateway traffic on ports 80 and 443. It’s working well enough to get workloads online while we plan the longer-term move to direct Cilium BGP advertisements.