Contents

Kubernetes Control Plane Load Balancer with HAProxy on VyOS


Prerequisites

  • VyOS configured as per Setting Up VyOS as a Proxmox VM
  • Two or more Kubernetes control plane nodes reachable on the lab network
  • The control plane nodes’ lab IPs noted — these become the HAProxy backends

Why Load Balance the Control Plane

Each control plane node runs an instance of the Kubernetes API server on port 6443. Without a load balancer in front of them, every client — kubectl, worker nodes, internal services — must point directly at one control plane node. If that node goes down, the API becomes unreachable even though the other nodes are healthy.

A load balancer provides a single stable endpoint. Clients connect to one address; HAProxy distributes the connections across all healthy control plane nodes and removes a node from rotation automatically if its health check fails.

VyOS includes HAProxy support natively — no separate VM or LXC container is needed.

Official reference: VyOS HAProxy


Configuring HAProxy on VyOS

The Kubernetes API server uses plain TCP on port 6443. HAProxy is configured in TCP mode so it forwards connections without inspecting or terminating TLS — the API server handles TLS end-to-end.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
configure

# Frontend — listen for incoming API server connections
set load-balancing haproxy service k8s-api bind '0.0.0.0'
set load-balancing haproxy service k8s-api port '6443'
set load-balancing haproxy service k8s-api mode 'tcp'
set load-balancing haproxy service k8s-api backend 'k8s-control'

# Backend — the control plane nodes
set load-balancing haproxy backend k8s-control mode 'tcp'
set load-balancing haproxy backend k8s-control balance 'roundrobin'

set load-balancing haproxy backend k8s-control server ctrl-01 address '10.x.x.x'
set load-balancing haproxy backend k8s-control server ctrl-01 port '6443'
set load-balancing haproxy backend k8s-control server ctrl-01 check

set load-balancing haproxy backend k8s-control server ctrl-02 address '10.x.x.x'
set load-balancing haproxy backend k8s-control server ctrl-02 port '6443'
set load-balancing haproxy backend k8s-control server ctrl-02 check

set load-balancing haproxy backend k8s-control server ctrl-03 address '10.x.x.x'
set load-balancing haproxy backend k8s-control server ctrl-03 port '6443'
set load-balancing haproxy backend k8s-control server ctrl-03 check

commit
save
  • bind '0.0.0.0' — listens on all VyOS interfaces, including the VRRP virtual IP; connections always reach the active router regardless of which node holds the VIP
  • mode tcp — HAProxy forwards raw TCP without terminating TLS; the API server certificate is presented directly to the client
  • balance roundrobin — distributes new connections evenly across healthy backends
  • check — enables TCP health checks; a backend is removed from rotation if it stops responding

Verifying

From any lab host, confirm HAProxy is accepting connections on the VyOS IP:

1
curl -k https://10.x.x.1:6443/healthz

A response of ok means HAProxy forwarded the request to a healthy control plane node. The -k flag skips certificate verification — use your CA bundle if you have one deployed.

Check which backends are currently healthy from the VyOS operational mode:

1
show load-balancing haproxy

What’s Next

  • Setting Up a Kubernetes Cluster — initialising the cluster with this load balancer as the control plane endpoint
  • VRRP redundancy — adding a second VyOS instance so the load balancer itself has no single point of failure
  • BGP peering with Kubernetes — dynamically routing Kubernetes service IPs through VyOS