Tune health checks for node replacement
Load balancer health checks matter more on Syself Autopilot than on a platform that patches nodes in place, because here nodes are drained and replaced during every upgrade and every self-healing event. The health check is what tells the Hetzner load balancer to stop sending traffic to a node that is going away. Tune it so a leaving node drops out of the target pool before its pods stop answering.
What happens on a node swap#
When the platform replaces a node, the load balancer must notice the old node is gone and register the new one. That registration is not instant. For a few seconds the load balancer may still send traffic to the node that is leaving, or not yet send it to the replacement. During that window, requests that land on the leaving node fail unless another node can serve them.
Two measures close that window: a health check that drops the leaving node quickly, and enough healthy replicas elsewhere to take the traffic.
The health-check annotations#
Set these on the type: LoadBalancer Service (or on the ingress controller's Service). Pick the check protocol first, then the timing.
An http (or https) check calls a path and expects a success status, so it follows the application's readiness. A node whose pod is failing leaves the pool even while its port is still open. Use this whenever the application has a health endpoint.
metadata:
annotations:
load-balancer.hetzner.cloud/health-check-protocol: http
load-balancer.hetzner.cloud/health-check-http-path: /healthz
load-balancer.hetzner.cloud/health-check-interval: "3s"
load-balancer.hetzner.cloud/health-check-timeout: "2s"
load-balancer.hetzner.cloud/health-check-retries: "2"
A tcp check only opens the port. It is the default and requires no path, but it cannot distinguish a hung application from a healthy one as long as the port still accepts connections. Use it for non-HTTP backends.
metadata:
annotations:
load-balancer.hetzner.cloud/health-check-protocol: tcp
load-balancer.hetzner.cloud/health-check-interval: "3s"
load-balancer.hetzner.cloud/health-check-timeout: "2s"
load-balancer.hetzner.cloud/health-check-retries: "2"
- Write
intervalandtimeoutwith a time unit. Use"15s"for 15 seconds or"1m30s"for a minute and a half. A plain number such as15is rejected, and the Service fails to reconcile. - A shorter
intervaland fewerretriesdrop a failing node from the pool sooner, which shrinks the swap window. Do not set them so aggressively that a single slow response ejects a healthy node.
The full annotation set, and the rest of what a Service load balancer exposes, is in Configure a load balancer .
Keep enough replicas to absorb the traffic#
A tight health check alone is not enough. The traffic a leaving node drops must go somewhere:
- Run at least two replicas of the exposed workload.
- Spread them across nodes with a topology spread constraint, so one node drain never removes them all.
- Add a PodDisruptionBudget so the drain cannot evict the last ready replica.
For the full sequence during an upgrade, both hops that external traffic takes, see Keep ingress and load balancers available . For why nodes are replaced rather than patched, see Self-healing and node replacement .
Note
With externalTrafficPolicy: Local, the load balancer already health-checks each node for a local ready pod and stops sending to a node that has none. That interacts with the settings here; see Preserve the client source IP .
Configure a Hetzner load balancer
Tune the control-plane load balancer with topology variables and per-Service load balancers with annotations, including the full annotation reference.
Enable PROXY protocol
Turn on PROXY protocol so the load balancer forwards the real client IP, and configure the backend to read it.