Logo
Engineering

Wie wir API-Anfragen im Hetzner Cloud Controller Manager reduziert haben

30. Juli 20268 min Lesedauer
Hero-API-Abfragen-Hero-Hetzner-Blog.webp
Zurück zur Übersicht
Die vier Controller im HCCM
Gemeinsamer Cache für die Node Controller
Beginnen wir mit dem Routes Controller
Upstream-Mitarbeit
Auswirkungen messen
Fazit

In diesem Artikel

  • Die vier Controller im HCCM
  • Gemeinsamer Cache für die Node Controller
  • Beginnen wir mit dem Routes Controller
  • Upstream-Mitarbeit
  • Auswirkungen messen
  • Fazit

In diesem Artikel

  • Die vier Controller im HCCM
  • Gemeinsamer Cache für die Node Controller
  • Beginnen wir mit dem Routes Controller
  • Upstream-Mitarbeit
  • Auswirkungen messen
  • Fazit
TL:DR
Der "hcloud-cloud-controller-manager" (HCCM) verbindet Kubernetes® mit der Hetzner Cloud und Robot und ordnet Cluster-Ressourcen den entsprechenden Servern, Routes und Load Balancern zu. Dabei lösten sie bislang mehr API-Abfragen aus als nötig – insbesondere beim Hinzufügen oder Entfernen von Nodes und durch regelmäßige Route Checks, selbst wenn sich im Cluster nichts geändert hatte. Ein gemeinsamer Cache stellt Serverdaten nun mehreren Controllern bereit, sodass nicht mehr jeder Server einzeln über die API abgefragt werden muss. Gleichzeitig aktualisiert der Routes Controller die Routen hauptsächlich dann, wenn relevante Ereignisse auftreten, statt sie kontinuierlich in festen Zeitabständen zu prüfen. Dadurch sinkt die Zahl der Anfragen an die Hetzner Cloud API beim Hochskalieren um etwa 76 Prozent und im Steady State um 94 Prozent. Die Änderung am Routes Controller wurde als Upstream Contribution in Kubernetes eingebracht; hccm v1.33 enthält alle beschriebenen Verbesserungen.

Der "hcloud-cloud-controller-manager" (HCCM) bildet die Schnittstelle zwischen deinem Kubernetes-Cluster und den APIs von der Hetzner Cloud und Robot. HCCM implementiert die Schnittstellen, die Kubernetes im Paket "k8s.io/cloud-provider" vorgibt. Über diese Schnittstellen können Cloud-Anbieter ihre anbieterspezifischen Funktionen in die gemeinsamen Kubernetes-Controller integrieren. In HCCM übernehmen vier dieser Controller die zentralen Aufgaben.

Die vier Controller im HCCM

Der Node Controller initialisiert jeden Kubernetes-Node und hinterlegt dabei Metadaten wie den Instanztyp und, ganz wichtig, die Provider-ID. Diese entspricht der ID des zugehörigen Hetzner Cloud Servers oder Robot Servers und beginnt mit "hcloud://" oder "hrobot://". Itie Provider-ID ist unveränderlich und stellt die eindeutige Verbindung zwischen einem Kubernetes-Node und dem entsprechenden Server in der API her. Neben der Initialisierung aktualisiert der Node Controller regelmäßig den Status der Nodes. Standardmäßig läuft diese Aktualisierung alle fünf Minuten. Das Intervall lässt sich mit "--node-status-update-frequency"anpassen. Für einen noch nicht initialisierten Node ist kein API-Aufruf erforderlich. Jeder bereits initialisierte Node führt dagegen zu einem Aufruf von "InstanceV2.InstanceMetadata".

Der Node Lifecycle Controller überwacht Kubernetes-Nodes, die nicht mehr als "ready" gelten. Standardmäßig prüft er alle fünf Sekunden, ob ein solcher Node beim Cloud-Provider noch existiert und ob der zugehörige Server heruntergefahren wurde. Ist der Server ausgeschaltet, versieht der Controller den Node mit einem entsprechenden Taint. Existiert der zugehörige Hetzner Cloud Server oder Robot Server nicht mehr, löscht er das Node-Objekt aus Kubernetes.

