BLUF
In der Kubernetes-Community gilt eine Konvention: Komponenten, die fest in Kubernetes integriert sind, referenzieren kubernetes.io in ihrer Benennung – Kubernetes Add-ons hingegen nicht. Add-ons folgen typischerweise einer selbsterklärenden Konvention wie ebs.csi.aws.com, an der sich intuitiv erkennen lässt, dass es sich um ein Add-on handelt. Das Add-on aws-load-balancer-controller bricht mit dieser Konvention.
Zielgruppe
Dieser Artikel richtet sich an drei Zielgruppen und verfolgt drei Zwecke:
1. Kubernetes-Admins, die EKS oder generische Kubernetes-Distributionen auf AWS betreiben: Sie müssen den Artikel nicht zwingend lesen, aber ich empfehle Ihnen, ihn als Lesezeichen zu speichern. Behalten Sie im Hinterkopf, dass es ihn als Referenz gibt – falls Sie jemals die AWS Load Balancer Provisionierung über Kubernetes Services mit Annotationen wie service.beta.kubernetes.io/aws-load-balancer-* debuggen müssen.
2. Kubernetes-Nerds, die Tiefenartikel mögen, um Kubernetes besser zu verstehen.
3. Maintainer von EKS, aws-cloud-controller-manager, aws-load-balancer-controller und der AWS-Dokumentation: Mein Ziel mit diesem Artikel ist es, eine verwirrende Inkonsistenz zu beleuchten, die einzigartig für die Kubernetes Load Balancer Provisionierung auf AWS ist. Ich hoffe, damit Veränderungen anzustoßen, die zu mehr Konsistenz mit dem Rest der Kubernetes-Community führen. (Das Problem zieht sich über mehrere Git-Repos und Dokumentationsseiten und lässt sich nicht einfach mit ein paar Merge Requests lösen.)
Einleitung
Ich habe kürzlich an einem Proof of Concept gearbeitet, bei dem 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-* bereitgestellt werden. Die Annotationen sind auf dieser Seite aufgelistet.
Anfangs funktionierten einige Annotationen nicht wie erwartet. Ich konnte sie zwar troubleshooten – aber dafür musste ich erst verstehen, warum sie nicht funktionierten. Die Dokumentation auf der verlinkten Seite erklärt die Funktionsweise grundsätzlich solide, ist für Einsteiger aber wenig zugänglich.
Dieser Beitrag dient daher als Deep Dive zu mehreren Themen:
- Warum der aws-load-balancer-controller verwirrend ist
- Hintergrund- und Kontextinformationen, die Einsteiger schnell auf Stand bringen
- 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 machen könnten
Herausforderung: Eine Verwechslung
Wie erwähnt finde ich die oben verlinkte Seite nicht besonders einsteigerfreundlich. Um es klarzustellen: Ich fand das Projekt verwirrend genug, dass ich einen Tag gebraucht habe, um es zu durchdringen. Das ist ein schlechtes Zeichen, denn ich bin seit Juli 2018 Kubernetes-SME. Nachdem ich es endlich verstanden hatte, war mein erster Gedanke: "Achso, darum geht es. TIL (Today I learned): Es gibt zwei verschiedene AWS-spezifische Kubernetes-Controller, die Annotationen an Kubernetes Services vom Typ Load Balancer nutzen können, um AWS LBs zu provisionieren und zu verwalten." Mein zweiter Gedanke: "Wow… Wie sollen andere das ohne Experten herausfinden? Darüber sollte ich einen Artikel schreiben."
Liste der Punkte, die das AWS Load Balancer Controller Project verwirrend machen:
1.) Es sieht aus wie offizielle, integrierte Funktionalität – ist es aber nicht!
Bei einer Google-Suche nach "aws service of type lb":
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-Dokumentation, der bei einer Suche nach "kubernetes service of type loadbalancer" als erstes Ergebnis erscheint:
https://kubernetes.io/docs/concepts/services-networking/service/
Alle drei Seiten wirken wie offizielle Dokumentation und scheinen dasselbe Thema zu behandeln, weil dieselben Annotationen auf allen drei Seiten auftauchen.
Wenn Sie auf allen drei Seiten per Strg+F nach Folgendem suchen:
service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags
… taucht dieselbe Ressource auf allen drei Seiten auf. Auf den ersten Blick könnte man also meinen, alle drei Seiten meinten dasselbe.
Tatsächlich ist der aws-load-balancer-controller ein Kubernetes Add-on, das die integrierte Funktionalität erweitert. Zwei der oben genannten Links beschreiben integrierte Funktionalität, der dritte ein Add-on, das diese Funktionalität ergänzt.
2.) Die Namenskonvention der Projekt-Website und der Annotationen ist sehr unintuitiv. Sie verleitet zu der Annahme, die Annotationen würden auf integrierte Funktionalität verweisen:
2A.) Der DNS-Name, unter dem die Projektdokumentation gehostet ist, lautet kubernetes-sigs.github.io – das wirkt so, als könnte es sich um integrierte Kubernetes-Funktionalität handeln.
2B.) Die Annotationen des Add-ons referenzieren service.beta.kubernetes.io, was üblicherweise integrierter Funktionalität vorbehalten ist.
3.) Die Startseite der Projektdokumentation macht nicht sofort klar, dass es sich um ein Kubernetes Add-on handelt, das integrierte Funktionalität erweitert.
Erst gegen Ende der zweiten Dokumentationsseite
fällt der Groschen beim Anblick von helm install aws-load-balancer-controller: "Aha! Das ist ein Add-on, ok, das ergibt Sinn."
4.) Das Muster der API ist inkonsistent mit dem, was in der breiteren Kubernetes-Community üblich ist: Cert Manager und der EBS Volume CSI (Container Storage Interface) Driver sind zwei Beispiele für übliche Muster:
- In der cert-manager-Dokumentation verwenden 95 % der Annotationen
cert-manager.io. Damit ist auf einen Blick intuitiv klar, dass die Annotationen auf ein Drittanbieter-Add-on verweisen. - Der erste Satz der Dokumentations-Startseite lautet: "cert-manager adds certificates and certificate issuers as resource types in Kubernetes clusters…". Damit wird gleich zu Beginn klargestellt, dass das Projekt eine Erweiterung ist, die Funktionalität hinzufügt.
- Beim EBS Volume CSI Driver wird eine Namenskonvention verwendet, die auf einen Blick erkennen lässt, dass er sich von der integrierten Funktionalität unterscheidet.
Die integrierte AWS Storage Class verwendet provisioner: kubernetes.io/aws-ebs
Die EBS Add-on Storage Class verwendet provisioner:ebs.csi.aws.com
- Die ersten Landing Pages der EBS-CSI-Dokumentation stellen typischerweise gleich zu Beginn mehrfach klar, dass es sich um ein Add-on handelt, das nicht standardmäßig installiert ist. Die Dokumentation dieses Projekts baut sogar gezielt das Schlüsselwort "driver" ein, um das intuitiver 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." Falls jemand statt auf der Doku-Seite auf der GitHub-Seite landet, enthält selbst die GitHub-Landing-Page des Projekts einen Link zu "Driver Installation".
5.) Auch UI und Dokumentation von AWS sind beim Thema aws-load-balancer-controller inkonsistent: Der AWS Load Balancer Controller hat einen User Guide unter docs.aws.amazon.com 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 Sie auf "Get more add-ons" klicken und Amazon EBS CSI Driver & AWS Distro for OpenTelemetry sehen.
6.) Dem Projekt fehlen Hintergrund- und Kontextinformationen
Die Service-Annotationsseite der Dokumentation erwähnt kurz zwei Themen, die einerseits nützlich zu verstehen sind (denn Verständnis erleichtert das Troubleshooting), andererseits für Einsteiger ohne zusätzliche Erklärung kaum nachvollziehbar. Wer die Themen googelt, findet nur sehr vage, fragmentierte und scheinbar widersprüchliche Informationen – es sei denn, man erkennt zahlreiche 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."
Idealerweise gäbe es eine zusammengefasste Definition dieser Begriffe sowie einen Link zu weiterführender Literatur. Hier meine Zusammenfassung: Technisch sind das zwei verschiedene Dinge, praktisch aber dasselbe. Der Legacy AWS Cloud Provider stellt die standardmäßig integrierte Funktionalität bereit, um Services vom Typ Load Balancer für Kubernetes-Cluster auf AWS zu provisionieren.
Hintergrund- und Kontextinformationen
Wenn ich etwas troubleshoote, versuche ich zuerst, es zu verstehen. Das Thema AWS-LB-Provisionierung erfordert dafür eine Menge Hintergrund- und Kontextinformationen. Diese Informationen waren bisher leider verstreut, nirgends ausführlich erklärt und voller Nuancen, die das Verständnis erschweren. Dies ist 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 Die Begriffe "in-tree" und "Legacy AWS Cloud Provider" haben Nuancen, die ohne Hintergrund zu diesen verwandten Themen schwer zu verstehen sind – deshalb fangen wir hier an.
Früher hatte Kubernetes vier Control-Plane-Komponenten: controller-manager, scheduler, api-server und etcd. Man betrieb entweder den kube-controller-manager oder den cloud-controller-manager – nicht beide.
In 95 % der Fälle kam der cloud-controller-manager zum Einsatz. Er hatte 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ß sich damit etwa das Provisionieren von AWS-EBS-Volumes und AWS Load Balancers erledigen.
Der kube-controller-manager ist eine cloud-agnostische Implementierung. Ihm fehlt deshalb die integrierte Fähigkeit, beispielsweise 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 den aws-cloud-controller-manager. Diagramme in der offiziellen Kubernetes-Dokumentation wurden entsprechend dieser neuen Architektur aktualisiert. Verifizieren lässt sich das auch mit Deployment-Methoden wie kops oder kubeadm, die die Control Plane sichtbar machen. Die Hauptänderung: Cloud-Controller-Manager sind nun jeweils einem einzigen Cloud Service Provider zugeordnet und sollen parallel zum kube-controller-manager laufen. Der ursprüngliche cloud-controller-manager war hingegen eher eine universelle All-in-one-Lösung.
2.) "In-tree" bezieht sich auf die Zeit, als Go-Lang-Bibliotheken, die mit mehreren CSP-APIs sprechen konnten, 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 Wartungssicht war das nicht nachhaltig. Um das Problem anzugehen, wurde ein KEP (Kubernetes Enhancement Proposal) genehmigt. Es schlug vor, CSP-Funktionalität von Kubernetes zu entkoppeln und in Add-ons zu refaktorisieren.
Diese Entkopplung sollte den Kubernetes-Releaseprozess vereinfachen und es Cloud-Anbietern ermöglichen, Features und Bugfixes unabhängig vom Releasezyklus und den Prozessen von Kubernetes auszuliefern. Eine Entscheidung, technische Schulden abzubauen, um die langfristige Gesundheit des Projekts zu sichern.
3.) Wer selbst zu diesem Thema recherchiert, stößt schnell auf Informationen, die sich auf den ersten Blick widersprechen – bis man mehrere Nuancen erkennt. Hier ein paar Nuancen in beliebiger Reihenfolge:
- Die Migration von in-tree zu out-of-tree scheint Jahre zu dauern. Es gibt zudem viele Quellen, die suggerieren, sie habe vor langer Zeit begonnen und vor langer Zeit geendet, dass sie zu unterschiedlichen Zeitpunkten begonnen und beendet wurde – oder dass sie nach wie vor andauert.
- Wie erwähnt enthielt die Codebasis von Kubernetes 1.14 APIs für acht verschiedene CSPs. In der Codebasis von Kubernetes 1.26 sind 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 es so klingen lässt, 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, lieber einen Artikel zu schreiben, statt zur Behebung eines Doku-Issues beizutragen. Auch wenn AWS und andere CSPs noch in-tree existieren – also in einer universellen CSP-Version des Cloud-Controller-Managers –, kommt diese Variante in der Praxis nicht zum Einsatz. AWS und andere CSPs nutzen ihre eigene, CSP-spezifische Implementierung wie den aws-cloud-controller-manager, statt des älteren in-tree-Universal-All-in-one-cloud-controller-managers.
Verschiedene CSPs haben ihre Migration vom universellen in-tree-Modell zur CSP-spezifischen out-of-tree-Variante in unterschiedlichem Tempo abgeschlossen. Etwas, das ebenfalls verwirrend ist: Diese komplexe Aufgabe wurde in zwei Teile gesplittet. Die ursprünglich integrierte Funktionalität enthielt Logik zum Provisionieren von CSP-Storage und CSP-LBs. Beides wurde nicht nur out-of-tree verlagert, sondern weiter entkoppelt – CSI-Treiber für CSP-Storage wurden zu einer eigenen, isolierten Komponente mit separatem Migrationszeitplan.
- Wer den Komplexitätsgrad dieses Refactorings vor Augen hat, dem ergeben einige Dinge plötzlich Sinn. Erstens: Es ist kein Wunder, dass das Refactoring mehr als vier Jahre gedauert hat. Out-of-tree Cloud-Provider-Implementierungen erreichten in Version 1.11 Beta-Status, im Mai 2019. Zweitens wird klar, warum Bugs wie der zur Implementierung von
ExternalTrafficPolicy: Localauf AWS LBs Jahre brauchten, um behoben zu werden – schließlich wurden mehrere Feature Freezes eingelegt, um den Migrationsprozess zu unterstützen. Auch erklärt das, warum es jahrelang nur wenige Feature-Erweiterungen für die integrierte AWS-LB-Provisionierungslogik gab.
4.) "Legacy AWS Cloud Provider" bezeichnet im Kern die standardmäßige Load-Balancer-Provisionierungsfunktionalität, die Sie in einer Standardinstallation von EKS oder Kubernetes auf AWS zur Verfügung haben.
Einige Nuancen verhindern, dass diese Aussage zu 100 % korrekt ist – aber sie ist nah genug an der Wahrheit, um nützlich zu sein.
Die Nuancen sind folgende:
- 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.
– Mit EKS läuft der aws-cloud-controller-manager auf den verwalteten Master-Knoten, die Sie nicht sehen können.
– Mit kops oder kubeadm und selbst gehosteten Master-Knoten sehen Sie ihn.
– Mit RKE2 sehen Sie ihn nicht – wegen einiger Defense-in-Depth-Sicherheitsdetails der Implementierung, mit denen bestimmte Control-Plane-Komponenten als von Kubernetes isolierte Prozesse ausgeführt werden.
- Legacy AWS Cloud Provider kann zwei verschiedene Dinge bezeichnen, im Kontext von AWS-LBs sind sie aber effektiv dasselbe, weil sie dieselben Annotationen unterstützen. Die ursprünglichen 22 Annotationen finden Sie, indem Sie auf dieser Seite nach dem String
const ServiceAnnotationLoadBalancersuchen. Hinweis: Zum Zeitpunkt dieses Artikels finden Sie auf der Doku-Seite bei einer Suche nachservice.beta.kubernetes.io/aws-load-balancernur 21 Annotationen. Das ist lediglich ein Problem mit der Doku, keine Code-Änderung.
Hier eine Liste der 22 Annotationen, die standardmäßig zur Verfügung stehen:
service.beta.kubernetes.io/aws-load-balancer-type
service.beta.kubernetes.io/aws-load-balancer-internal
service.beta.kubernetes.io/aws-load-balancer-proxy-protocol
service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval
service.beta.kubernetes.io/aws-load-balancer-access-log-enabled
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix
service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled
service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout
service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled
service.beta.kubernetes.io/aws-load-balancer-extra-security-groups
service.beta.kubernetes.io/aws-load-balancer-security-groups
service.beta.kubernetes.io/aws-load-balancer-ssl-cert
service.beta.kubernetes.io/aws-load-balancer-ssl-ports
service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy
service.beta.kubernetes.io/aws-load-balancer-backend-protocol
service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags
service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold
service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold
service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout
service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval
5.) Das AWS Load Balancer Controller Project ähnelt konzeptionell dem AWS EBS CSI Driver Project: Beide stehen für die Entkopplung von Kubernetes-Controller-Logik, die früher in-tree im universellen All-in-one-cloud-controller-manager existierte. Beide hatten das gemeinsame Ziel, Rückwärtskompatibilität zu gewährleisten. Ein Teil von mir fragt sich, ob das eine Rolle bei der Entscheidung des Projekts gespielt hat, einige Annotationen wiederzuverwenden.
6.) Die Projekte EBS CSI Driver Add-on und AWS LB Controller Add-on wurden von verschiedenen Gruppen gestartet.
Das EBS CSI Driver Add-on Project wurde von AWS gestartet. Das AWS LB Controller Add-on Project wurde ursprünglich von Ticketmaster und CoreOS initiiert und hieß früher "AWS ALB Ingress Controller". 2018 wurde es an die Kubernetes SIG-AWS gespendet. Der ALB Ingress Controller war ursprünglich am ehesten als Application Load Balancer Controller zu beschreiben. Mit der Zeit erweiterte sich der Projektumfang um die Steuerung von NLBs. Im Juli 2021 wurde das Projekt deshalb in "AWS Load Balancer Controller" umbenannt.
Warum sind die Dinge, wie sie sind?
Wäre die Logik des All-in-one-Universal-cloud-controller-managers nicht aus dem Tree heraus in entkoppelte externe Add-ons migriert worden, hätten technische Schulden alle künftige Feature-Entwicklung und Bugfixes dauerhaft ausgebremst. Ich erinnere mich an eine Zeit, als Bugs rund um externalTrafficPolicy: local immer wieder auftraten und Jahre brauchten, um richtig behoben zu werden. Inzwischen ist die Logik vom Code, dem Releaseprozess und dem Testing des offiziellen Kubernetes-Projekts entkoppelt. Bugs werden nun in Monaten statt Jahren behoben, und Feature Requests können wieder in Betracht gezogen werden.
Schnellere Entwicklung hat zu großartigen Verbesserungen geführt – etwa zu einer einfacheren Implementierung eines Software Defined Perimeter über einen Authn/z-Proxy, dank der neuen Integration von AWS Cognito mit der ALB-Provisionierungslogik. Auch das AWS LB Controller Project bietet mehr Optionen beim Provisionieren 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 sich festlegen lässt, wie Traffic zu den Backend-Pods geroutet wird. Der Standardwert "instance" bewirkt, dass Traffic von nELB -> NodePort -> Kube Service -> Pod fließt. Ein neu hinzugefügter Wert "ip" ermöglicht es, dass Traffic nELB -> Pod fließt – ähnlich wie es bei aELB funktioniert.
Kurzreferenz:
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, dass das Verwalten von nELBs in dem ehemals als ALB Ingress Controller bekannten Projekt auch deshalb hinzukam, weil das ALB Ingress Controller Project zu einer Zeit, als der aws-cloud-controller-manager einen Feature Freeze zur Unterstützung der in-tree-Migration hatte, vermutlich offener für Änderungen und neue Features war.
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 Project von Anfang an unter Kontrolle hatte. Das LB Controller Project wurde dagegen übernommen, und große Organisationen setzen Änderungen tendenziell langsam um – siehe Brooks's Law. (Kommunikationsoverhead in großen Organisationen verlangsamt Änderungen erheblich.)
Troubleshooting-Tipps für den AWS LB Controller
Diese Troubleshooting-Tipps sind weder umfassend noch erschöpfend gemeint. Sie sollen gerade nützlich genug sein, um Sie aus einer Sackgasse zu holen und in die richtige Richtung für vertiefende Recherche zu weisen.
1.) Prüfen, ob der AWS LB Controller installiert istkubectl get deployments --namespace=kube-system
Das ist deshalb wichtig, weil daraus erhebliche Verhaltensänderungen entstehen können. Wenn Sie zwei Cluster mit zu 99 % identischen YAML-Workloads und identischer Konfiguration deployen und der einzige Unterschied von 1 % darin liegt, ob der AWS LB Controller installiert ist – können dieselben YAML-Dateien zu unterschiedlichen Ergebnissen führen.
2.) Ziehen Sie ein Update auf die neueste Version ernsthaft in Betracht
Mit folgendem Befehl sehen Sie, welche Version Sie betreiben:
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 auszahlte, auf dem neuesten Stand zu bleiben:
EKS 1.21 erreichte am 15. Februar 2023 sein End of Life. Einige Anwender des AWS LB Controllers erlitten Ausfälle, bis sie von 2.3.x auf 2.4.x updateten. Die Ausfälle entstanden, weil das Upgrade von Kubernetes 1.21 auf 1.22 viele veraltete APIs entfernt hatte. Der AWS LB Controller 2.4.x unterstützt die neuere Ingress-API networking.k8s.io/v1. Version 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 erkannten dieses Problem und sorgten dafür, dass die 2.4.x-Versionen mit Kubernetes 1.19++ funktionieren – so hatten Organisationen Zeit zur Migration. Wer sich an die Best Practice gehalten hat, Add-ons aktuell zu halten, hat Ausfälle vermieden. Andere, die nur Mindestwartung betreiben, sind wahrscheinlich auf dieses Problem gestoßen, als sie Kubernetes irgendwann auf eine unterstützte Version aktualisiert haben.
3.) Lesen Sie die Installationsdokumentation einmal komplett von Anfang bis Ende durch – einige Anforderungen lassen sich leicht übersehen:
Zusätzlich zur Installation des aws-load-balancer-controller im Namespace kube-system und zur korrekten Einrichtung der IAM-Rollen müssen Sie auch die Subnetze der VPC korrekt taggen.
# Snippet einer Terraform-VPC-Konfiguration als Code
module vpc {
...
public_subnet_tags = {
"kubernetes.io/role/elb" = "1"
}
private_subnet_tags = {
"kubernetes.io/role/internal-elb" = "1"
}
}
/*
Zusätzliche Hintergrundinformationen:
In der EKS-Doku
https://aws.amazon.com/premiumsupport/knowledge-center/eks-load-balancer-controller-subnets/
findet sich ein Verweis auf
"kubernetes.io/cluster/${local.cluster_name}" = "shared"
Dieses Tag wurde von älteren Versionen des aws-load-balancer-controller benötigt
*/
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 Classes per Annotation als Standard markiert ist.
Falls die alb-Ingress-Class nicht als Standard markiert ist, geben Sie die gewünschte Ingress Class auf dem zu debuggenden Ingress-Objekt explizit an.
5. Wenn Sie LB-Provisionierungs-Annotationen debuggen müssen, die spezifisch für Service-Objekte sind, wird es etwas komplizierter…
Worin liegt die Komplexität:
- Sie haben effektiv zwei verschiedene Controller, die gleichzeitig im selben Cluster laufen.
- Bei EKS – einem Managed Service mit verwalteten Kubernetes-Master-Knoten – sehen Sie nur einen der beiden Controller. (Den aws-cloud-controller-manager sehen Sie nicht, da er auf den verwalteten Master-Knoten läuft.)
- Die beiden Controller überschneiden sich stark in Funktionalität und in den Objekten, für die sie zuständig sind:
– 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, sobald 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
Dann kann der aws-load-balancer-controller das Objekt verwalten.
5B.) Wenn der aws-load-balancer-controller einen Service verwaltet, wird kubectl describe service nützlich! Wer fortgeschrittene LB-Optionen ausprobiert hat, ist vermutlich schon einmal in eine Situation geraten, in der ein LB im Status "pending" hängt und sich nicht provisionieren lässt. Angenommen, Sie führen kubectl describe service $NAME zum Debuggen aus. Verwaltet der Legacy AWS Controller Manager den Service, bekommen Sie wahrscheinlich eine nutzlose Fehlermeldung. Verwaltet der aws-load-balancer-controller den Service, erhalten Sie tatsächlich Fehlermeldungen, die für das Debugging hilfreich sind. (Sie weisen sehr gut auf vergessene Installationsschritte hin – etwa fehlende IAM-Rechte oder das vergessene Tagging der Subnetze.)
5C.) Überfliegen Sie die Release Notes, um zu prüfen, welche Änderungen Sie berücksichtigen müssen:
- Der aws-cloud-controller-manager provisioniert LBs standardmäßig mit öffentlichen IPs. Für private IPs ist zusätzliche Konfiguration nötig. Beim aws-load-balancer-controller ist es umgekehrt. (seit v2.2.0)
- Der aws-cloud-controller-manager provisioniert standardmäßig cELBs. Der aws-load-balancer-controller provisioniert standardmäßig nELBs (für alles, was mit
service.beta.kubernetes.io/aws-load-balancer-type: externalannotiert ist – das steuert, welcher Controller zuständig ist). - Container-Images des aws-cloud-controller-manager waren früher auf Docker Hub verfügbar, aber ab v2.4.6 werden sie zukünftig nur noch in der public.ecr.aws Container Registry gehostet.
5D.) Die meisten Kubernetes-Objekte unterstützen Reconciliation Loops, die den aktuellen in den gewünschten Zustand überführen. Bei Load-Balancer-Controllern gibt es einige Edge Cases, in denen Sie löschen und neu erstellen müssen, damit iterative Änderungen wirksam werden.
In der Regel ist das nicht nötig, manchmal aber einen Versuch wert. Die Annotation aus 5A ist ein Beispiel, bei dem die Doku Neuerstellung statt Modifikation empfiehlt. Erwähnenswert ist außerdem, dass die Werte nlb-ip und external spezifisch für den AWS LB Controller sind. Der Legacy Controller verwendet die Werte nlb und (leer für die Provisionierung eines cELB). Dieser Stolperstein kann für alle wichtig sein, die einen GitOps-Controller wie ArgoCD oder Flux für iterative Änderungen einsetzen – diese aktualisieren Manifeste tendenziell, statt Ressourcen zu löschen und neu anzulegen. Wer als ArgoCD- oder Flux-Anwender iterative Änderungen in einer Dev-Umgebung testet, muss in diesem Edge Case möglicherweise manuell eingreifen, damit die Änderungen wirksam werden.
Ich hatte zwei Hauptgründe, diesen Artikel zu schreiben. Der erste war, Wissen zu teilen – das ist erledigt. Der zweite war, Änderungen anzustoßen, die das Ganze weniger verwirrend machen können. Es gibt drei Änderungen, die Projekt- und Dokumentations-Maintainer vornehmen könnten und die viel zur Klärung beitragen würden. Sie alle laufen darauf hinaus, den aws-load-balancer-controller stärker an das EBS-CSI-Projekt anzulehnen:
- Das Projekt zur Liste der offiziellen EKS-Add-ons hinzufügen, die über die AWS Console GUI installierbar sind.
- Die Dokumentation an mehreren Stellen aktualisieren, sodass sofort offensichtlich wird, dass der aws-load-balancer-controller ein Add-on ist.
- Die Annotationen umstellen, sodass sie statt
kubernetes.ioeherebs.csi.aws.comähneln. Damit wird der Add-on-Status durch bloßes Hinsehen offensichtlich – und es entsteht ein SEO-Effekt (Suchmaschinenoptimierung), der das Auffinden relevanter Dokumentation verbessert.