Chris McGrath von DoiT führt uns durch den Kubernetes AWS LB Controller und erklärt, wie er hinter den Kulissen funktioniert.

BLUF
In der Kubernetes-Community gibt es eine Konvention: Was direkt in Kubernetes eingebaut ist, trägt kubernetes.io im Namen, Kubernetes-Add-ons hingegen nicht. Add-ons folgen meist einer selbsterklärenden Konvention wie ebs.csi.aws.com, an der man intuitiv erkennt, dass es sich um ein Add-on handelt. Das Add-on aws-load-balancer-controller bricht mit dieser etablierten Konvention.
Zielgruppe
Dieser Artikel richtet sich an drei Zielgruppen mit jeweils eigenem Zweck:
1. Kubernetes-Admins, die EKS oder generische Kubernetes-Distributionen auf AWS betreiben: Sie müssen den Artikel nicht zwingend lesen, ich empfehle aber, ihn als Lesezeichen zu speichern und im Hinterkopf zu behalten – als Referenz für den Fall, dass Sie jemals AWS-Load-Balancer-Provisionierung über Kubernetes Services mit Annotationen wie service.beta.kubernetes.io/aws-load-balancer-* debuggen müssen.
2. Kubernetes-Nerds, die Deep-Dive-Artikel mögen, um Kubernetes besser zu verstehen.
3. Maintainer von EKS, aws-cloud-controller-manager, aws-load-balancer-controller und der AWS Docs: Mit diesem Artikel möchte ich auf eine verwirrende Inkonsistenz aufmerksam machen, die so nur bei der Kubernetes-Load-Balancer-Provisionierung auf AWS existiert. Ich hoffe, dass er einen Anstoß zu mehr Konsistenz mit dem Rest der Kubernetes-Community gibt. (Das Problem zieht sich durch mehrere Git-Repos und Doku-Seiten und lässt sich nicht mit ein paar Merge Requests aus der Welt schaffen.)
Einführung
Vor Kurzem habe ich an einem Proof of Concept gearbeitet, bei dem es darum ging, AWS Load Balancer für einen EKS-Cluster (Elastic Kubernetes Service) über Kubernetes Services vom Typ LoadBalancer mit Annotationen der Form service.beta.kubernetes.io/aws-load-balancer-* zu provisionieren – diese sind auf dieser Seite aufgelistet.
Anfangs liefen einige Annotationen nicht wie erwartet. Ich konnte die Probleme zwar lösen, dafür musste ich aber erst einmal verstehen, warum etwas nicht funktionierte. Die Doku auf der verlinkten Seite erklärt das Verhalten zwar ordentlich, die Erklärungen sind jedoch nicht besonders einsteigerfreundlich.
Dieser Beitrag ist daher ein Deep Dive zu mehreren Themen:
- Warum der aws-load-balancer-controller verwirrend ist
- Hintergrundwissen, mit dem Einsteiger schnell auf den richtigen Stand kommen
- Details dazu, warum die Dinge so funktionieren, wie sie funktionieren
- Einige grundlegende, aber nützliche Troubleshooting-Tipps
- Ideen, wie verschiedene Maintainer-Gruppen das Ganze in Zukunft weniger verwirrend gestalten könnten
Knackpunkt: Eine Verwechslungsgeschichte
Wie erwähnt, finde ich die oben verlinkte Seite nicht besonders einsteigerfreundlich. Konkret: Das Projekt war für mich verwirrend genug, dass ich einen ganzen Tag gebraucht habe, um es zu durchdringen. Das ist ein schlechtes Zeichen, denn ich bin seit Juli 2018 Kubernetes-SME. Als ich es endlich durchschaut hatte, war mein erster Gedanke: "Ach, so läuft das. TIL (Today I Learned): Es gibt zwei verschiedene AWS-spezifische Kubernetes-Controller, die letztlich Annotationen an Kubernetes Services vom Typ Load Balancer nutzen können, um AWS-LBs zu provisionieren und zu verwalten." Mein zweiter Gedanke war: "Wow … wie sollen das andere Leute ohne Experten an ihrer Seite herausfinden? Darüber sollte ich einen Artikel schreiben."
Hier eine Liste der Punkte, die das AWS-Load-Balancer-Controller-Projekt verwirrend machen:
1.) Es sieht aus wie offizielle, eingebaute Funktionalität, ist es aber nicht!
Als ich auf Google nach "aws service of type lb" gesucht habe:
Erstes Ergebnis: docs.aws.amazon.com/eks/latest/userguide/network-load-balancing.html
Zweites Ergebnis: kubernetes-sigs.github.io/aws-load-balancer-controller/v2.4/guide/service/annotations/
Und der relevante Abschnitt der offiziellen Kubernetes-Doku, der bei der Suche nach "kubernetes service of type loadbalancer" als erstes Ergebnis erscheint:
https://kubernetes.io/docs/concepts/services-networking/service/
Alle drei Seiten sehen wie offizielle Doku aus, und alle drei scheinen dasselbe Thema zu behandeln, weil auf allen drei Seiten dieselben Annotationen auftauchen.
Wenn man auf allen drei Seiten per Strg+F nach
service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags
sucht, erscheint dieselbe Ressource. Auf den ersten Blick könnte man also denken, alle drei Seiten beschreiben dasselbe.
Tatsächlich ist der aws-load-balancer-controller aber ein Kubernetes-Add-on, das die eingebaute Funktionalität erweitert. Zwei der oben genannten Links beschreiben also eingebaute Funktionalität, der dritte ein Add-on, das zusätzliche Funktionen bietet.
2.) Die Namenskonvention der Projekt-Website und der Annotationen ist alles andere als intuitiv. Sie suggeriert, dass die Annotationen auf eingebaute Funktionalität verweisen:
2A.) Der DNS-Name, unter dem die Doku des Projekts gehostet wird, lautet kubernetes-sigs.github.io – das wirkt, als könnte es sich um eingebaute Kubernetes-Funktionalität handeln.
2B.) Die Annotationen des Add-ons referenzieren service.beta.kubernetes.io, was üblicherweise eingebauter Funktionalität vorbehalten ist.
3.) Auf der Startseite der Projekt-Doku wird nicht sofort klar, dass es sich um ein Kubernetes-Add-on handelt, das eingebaute Funktionalität erweitert.
Erst gegen Ende der zweiten Doku-Seite
und beim Anblick von helm install aws-load-balancer-controller macht es im Kopf "Aaaah! Das ist also ein Add-on, ok, das ergibt Sinn."
4.) Das API-Muster bricht mit dem üblichen Vorgehen in der breiteren Kubernetes-Community:
Cert Manager und der EBS Volume CSI (Container Storage Interface) Driver dienen als zwei Beispiele für übliche Muster:
- In der Doku von cert-manager nutzen 95 % der Annotationen
cert-manager.io. Damit ist auf einen Blick klar, dass die Annotationen zu einem Drittanbieter-Add-on gehören. - Der erste Satz der Landingpage der Doku lautet: "cert-manager adds certificates and certificate issuers as resource types in Kubernetes clusters …" – so wird gleich zu Beginn deutlich, dass das Projekt eine Erweiterung ist, die Funktionalität hinzufügt.
- Beim EBS Volume CSI Driver wird eine Namenskonvention verwendet, die auf einen Blick deutlich macht, dass es sich um etwas anderes als die eingebaute Funktionalität handelt.
Die eingebaute AWS Storage Class nutzt provisioner: kubernetes.io/aws-ebs
Die EBS-Add-on-Storage-Class nutzt provisioner: ebs.csi.aws.com
- Auf den Landingpages mehrerer EBS-CSI-Doku-Seiten wird ganz oben immer wieder klargestellt, dass es sich um ein Add-on handelt, das nicht standardmäßig installiert ist. Die Doku dieses Projekts geht sogar so weit, das Schlüsselwort "driver" gezielt einzusetzen, um es noch klarer zu machen: "The Amazon EBS CSI driver isn't installed when you first create a cluster. To use the driver, you must add it as an Amazon EKS add-on or as a self-managed add-on." Und falls jemand auf der GitHub-Seite statt in der Doku landet: Auch die GitHub-Landingpage des Projekts hat einen Link zu "Driver Installation".
5.) Auch die UI und Doku von AWS sind beim aws-load-balancer-controller inkonsistent:
Der AWS Load Balancer Controller hat unter docs.aws.amazon.com einen User Guide mit dem Titel "Installing the AWS Load Balancer Controller add-on".
In der GUI taucht er aber nicht als offizielles Add-on auf – nicht einmal, wenn man auf "Get more add-ons" klickt und dort Amazon EBS CSI Driver und AWS Distro for OpenTelemetry sieht.