Der Routes Controller legt für jeden Node eine Route im privaten Netzwerk an. Dabei ordnet er das Pod-CIDR des jeweiligen Kubernetes-Nodes seiner privaten IP-Adresse zu. Hat node-1 beispielsweise die private IP-Adresse "10.0.0.2" und das Pod-CIDR "10.244.0.0/24", erstellt der HCCM folgende Route: "10.244.0.0/24 → 10.0.0.2". Datenverkehr, der für einen beliebigen Pod auf node-1 bestimmt ist, wird dadurch über das Private Network direkt an diesen Node weitergeleitet. So entfällt der zusätzliche Overhead eines Overlay-Netzwerks wie VXLAN.

Der Service Controller erstellt und konfiguriert schließlich für jeden Kubernetes-"Service" vom Typ "LoadBalancer" einen Hetzner Cloud Load Balancer.

Alle vier Controller kommunizieren mit den Hetzner-APIs. Die dabei entstehenden Anfragen werden auf das Rate Limit des jeweiligen Accounts angerechnet. Ziel der im Folgenden beschriebenen Arbeiten war es daher, unnötige API-Anfragen zu reduzieren, ohne dabei Abstriche bei der korrekten Funktionsweise zu machen.

Gemeinsamer Cache für die Node Controller

Content-API-Abfragen-Cache-Hetzner-Blog.webp
Content-API-Abfragen-Cache-Hetzner-Blog.webp

Zuerst haben wir uns den Node Controller und den Node Lifecycle Controller vorgenommen. Beide basieren auf der "InstanceV2"-Schnittstelle des Cloud-Providers. Darüber lassen sich die Metadaten eines Nodes abrufen ("InstanceMetadata") und prüfen, ob der zugehörige Server heruntergefahren wurde ("InstanceShutdown") und ob er überhaupt noch existiert ("InstanceExists").

Bei Skalierungsvorgängen erzeugen diese Controller besonders viele API-Anfragen. Der Node Controller erzeugt sowohl beim Hoch- als auch beim Herunterskalieren viel Traffic, und der node Lifecycle Controller sorgt für zusätzliche Anfragen. Besonders aktiv wird der Lifecycle Controller, wenn mehrere Nodes gleichzeitig heruntergefahren werden: Alle fünf Sekunden prüft er für jeden Node zunächst, ob dieser noch existiert ("InstanceExists"). Falls ja, prüft er anschließend, ob er heruntergefahren wurde ("InstanceShutdown"). Da die beiden Methoden nacheinander aufgerufen werden, sind für jede Prüfung zwei API-Anfragen nötig. Genau bei diesem wiederkehrenden Muster zahlt sich ein Cache aus.

Auch beim Hochskalieren werden Informationen zu jedem Kubernetes-Node benötigt. Daraus ergab sich ein konkreter Ansatz: Der Cache ruft alle Server mit einer einzigen Anfrage ab, speichert die Daten für einen konfigurierbaren Zeitraum und aktualisiert sie gemeinsam, statt jeden Server einzeln abzufragen. Der Routes Controller verfügte bereits über einen solchen Cache. Wir haben ihn deshalb an unsere Anforderungen angepasst und so umgebaut, dass ihn mehrere Controller gemeinsam nutzen können.

Die standardmäßige Time to Live (TTL) beträgt zehn Sekunden und lässt sich anpassen. Auch die Cache-Strategie ist konfigurierbar: Statt alle Server auf einmal abzurufen, kann der Cache jeden Server einzeln laden und speichern. Standardmäßig rufen wir jedoch alle Server gemeinsam ab, da sich die Zahl der API-Anfragen nur durch diese gebündelte Anfrage deutlich reduzieren lässt.

Dadurch greifen Aktivitätsspitzen, die zuvor eine große Zahl einzelner API-Aufrufe ausgelöst haben, nun auf einen gemeinsamen und regelmäßig aktualisierten Datenbestand aller Server im Cluster zu. So bleibt der HCCM auch bei laufenden Änderungen am Cluster deutlich innerhalb der Rate Limits des Accounts.

Beginnen wir mit dem Routes Controller

