Conversation
A balancer was found only by its name, and without the robotlb/balancer annotation that name was the service name without the namespace. Services with the same name in two namespaces shared one balancer, overwrote each other's ports and targets, and releasing one deleted the other's. Any balancer whose name a service resolved to, including one named in the annotation, could be reconfigured or deleted, even one robotlb never created. New balancers are named <service>.<namespace> and carry the robotlb/service-uid label from the create request on. The balancer of a service is found by that label, and only a labelled balancer is changed or deleted. A release never goes by name, so a service released again cannot hit a balancer another service created under the old name since. The label replaces the robotlb/balancer-id annotation, which recorded the balancer ID for the release: the label identifies the balancer the same way, cannot go stale between creating a balancer and recording it, and saves a patch of the service. The annotation was never released. Balancers from earlier releases have no label. A reconcile adopts an unlabelled balancer under the old name or the name the service asks for only when every target is an IP and one of them is a node of the service, so a balancer pointing at other hosts is never taken over. While the service has no target nodes, an unlabelled balancer with IP targets cannot be judged, and the service waits with a warning event instead of replacing it. Otherwise, under the old name a balancer that is not adopted is skipped, and the service gets a new balancer under <service>.<namespace> without an event. Under the name the service asks for it is left alone with a warning event: one labelled for another service names that service's UID, an unlabelled one names the command to hand it over. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la>
This was referenced Sep 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
robotlb now tells its own balancers apart from everything else in the Hetzner project, and a Service can no longer land on a balancer another Service uses.
New balancers get the namespace in their default name and an ownership label. Without the
robotlb/balancerannotation the name is<service>.<namespace>. Both parts are DNS labels without dots, so the name is at most 127 characters (Hetzner allows 128) and can't collide with a name from an earlier release. The create request sets therobotlb/service-uidlabel. hcloud-cloud-controller-manager uses the same scheme withhcloud-ccm/service-uid.robotlb finds a Service's balancer by that label and changes or deletes only a balancer labelled for that Service. A release never looks a balancer up by name. So a Service released again can't delete a balancer another Service has since created under its old name.
The label also replaces the balancer ID annotation from #47. It identifies the balancer the same way, can't go stale between creating the balancer and recording its ID, and saves a patch of the Service.
robotlb/balancer-idwas never released, so it is removed.Balancers from earlier releases have no label, so a reconcile adopts them when they look like the Service's own. The check applies to an unlabelled balancer under the old name or the name the Service asks for: every target must be an IP, and at least one of them a node of the Service. robotlb adds the label and keeps the name and any labels the balancer already has. Adopting only balancers with no labels at all would be stricter, but a balancer someone labelled by hand would then be replaced by a new one with a new IP. While the Service has no target nodes, the check can't be made, and the Service waits with a warning event instead of replacing the old balancer with a new one and a new IP.
Any other balancer is never touched. Under the old name robotlb skips it, and the Service gets a new balancer under
<service>.<namespace>without an event. Under the name the Service asks for, the Service gets a warning event instead:hcloud load-balancer add-labelcommand to hand it over.Two balancers matching one Service now also produce an event instead of a silent skip.
Some behaviour changes, and the README upgrade notes cover each of them:
robotlb/balancerafter creation doesn't rename the balancer or create a new one.LoadBalancerbefore its first successful reconcile on this release stays in the project and keeps being billed. That includes the Services fix(service): release the balancer when a service stops needing it #47 releases on the first start.hcloud load-balancer list --selector '!robotlb/service-uid'lists them.Some risk remains. Someone who can edit a Service in the cluster can still take over an unlabelled balancer that already targets the cluster's nodes. That is either another robotlb balancer that hasn't been migrated yet, until its own Service reconciles, or a balancer someone made by hand for this cluster. Two clusters in one project with overlapping private subnets can also match each other's unlabelled balancers. Before this change, any of those was taken by name alone.
Stacked on #57.
Closes #41
Closes #43