6.) Dem Projekt fehlt Hintergrundwissen
Die Service-Annotation-Seite der Doku erwähnt kurz zwei Themen, die einerseits hilfreich zu verstehen sind (denn Verstehen erleichtert Troubleshooting), die ein Neuling andererseits ohne zusätzliche Erklärung kaum durchdringen kann. Wer die Themen googelt, findet sehr vage, fragmentierte und scheinbar widersprüchliche Informationen – es sei denn, man erkennt eine ganze Reihe von Nuancen.
Die beiden Themen, die in der Doku ohne Erklärung kurz erwähnt werden, sind:
1. "in-tree": "the k8s in-tree kube-controller-manager"
2. "Legacy AWS Cloud Provider": "The AWS Load Balancer Controller manages Kubernetes Services in a compatible way with the legacy aws cloud provider."
Im Idealfall gäbe es eine knappe Definition dieser Begriffe und einen Link zu weiterführender Lektüre für Interessierte. So würde ich sie zusammenfassen: Technisch sind das zwei verschiedene Dinge, in der Praxis kann man sie aber als dasselbe betrachten. Der Legacy AWS Cloud Provider stellt die standardmäßig eingebaute Funktionalität bereit, um Services vom Typ Load Balancer für Kubernetes-Cluster auf AWS zu provisionieren.
Hintergrundwissen
Wenn ich etwas debugge, versuche ich als Erstes, es zu verstehen. Das Thema AWS-LB-Provisionierung erfordert für ein vollständiges Verständnis eine Menge Hintergrundwissen. Bisher waren diese Informationen verstreut, nirgendwo wirklich in der Tiefe erklärt und voller Nuancen, die das Verständnis erschweren. Hier mein Versuch, einige zentrale Hintergrundinformationen zu bündeln und verständlich aufzubereiten.
Hintergrund zu zentralen Themen:
1.) kube-controller-manager vs. cloud-controller-manager vs. aws-cloud-controller-manager
Was "in-tree" und "Legacy AWS Cloud Provider" genau bedeuten, lässt sich ohne den Kontext zu diesen verwandten Themen schwer verstehen – also fangen wir hier an.
Früher hatte Kubernetes vier Control-Plane-Komponenten: controller-manager, scheduler, api-server und etcd. Man führte entweder den kube-controller-manager oder den cloud-controller-manager aus, nicht beide gleichzeitig.
Der cloud-controller-manager war die Variante, die in 95 % der Fälle eingesetzt wurde. Er bot dieselbe Funktionalität wie der kube-controller-manager, plus integrierte Unterstützung für die Anbindung an mehrere CSP-APIs (Cloud Service Provider). Da er mit CSP-APIs sprechen konnte, ließen sich darüber etwa AWS-EBS-Volumes und AWS Load Balancer provisionieren.
Der kube-controller-manager ist eine cloud-agnostische Implementierung – ihm fehlt also die eingebaute Fähigkeit, Dinge wie CSP-Storage und CSP-Load-Balancer automatisch zu provisionieren.
Heute hat Kubernetes in der Regel fünf Control-Plane-Komponenten:
etcd, kube-api-server, kube-scheduler, kube-controller-manager und einen CSP-spezifischen Controller-Manager wie aws-cloud-controller-manager. Die Diagramme in der offiziellen Kubernetes-Doku wurden an diese neue Architektur angepasst. Verifizieren lässt sich das auch über Deployment-Methoden wie kops oder kubeadm, mit denen man die Control Plane sehen kann. Die wichtigste Änderung: Es gibt nun Cloud Controller Manager, die jeweils einem einzigen Cloud-Service-Provider gewidmet sind und parallel zum kube-controller-manager laufen sollen. Der ursprüngliche cloud-controller-manager war eher eine universelle Allround-Lösung.
2.) "In-tree" bezeichnet die Zeit, in der Go-Bibliotheken zur Anbindung an mehrere CSP-APIs im Kubernetes-Repo lagen, um daraus ein universelles Kubernetes-Cloud-Controller-Manager-Container-Image zu bauen:
In-tree: Code, der im zentralen Kubernetes-Repository k8s.io/kubernetes liegt.
Out-of-Tree: Code, der in einem externen Repository außerhalb des Git-Repos k8s.io/kubernetes liegt.
Die Codebasis von Kubernetes 1.14 enthielt APIs für 8 verschiedene CSPs integriert. Es sollten weitere hinzukommen, und weil alle zusammengebündelt waren, mussten sie für ein Release alle gleichzeitig Stabilität erreichen. Aus Wartbarkeitssicht war das ein nicht tragfähiges Muster. Um das Problem anzugehen, wurde ein KEP (Kubernetes Enhancement Proposal) angenommen. Es schlug vor, CSP-Funktionalität von Kubernetes zu entkoppeln und in Add-ons zu refaktorieren.
Diese Entkopplung würde den Kubernetes-Releaseprozess vereinfachen und es Cloud-Providern ermöglichen, Features und Bugfixes unabhängig vom Release-Zyklus und den Prozessen von Kubernetes auszuliefern. Eine Entscheidung, technische Schulden abzubauen, um die langfristige Gesundheit des Projekts zu sichern.
3.) Wer sich selbst in das Thema einliest, stößt schnell auf scheinbar widersprüchliche Informationen – bis man mehrere Nuancen erkennt. Hier ein paar davon in beliebiger Reihenfolge:
- Die Migration von in-tree zu out-of-tree zieht sich offenbar über Jahre. Gleichzeitig deuten viele Hinweise darauf hin, dass sie längst begonnen und längst abgeschlossen sei. Dass sie zu unterschiedlichen Zeitpunkten begonnen und beendet wurde. Und dass sie noch im Gange ist.
- Weiter oben habe ich erwähnt, dass die Codebasis von Kubernetes 1.14 APIs für acht verschiedene CSPs hatte.
Wenn Sie sich die Codebasis von Kubernetes 1.26 ansehen, finden Sie immer noch vier verschiedene CSPs in-tree. AWS taucht weiterhin in der Liste der in-tree-CSPs auf. Aber es gibt ein out-of-tree-Git-Repo, das auf den aws-cloud-provider verweist und so klingt, als hätte AWS seine Migration bereits in 1.20 abgeschlossen.
Aber das KEP legt nahe, dass die Migration etwa mit Version 1.27 abgeschlossen sein wird?
Genau wegen solcher Dinge habe ich mich entschieden, einen Artikel darüber zu schreiben, statt zu einem Doku-Issue beizutragen. Auch wenn AWS und andere CSPs immer noch in-tree bzw. in einer universellen CSP-Version des Cloud Controller Manager existieren – diese Version wird in der Praxis nicht verwendet. AWS und andere CSPs nutzen ihre eigene CSP-spezifische Implementierung wie aws-cloud-controller-manager statt des älteren universellen Allround-cloud-controller-manager aus dem in-tree-Stand.
Die verschiedenen CSPs schließen ihre Migration vom universellen in-tree zum CSP-spezifischen out-of-tree in unterschiedlichem Tempo ab. Etwas verwirrend ist außerdem, dass dieses komplexe Vorhaben in zwei Teile gesplittet wurde. Die ursprünglich eingebaute in-tree-Funktionalität enthielt Logik zum Provisionieren von CSP-Storage und CSP-LBs. Die wurde nicht nur out-of-tree gezogen, sondern weiter entkoppelt: CSI-Treiber für CSP-Storage wurden zu eigenen, isolierten Komponenten mit eigenen Migrationszeitplänen.
- Wenn man das Ausmaß der Komplexität dieses Refactorings begreift, fängt einiges an, Sinn zu ergeben. Erstens: Kein Wunder, dass das Refactoring über vier Jahre gedauert hat. Out-of-tree-Cloud-Provider-Implementierungen erreichten in Version 1.11 Beta-Status, im Mai 2019. Zweitens: Wenn man bedenkt, dass mehrere Feature-Freezes eingeführt wurden, um den Migrationsprozess zu unterstützen, ergibt es Sinn, warum Bugs wie die Implementierung von
ExternalTrafficPolicy: Localbei AWS-LBs Jahre brauchten, um behoben zu werden. Es erklärt auch, warum es jahrelang kaum Feature-Erweiterungen für die eingebaute AWS-LB-Provisionierungslogik gab.
4.) "Legacy AWS Cloud Provider" bezeichnet im Wesentlichen die standardmäßige Load-Balancer-Provisionierungs-Funktionalität, auf die Sie in einer Standardinstallation von EKS oder Kubernetes auf AWS Zugriff haben.
Ein paar Nuancen verhindern, dass diese Aussage zu 100 % korrekt ist, aber sie kommt der Wahrheit nahe genug, um nützlich zu sein.
Die Nuancen sind:
- Legacy AWS Cloud Provider kann sich auf die AWS-spezifische Logik beziehen, die in-tree im (universellen CSP) cloud-controller-manager existierte und AWS-EBS-Volumes sowie AWS-LBs provisionieren konnte.
- Legacy AWS Cloud Provider kann sich auch auf die standardmäßige Load-Balancer-Provisionierungslogik beziehen, die im aws-cloud-controller-manager vorhanden ist.
- Der aws-cloud-controller-manager ist für Nutzer oft unsichtbar.
– Wenn Sie EKS verwenden, läuft der aws-cloud-controller-manager auf den verwalteten Master-Nodes, die Sie nicht sehen können.
– Wenn Sie kops oder kubeadm mit selbstgehosteten Master-Nodes verwenden, sehen Sie ihn.
– Wenn Sie RKE2 verwenden, sehen Sie ihn nicht, weil dort aus Defense-in-Depth-Sicherheitsgründen bestimmte Control-Plane-Komponenten als von Kubernetes isolierte Prozesse laufen.
- Legacy AWS Cloud Provider kann zwei verschiedene Dinge meinen, im Kontext von AWS-LBs sind sie aber praktisch dasselbe, weil sie dieselben Annotationen unterstützen. Die ursprünglichen 22 Annotationen finden Sie, wenn Sie auf dieser Seite nach dem String
const ServiceAnnotationLoadBalancersuchen. Hinweis: Zum Zeitpunkt dieses Schreibens sehen Sie, wenn Sie auf der Doku-Seite nachservice.beta.kubernetes.io/aws-load-balancersuchen, nur 21 Annotationen. Das ist lediglich ein Doku-Problem, keine Code-Änderung.
Hier die Liste der 22 standardmäßig verfügbaren Annotationen:
service.beta.kubernetes.io/aws-load-balancer-typeservice.beta.kubernetes.io/aws-load-balancer-internalservice.beta.kubernetes.io/aws-load-balancer-proxy-protocolservice.beta.kubernetes.io/aws-load-balancer-access-log-emit-intervalservice.beta.kubernetes.io/aws-load-balancer-access-log-enabledservice.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-nameservice.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefixservice.beta.kubernetes.io/aws-load-balancer-connection-draining-enabledservice.beta.kubernetes.io/aws-load-balancer-connection-draining-timeoutservice.beta.kubernetes.io/aws-load-balancer-connection-idle-timeoutservice.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabledservice.beta.kubernetes.io/aws-load-balancer-extra-security-groupsservice.beta.kubernetes.io/aws-load-balancer-security-groupsservice.beta.kubernetes.io/aws-load-balancer-ssl-certservice.beta.kubernetes.io/aws-load-balancer-ssl-portsservice.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policyservice.beta.kubernetes.io/aws-load-balancer-backend-protocolservice.beta.kubernetes.io/aws-load-balancer-additional-resource-tagsservice.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-thresholdservice.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-thresholdservice.beta.kubernetes.io/aws-load-balancer-healthcheck-timeoutservice.beta.kubernetes.io/aws-load-balancer-healthcheck-interval5.) Das AWS-Load-Balancer-Controller-Projekt ist konzeptionell ähnlich wie das AWS-EBS-CSI-Driver-Projekt:
Beide stehen für die Entkopplung von Kubernetes-Controller-Logik, die früher in-tree im universellen Allround-cloud-controller-manager lebte. Beide hatten das gemeinsame Ziel, Rückwärtskompatibilität zu gewährleisten. Ein Teil von mir vermutet, dass das bei der Entscheidung des Projekts, einige Annotationen wiederzuverwenden, eine Rolle gespielt hat.
6.) Die Projekte EBS-CSI-Driver-Add-on und AWS-LB-Controller-Add-on wurden von unterschiedlichen Gruppen ins Leben gerufen.
Das EBS-CSI-Driver-Add-on-Projekt wurde von AWS gestartet. Das AWS-LB-Controller-Add-on-Projekt wurde ursprünglich von Ticketmaster und CoreOS gestartet und war früher als "AWS ALB Ingress Controller" bekannt. 2018 wurde es an Kubernetes SIG-AWS gespendet. Der ALB Ingress Controller ließ sich ursprünglich am besten als Application Load Balancer Controller beschreiben. Mit der Zeit erweiterte sich der Scope des Projekts auch auf die Steuerung von NLBs. Im Juli 2021 wurde das Projekt daher in "AWS Load Balancer Controller" umbenannt.
Warum sind die Dinge so, wie sie sind?
Wäre die Logik des universellen Allround-cloud-controller-manager nicht out-of-tree in entkoppelte externe Add-ons migriert worden, hätten technische Schulden alle künftige Feature-Entwicklung und Bugfixes dauerhaft ausgebremst. Ich erinnere mich an Zeiten, in denen Bugs rund um externalTrafficPolicy: local immer wieder auftraten und Jahre brauchten, um ordentlich behoben zu werden. Jetzt, da die Logik vom Code, Releaseprozess und Testing des offiziellen Kubernetes-Projekts entkoppelt ist, werden Bugs in Monaten statt Jahren behoben, und Feature-Wünsche können wieder ernsthaft erwogen werden.
Schnellere Entwicklung hat zu großartigen Verbesserungen geführt – etwa dazu, dass sich das Konzept eines Software Defined Perimeter via Authn/z-Proxy dank der neuen Integration von AWS Cognito mit der ALB-Provisionierungslogik leichter umsetzen lässt. Auch das AWS-LB-Controller-Projekt bietet inzwischen mehr Optionen für die Provisionierung von NLBs über Annotationen. Ein neues Feature, das mir besonders gefällt, ist die Annotation service.beta.kubernetes.io/aws-load-balancer-nlb-target-type:, mit der Sie wählen können, wie Traffic zu Backend-Pods geroutet wird. Der Default-Wert "instance" sorgt dafür, dass Traffic von nELB -> NodePort -> Kube-Service -> Pod fließt. Der neu hinzugefügte Wert "ip" erlaubt, dass Traffic nELB -> Pod gehen kann, ähnlich wie bei aELB.
Kurzform-Referenz:
nELB = network Elastic Load Balancer (L4-LB as a Service)
aELB/ALB = application Elastic Load Balancer (L7-LB as a Service)
cELB = classic Elastic Load Balancer (L4/L7-LB as a Service)
Ich vermute, ein Grund dafür, dass das NLB-Management überhaupt in das ehemals als ALB Ingress Controller bekannte Projekt gerutscht ist (Scope Creep), war: Das ALB-Ingress-Controller-Projekt war Änderungen und neuen Features wahrscheinlich offener gegenüber, während der aws-cloud-controller-manager einen Feature-Freeze hatte, um die in-tree-Migration zu unterstützen.
Warum ist der AWS Load Balancer Controller nicht eher wie das AWS-EBS-CSI-Driver-Add-on aufgebaut? Ich denke, das hängt damit zusammen, dass AWS das EBS-CSI-Projekt von Anfang bis Ende kontrolliert hat, während das LB-Controller-Projekt übernommen wurde – und große Organisationen Änderungen aufgrund von Brooks's Law nur langsam umsetzen. (Kommunikations-Overhead in großen Organisationen verlangsamt Änderungen erheblich.)
Troubleshooting-Tipps für den AWS LB Controller
Diese Troubleshooting-Tipps erheben keinen Anspruch auf Vollständigkeit. Sie sollen lediglich nützlich genug sein, um Sie aus einer Sackgasse herauszuholen und Ihnen Themen aufzuzeigen, zu denen sich weitere Recherche lohnt.
1.) Prüfen, ob der AWS LB Controller installiert ist
kubectl get deployments --namespace=kube-system
Das ist deshalb wichtig, weil sich dadurch das Verhalten erheblich verändern kann. Wenn Sie zwei Cluster haben, in denen 99 % der YAML-Workloads und Konfigurationen identisch sind und der 1 %-Unterschied darin besteht, ob der AWS LB Controller installiert ist oder nicht, kann dasselbe YAML zu unterschiedlichen Ergebnissen führen.
2.) Erwägen Sie unbedingt ein Update auf die neueste Version
Mit folgendem Befehl sehen Sie, welche Version Sie ausführen:
kubectl get deploy aws-load-balancer-controller -n=kube-system -o yaml | grep image:
image: public.ecr.aws/eks/aws-load-balancer-controller:v2.4.6
Hier ein aktuelles, reales Szenario, in dem es sich gelohnt hat, auf dem neuesten Stand zu bleiben:
EKS 1.21 erreichte am 15. Februar 2023 sein End of Life. Einige Nutzer des AWS LB Controller hatten Ausfälle, bis sie von 2.3.x auf 2.4.x aktualisiert hatten. Die Ausfälle entstanden, weil das Upgrade von Kubernetes 1.21 auf 1.22 viele veraltete APIs entfernte. AWS LB Controller 2.4.x unterstützt die neuere Ingress-API networking.k8s.io/v1. 2.3.x unterstützt nur die ältere API networking.k8s.io/v1beta1, die in Kubernetes 1.22 entfernt wurde. Die Issue Tickets des aws-lb-controller-Projekts haben das frühzeitig erkannt und dafür gesorgt, dass 2.4.x-Versionen mit Kubernetes 1.19++ funktionieren – was Organisationen Zeit zur Migration verschaffte. Wer der Best Practice gefolgt ist, seine Add-ons aktuell zu halten, hat Ausfälle vermieden. Andere, die nur das Minimum an Wartung betreiben, sind wahrscheinlich auf dieses Problem gestoßen, als sie schließlich Kubernetes aktualisieren mussten, um auf einer unterstützten Version zu bleiben.
3.) Lesen Sie die Installationsdoku gründlich von Anfang bis Ende – Anforderungen lassen sich leicht übersehen:
Zusätzlich dazu, dass Sie den aws-load-balancer-controller im Namespace kube-system installieren und IAM-Rollen korrekt einrichten, müssen Sie auch die Subnetze der VPC korrekt taggen.
# Snippet einer Terraform-VPC-Config as Codemodule vpc { ... public_subnet_tags = { "kubernetes.io/role/elb" = "1" } private_subnet_tags = { "kubernetes.io/role/internal-elb" = "1" }}
/*Zusätzlicher Hintergrund:Wenn Sie sich die EKS-Doku ansehenhttps://aws.amazon.com/premiumsupport/knowledge-center/eks-load-balancer-controller-subnets/finden Sie einen Verweis auf"kubernetes.io/cluster/${local.cluster_name}" = "shared"Dieses Tag war bei älteren Versionen des aws-load-balancer-controller erforderlich*/4.) Wenn Sie ein Ingress-Objekt debuggen müssen, prüfen Sie, welche IngressClasses installiert sind
kubectl get ingressclass
Sehen Sie mehr als eine, sollten Sie kubectl describe ingressclass ausführen und prüfen, ob eine der Ingress-Klassen per Annotation als Default markiert ist.
Ist die alb-Ingress-Klasse nicht als Default markiert, sollten Sie die gewünschte Ingress-Klasse explizit am zu debuggenden Ingress-Objekt angeben.
5. Wenn Sie LB-Provisionierungs-Annotationen für Service-Objekte debuggen müssen, wird es etwas komplizierter … Warum es kompliziert ist:
Sie haben effektiv zwei verschiedene Controller, die gleichzeitig im selben Cluster laufen.
Bei EKS, einem Managed Service mit verwalteten Kubernetes-Master-Nodes, sehen Sie nur einen der beiden Controller (den aws-cloud-controller-manager sehen Sie nicht, da er auf den verwalteten Master-Nodes läuft).
Die beiden Controller überschneiden sich stark in Funktionsumfang und verwalteten Objekten:
– aws-cloud-controller-manager: provisioniert cELBs und nELBs
– aws-load-balancer-controller: provisioniert aELBs und nELBs
5A.) Bestimmen Sie, welcher Controller Ihr Kubernetes-Service-Objekt aktiv verwaltet.
Laut dieser Doku ignoriert der aws-cloud-controller-manager das Objekt – sodass der aws-load-balancer-controller es verwalten kann –, wenn Sie einen Kubernetes-Service mit einer dieser Optionen annotieren:
service.beta.kubernetes.io/aws-load-balancer-type: nlb-ip
service.beta.kubernetes.io/aws-load-balancer-type: external
5B.) Wenn der aws-load-balancer-controller einen Service verwaltet, wird kubectl describe service nützlich!
Viele, die fortgeschrittene LB-Optionen ausprobiert haben, sind wahrscheinlich auf das Szenario gestoßen, dass ein LB im Status "pending" hängenbleibt und sich weigert, provisioniert zu werden. Angenommen, Sie führen kubectl describe service $NAME zum Debuggen aus. Verwaltet der Legacy AWS Controller Manager den Service, erhalten Sie wahrscheinlich eine nutzlose Fehlermeldung. Verwaltet der aws-load-balancer-controller den Service, bekommen Sie tatsächlich Fehlermeldungen, die für das Debugging hilfreich sind. (Sie zeigen z. B. gut, ob Sie einen Installationsschritt vermasselt haben – etwa fehlende IAM-Rechte oder das Taggen der Subnetze vergessen.)
5C.) Überfliegen Sie die Release Notes auf zu berücksichtigende Änderungen:
- aws-cloud-controller-manager provisioniert LBs standardmäßig mit öffentlichen IPs. Sie müssen Konfiguration ergänzen, um Private IPs zu provisionieren. Beim aws-load-balancer-controller ist es umgekehrt. (seit v2.2.0)
- aws-cloud-controller-manager provisioniert standardmäßig cELBs. aws-load-balancer-controller provisioniert standardmäßig nELBs (für alle, die mit
service.beta.kubernetes.io/aws-load-balancer-type: externalannotiert sind, da dies steuert, welcher Controller zuständig ist). - Die Container-Images des aws-cloud-controller-manager waren früher auf Docker Hub verfügbar, ab v2.4.6 werden sie jedoch nur noch in der public.ecr.aws-Container-Registry gehostet.
5D.) Die meisten Kubernetes-Objekte unterstützen Reconciliation-Loops, die den aktuellen Zustand in den gewünschten überführen. Bei Load-Balancer-Controllern gibt es einige Edge Cases, in denen Sie Ressourcen löschen und neu erstellen müssen, damit iterative Änderungen wirksam werden.
Normalerweise ist das nicht nötig, manchmal lohnt sich der Versuch aber – die Annotation in 5A ist ein Beispiel, in dem die Doku ausdrücklich Neuerstellung statt Modifikation empfiehlt. Wichtig: Die Werte nlb-ip und external sind spezifisch für den AWS LB Controller; der Legacy Controller verwendet die Werte nlb und (leer provisioniert einen cELB). Diese Stolperfalle kann für jeden wichtig sein, der einen GitOps-Controller wie ArgoCD oder Flux für iterative Änderungen einsetzt, da diese Manifeste eher aktualisieren, als Ressourcen zu löschen und neu zu erstellen. Wenn ein ArgoCD- oder Flux-Nutzer also iterative Änderungen in einer Dev-Umgebung testet, muss er in diesem Edge Case möglicherweise manuell eingreifen, damit seine Änderungen wirksam werden.
Ich hatte zwei Hauptgründe für diesen Artikel. Der erste war, Wissen zu teilen – das ist erledigt. Der zweite war, Änderungen anzustoßen, die helfen, das Ganze weniger verwirrend zu machen. Es gibt drei Änderungen, die Projekt- und Doku-Maintainer vornehmen könnten und die viel zur Klärung beitragen würden. Alle laufen darauf hinaus, den aws-load-balancer-controller stärker am EBS-CSI-Projekt auszurichten:
- Das Projekt in die Liste der offiziellen EKS-Add-ons aufnehmen, die sich über die AWS Console GUI installieren lassen.
- Die Doku an mehreren Stellen aktualisieren, sodass sofort klar wird, dass der aws-load-balancer-controller ein Add-on ist.
- Die Annotationen so anpassen, dass sie statt
kubernetes.ioeherebs.csi.aws.comähneln. Damit wird der Add-on-Status auf einen Blick deutlich, und es ergibt sich ein SEO-Effekt (Search Engine Optimization), der das Nachschlagen relevanter Doku angenehmer macht.