Als Nächstes haben wir uns den Routes Controller vorgenommen. Er gleicht die konfigurierten Routen in festen Zeitabständen ab. Der Upstream-Standard liegt bei zehn Sekunden, im HCCM beträgt das Intervall seit v1.14.2 jedoch 30 Sekunden. Das Problem: Bei jedem Abgleich ruft der Controller das private Netzwerk über die Hetzner Cloud API ab und liest dessen Routen aus – unabhängig davon, ob sich etwas geändert hat. Selbst in einem stabilen Cluster, in dem keine Änderungen stattfinden, verursacht der Controller dadurch mindestens alle 30 Sekunden eine API-Anfrage, ohne dass sie einen Nutzen bringt.

Der Routes Controller führt den Abgleich deshalb jetzt nur noch aus, wenn es dafür einen konkreten Anlass gibt: wenn Nodes hinzugefügt oder entfernt werden oder wenn sich bestimmte Eigenschaften eines Nodes ändern. Bei den vielen Clustern, die weitgehend unverändert bleiben und kein Autoscaling nutzen, entfallen diese kontinuierlichen, unnötigen Anfragen damit vollständig.

Als Sicherheitsmechanismus führen wir zusätzlich in regelmäßigen Abständen einen Abgleich durch. Das Intervall liegt zwischen zwölf und 24 Stunden und wird beim Start des Controllers zufällig festgelegt.

Content-API-Abfragen-ticks-Hetzner-Blog.svg
Content-API-Abfragen-ticks-Hetzner-Blog.svg

Upstream-Mitarbeit

Es gab eine Komplikation bei der Änderung am Routes Controller: Der zugrunde liegende Code gehört nicht uns. Der Routes Controller ist Teil des gemeinsam gepflegten Kubernetes-Upstream-Projekts und fällt dort in den Zuständigkeitsbereich der SIG Cloud Provider. Diese Special Interest Group betreut die Schnittstellen, auf denen alle Cloud-Integrationen aufbauen. Eine Änderung am Verhalten des Controllers betrifft damit alle Anbieter, die dieselben Controller verwenden. Eine solche Anpassung lässt sich deshalb nicht einfach mit einem Pull Request und einer schnellen Zustimmung umsetzen.

Wir stellten unseren Vorschlag im zweiwöchentlichen Meeting der SIG vor und stießen damit auf positive Resonanz. Andere Controller waren bereits auf einen ereignisbasierten Ansatz umgestellt worden, sodass das Grundprinzip bekannt war. Die Mitglieder freuten sich zudem, dass sich jemand bereit erklärte, dieses Thema anzugehen. Der Vorschlag wurde unter zwei Bedingungen angenommen: Wir mussten ein Kubernetes Enhancement Proposal erstellen und das neue Verhalten hinter einem Feature Gate absichern.

Content-API-Abfragen-Meeting-Hetzner-Blog.webp
Content-API-Abfragen-Meeting-Hetzner-Blog.webp

Beide Anforderungen zeigen gut, wie Kubernetes grundsätzlich mit Änderungen umgeht. Ein Kubernetes Enhancement Proposal, kurz KEP, dient dazu, neue Funktionen und größere Änderungen strukturiert vorzuschlagen und zu koordinieren. Das Dokument beschreibt unter anderem die Motivation, den technischen Entwurf, den Testplan und die Kriterien für die schrittweise Weiterentwicklung der Funktion. All das wird öffentlich geprüft, bevor die eigentliche Implementierung beginnt. Das Feature Gate soll dagegen das Risiko begrenzen. Ein ereignisbasierter Abgleich verändert das Verhalten von Code, auf den Dutzende Cloud-Anbieter angewiesen sind. Durch ein Feature Gate kann die neue Funktion zunächst deaktiviert ausgeliefert, kontrolliert aktiviert und bei Problemen wieder abgeschaltet werden. So wird das neue Verhalten niemandem aufgezwungen, der noch nicht bereit dafür ist.

Die größte Hürde war letztlich nicht die Idee selbst, sondern der damit verbundene formale Prozess: Wir mussten uns in die Vorlagen einarbeiten und die Dokumentation zu den einzelnen Schritten zusammensuchen. Aus dem Vorschlag entstand schließlich KEP-5237, das inzwischen in der Alpha-Phase in das Projekt aufgenommen wurde. Nach der Annahme konnten wir die Änderung implementieren. Seit HCCM v1.29.0 ist das zugehörige Feature Gate standardmäßig aktiviert.

Entscheidend für den erfolgreichen Abschluss war, kontinuierlich am Prozess beteiligt zu bleiben. Durch die Teilnahme an den zweiwöchentlichen Meetings und regelmäßige Updates zum Stand des KEP blieben die Mitglieder der SIG eingebunden. Dadurch konnten wir deutlich leichter Feedback, Reviews und schließlich die endgültige Freigabe erhalten. Während des gesamten Prozesses standen sie uns mit Rat und Tat zur Seite. Eine Erinnerung daran, dass es bei der Arbeit am Upstream-Projekt ebenso sehr darauf ankommt, regelmäßig präsent zu sein, wie auf den Code selbst.

Auswirkungen messen

Die folgenden Messungen berücksichtigen keine "GET /actions" -Aufrufe an die Hetzner Cloud API, da die Antwortzeit dieser Endpunkte von der Latenz anderer Ressourcen abhängt – zum Beispiel davon, wie lange das Anlegen einer Route in einem Private Network dauert.

Content-API-Abfragen-Scenario-Hetzner-Blog.webp
Content-API-Abfragen-Scenario-Hetzner-Blog.webp

Wir haben zwei Szenarien gemessen: zum einen das Hochskalieren von null auf zehn Workers bei einem einzelnen Control-Plane-Node, zum anderen einen sechsminütigen Zeitraum in einem bereits laufenden Cluster mit einem Control-Plane-Node und zehn Workers. Der Zeitraum von sechs Minuten wurde bewusst gewählt, damit die alle fünf Minuten ausgeführte Statusaktualisierungsschleife des Node Controllers während der Messung mindestens einmal läuft.

Die beiden Optimierungen wirken an unterschiedlichen Stellen. In einem statischen Cluster verursachen vor allem die zeitgesteuerten Abgleiche des Routes Controllers Traffic. Allein durch das Feature Flag sinkt die Zahl der Anfragen im Steady State deshalb von 31 auf 12. Beim Hochskalieren verändert das Feature Flag die Zahl dagegen kaum – von 114 auf 109 –, da diese Last von den Node Controllern und nicht vom Routes Controller ausgeht. In diesem Fall greift der gemeinsame Cache: Er fasst die einzelnen Abfragen pro Node in einer gebündelten Ansicht zusammen und reduziert den Traffic beim Hochskalieren auf 27.

Fazit

Die beiden Änderungen setzen bei den größten Quellen vermeidbarer API-Anfragen an: bei den zeitgesteuerten Abgleichen des Routes Controllers in inaktiven Clustern und bei den Abfragen einzelner Nodes durch die Node Controller während des Skalierens. Das Feature Flag sorgt dafür, dass statische Cluster keine unnötigen Anfragen verursachen, während der gemeinsame Cache Lastspitzen beim Skalieren abfängt. Zusammen reduzieren sie die Anfragen an die Hetzner Cloud API beim Hochskalieren um rund 76 Prozent und im Steady State um 94 Prozent, ohne die Funktionsweise der Controller zu verändern.

Wenn du alle genannten Funktionen haben möchtest, kannst du den HCCM version v1.33 nutzen.

Für weitere Informationen zum HCCM sieh dir das GitHub-Projekt an.

Engineering
Content-profile-Metzger-Lukas-Hetzner-Blog.webp

Lukas Metzner

Open Source Software Developer, Integrations

Artikel teilen
Logo
Abonnieren Sie unseren Newsletter

Abonnieren Sie unseren Newsletter

Hetzner
  • Unternehmen
  • Unsere Kunden
  • Nachhaltigkeit
  • neu
    Blog
  • Karriere
  • Pressroom
Support
  • Support Center
  • Kontakt
  • Downloads
  • Hetzner Docs
  • Status
Rechtliches
  • Impressum
  • Datenschutz
  • System Policies
  • AGB
  • Digital Services Act
  • Abuse-Formular

©2026 Hetzner Online GmbH. Alle Rechte vorbehalten. Preise