Chris McGrath di DoiT ci accompagna alla scoperta del Kubernetes AWS LB Controller e del suo funzionamento dietro le quinte.

BLUF
Nella community Kubernetes vige una convenzione: i componenti nativi di Kubernetes riportano kubernetes.io nel nome, mentre gli Add-on no. Gli Add-on tendono a seguire una convenzione auto-esplicativa come ebs.csi.aws.com, dalla quale si capisce a colpo d'occhio che si tratta appunto di un add-on. L'add-on aws-load-balancer-controller rompe questa convenzione.
A chi si rivolge questo articolo
L'articolo si rivolge a tre tipologie di lettori, con altrettante finalità:
1. Amministratori Kubernetes che gestiscono EKS o distribuzioni Kubernetes generiche su AWS: non è indispensabile leggerlo, ma consiglio di salvarlo nei segnalibri e di tenerlo a mente come materiale di riferimento, da riprendere in mano in caso di debug del provisioning di AWS Load Balancer tramite servizi Kubernetes con annotazioni del tipo service.beta.kubernetes.io/aws-load-balancer-*.
2. Appassionati di Kubernetes a cui piacciono gli articoli di approfondimento per capirne meglio i meccanismi.
3. Maintainer di EKS, aws-cloud-controller-manager, aws-load-balancer-controller e della documentazione AWS: l'obiettivo è far luce su un'incoerenza confusa, peculiare del provisioning dei Load Balancer Kubernetes su AWS. La speranza è che incoraggi un riallineamento con il resto della community Kubernetes. (Il problema attraversa diversi repository git e siti di documentazione, quindi non si risolve con un paio di merge request.)
Introduzione
Di recente ho avviato un proof of concept che prevedeva il provisioning di AWS Load Balancer per un cluster EKS (Elastic Kubernetes Service) tramite servizi Kubernetes di tipo LoadBalancer, con annotazioni nella forma service.beta.kubernetes.io/aws-load-balancer-* elencate in questa pagina.
Inizialmente alcune annotazioni non funzionavano come previsto. Sono riuscito a risolverle, ma c'è un dettaglio importante: per farlo ho dovuto capire perché non funzionavano. La documentazione della pagina linkata spiega in modo discreto come funzionano le cose, ma non è particolarmente accessibile a chi parte da zero.
Questo articolo, quindi, vuole essere un approfondimento su diversi temi:
- Perché aws-load-balancer-controller crea confusione
- Le informazioni di contesto che servono ai principianti per partire con il piede giusto
- I dettagli sul perché le cose funzionano in questo modo
- Qualche consiglio di troubleshooting di base, ma utile
- Idee su come i vari gruppi di maintainer potrebbero ridurre la confusione in futuro
La sfida: un caso di scambio di identità
Dicevo che la pagina linkata sopra non è particolarmente accessibile per chi parte da zero. Per essere più chiaro: ho trovato il progetto talmente confuso da metterci un'intera giornata per capirlo. È un brutto segno, dato che mi occupo di Kubernetes come SME da luglio 2018. Una volta capito, il primo pensiero è stato: "Ah, è questo che succede. TIL (Today I learned) che esistono due controller Kubernetes specifici per AWS che possono entrambi finire per usare le annotazioni applicate ai servizi Kubernetes di tipo Load Balancer per fare provisioning e gestire AWS LB". Il secondo pensiero è stato: "Wow… come fanno gli altri a venirne a capo, senza un esperto sotto mano? Devo scrivere un articolo a riguardo".
Ecco un elenco di motivi per cui il progetto AWS Load Balancer Controller crea confusione:
1.) Sembra una funzionalità ufficiale integrata, ma non lo è!
Cercando su Google "aws service of type lb":
Primo risultato: docs.aws.amazon.com/eks/latest/userguide/network-load-balancing.html
Secondo risultato: kubernetes-sigs.github.io/aws-load-balancer-controller/v2.4/guide/service/annotations/
E la sezione pertinente della documentazione ufficiale di Kubernetes, primo risultato cercando "kubernetes service of type loadbalancer":
https://kubernetes.io/docs/concepts/services-networking/service/
Tutte e tre le pagine sembrano documentazione ufficiale e tutte e tre paiono parlare dello stesso argomento, perché le stesse annotazioni compaiono ovunque.
Se cercate (con Ctrl+F) in tutte e tre le pagine:
service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags
la stessa risorsa compare in tutte e tre. Cosa che, a prima vista, fa pensare che i tre siti stiano parlando della stessa cosa.
In realtà aws-load-balancer-controller è un Add-on di Kubernetes che estende la funzionalità integrata. Quindi due dei link sopra trattano funzionalità integrate, mentre il terzo è un add-on pensato per offrire funzionalità aggiuntive.
2.) La convenzione di denominazione usata dal sito del progetto e dalle annotazioni è davvero poco intuitiva e induce a pensare che le annotazioni si riferiscano a funzionalità integrate:
2A.) Il nome DNS dove è ospitata la documentazione del progetto è kubernetes-sigs.github.io
e questo lo fa sembrare una funzionalità integrata di Kubernetes.
2B.) Le annotazioni dell'add-on fanno riferimento a service.beta.kubernetes.io, che di norma è riservato alle funzionalità integrate.
3.) La home page del sito di documentazione del progetto non rende immediatamente evidente che si tratta di un Add-on Kubernetes pensato per estendere la funzionalità integrata.
Solo arrivando in fondo alla seconda pagina della documentazione
e notando helm install aws-load-balancer-controller, scatta il classico: "Ahhh! È un add-on, ok, allora ha senso".
4.) Il pattern usato dall'API è incoerente con quello adottato dalla community Kubernetes in senso più ampio:
Prendiamo Cert Manager e EBS Volume CSI (Container Storage Interface) Driver come due esempi di pattern "normali":
- Nella documentazione di cert-manager, il 95% delle annotazioni usa
cert-manager.io. A colpo d'occhio è quindi evidente che le annotazioni si riferiscono a un add-on di terze parti. - La prima frase della landing page della documentazione è "cert-manager adds certificates and certificate issuers as resource types in Kubernetes clusters…": chiarisce subito che il progetto è un'estensione che aggiunge funzionalità.
- Nel caso di EBS Volume CSI Driver, viene utilizzata una convenzione di denominazione che permette di distinguere intuitivamente, a colpo d'occhio, che è qualcosa di diverso dalla funzionalità integrata.
La Storage Class AWS integrata usa provisioner: kubernetes.io/aws-ebs
La Storage Class dell'add-on EBS usa provisioner: ebs.csi.aws.com
- È molto comune che le landing page dei vari siti di documentazione di EBS CSI ribadiscano fin da subito che si tratta di un add-on non installato di default. La documentazione del progetto arriva persino a inserire intenzionalmente la parola chiave "driver" per renderlo più intuitivo: "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." E nel caso si arrivi prima alla pagina GitHub anziché alla documentazione, anche la landing page GitHub del progetto contiene un link a "Driver Installation".
5.) Anche l'interfaccia utente e la documentazione di AWS sono incoerenti per quanto riguarda aws-load-balancer-controller:
AWS Load Balancer Controller ha una guida utente su docs.aws.amazon.com intitolata "Installing the AWS Load Balancer Controller add-on".
Eppure, nella GUI non compare come add-on ufficiale, nemmeno cliccando su "Get more add-ons", dove invece si vedono Amazon EBS CSI Driver e AWS Distro for OpenTelemetry.

6.) Al progetto mancano informazioni di contesto
La pagina della documentazione dedicata alle service annotation menziona di sfuggita due argomenti che sono al tempo stesso utili da capire (la comprensione aiuta nel troubleshooting) e quasi impossibili da afferrare per chi è alle prime armi senza ulteriori spiegazioni. Cercandoli su Google si trovano informazioni vaghe, frammentate e in apparenza contraddittorie, a meno di non saper cogliere parecchie sfumature.
I due argomenti citati senza spiegazione nella documentazione sono:
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."
In un mondo ideale ci sarebbe una definizione sintetica di cosa significhino questi termini e un link agli approfondimenti per chi è interessato. Ecco come li riassumerei: tecnicamente sono due cose diverse, ma in pratica si possono considerare la stessa cosa. Il Legacy AWS Cloud Provider è ciò che fornisce la funzionalità integrata di default per il provisioning dei servizi di tipo Load Balancer nei cluster Kubernetes in esecuzione su AWS.
Informazioni di contesto
Quando faccio troubleshooting, la prima cosa che cerco di fare è capire cosa sto guardando. Il provisioning degli AWS LB richiede parecchie informazioni di contesto per essere compreso a fondo. Purtroppo, fino a oggi queste informazioni erano sparse, mai spiegate in profondità e piene di sfumature difficili da assimilare. Questo è il mio tentativo di consolidare alcuni elementi chiave di contesto e renderli facili da capire.
Contesto sui temi chiave:
1.) kube-controller-manager vs cloud-controller-manager vs aws-cloud-controller-manager
Ci sono sfumature in ciò a cui fanno riferimento "in-tree" e "Legacy AWS Cloud Provider" che sono difficili da cogliere senza il contesto degli argomenti correlati: partiamo quindi da qui.
In passato Kubernetes aveva quattro componenti del control plane: controller-manager, scheduler, api-server ed etcd. Si eseguiva o kube-controller-manager o cloud-controller-manager, non entrambi.
Il cloud-controller-manager era l'opzione utilizzata nel 95% dei casi. Aveva la stessa funzionalità del kube-controller-manager, più il supporto integrato per dialogare con le API di più CSP (Cloud Service Provider). Sapendo come parlare con le API dei CSP, poteva fare cose come il provisioning di volumi AWS EBS e di AWS Load Balancer.
Il kube-controller-manager è invece un'implementazione cloud-agnostic, e quindi non ha la capacità integrata di fare cose come l'auto-provisioning di storage e Load Balancer dei CSP.
Kubernetes oggi ha normalmente cinque componenti del control plane:
etcd, kube-api-server, kube-scheduler, kube-controller-manager e un controller manager specifico per CSP come aws-cloud-controller-manager. I diagrammi nella documentazione ufficiale di Kubernetes sono stati aggiornati per riflettere la nuova architettura. Lo si può anche verificare usando metodi di deployment come kops o kubeadm, che permettono di vedere il control plane. Il cambiamento principale è che oggi ci sono cloud controller manager dedicati a un singolo cloud service provider, pensati per essere eseguiti accanto al kube-controller-manager. Il cloud-controller-manager originale era invece più una soluzione universale all-in-one.
2.) "In-tree" si riferisce all'epoca in cui le librerie Go in grado di interfacciarsi con le API di più CSP risiedevano nel repository di Kubernetes per costruire un'immagine container universale di Kubernetes Cloud Controller Manager:
In-tree: codice che risiede nel repository core di Kubernetes k8s.io/kubernetes.
Out-of-Tree: codice che risiede in un repository esterno al repository git k8s.io/kubernetes.
Il codice di Kubernetes 1.14 aveva integrate le API per 8 diversi CSP. Se ne volevano aggiungere altri e il fatto che fossero tutti raggruppati insieme significava che dovevano raggiungere la stabilità tutti insieme per ogni release. Un pattern insostenibile dal punto di vista della manutenibilità. Per affrontare il problema è stato approvato un KEP (Kubernetes Enhancement Proposal) che proponeva di disaccoppiare la funzionalità CSP da Kubernetes e di rifattorizzarla in add-on.
Questo disaccoppiamento avrebbe semplificato il processo di rilascio di Kubernetes e permesso ai cloud provider di rilasciare funzionalità e correzioni di bug in modo indipendente dal ciclo e dai processi di rilascio di Kubernetes. Una scelta per ripagare il debito tecnico e garantire la salute a lungo termine del progetto.
3.) Se si prova a fare ricerche autonome su questo tema, è facile imbattersi in informazioni che a prima vista sembrano contraddittorie, finché non si colgono diverse sfumature. Eccone alcune in ordine sparso:
- Sembra che la migrazione da in-tree a out-of-tree stia richiedendo anni. Si trovano anche molte informazioni che lasciano intendere che sia iniziata e finita molto tempo fa, oppure che sia iniziata e finita in tempi diversi, o ancora che sia tuttora in corso.
- Prima ho ricordato che il codice di Kubernetes 1.14 aveva API per otto diversi CSP.
Guardando il codice di Kubernetes 1.26, si vedono ancora quattro diversi CSP in-tree. AWS compare ancora nell'elenco dei CSP in-tree. Ma esiste un repository git out-of-tree relativo ad aws-cloud-provider che fa pensare che AWS abbia completato la migrazione già nella 1.20.
Eppure il KEP suggerisce che la migrazione finirà intorno alla versione 1.27?
È proprio per situazioni come queste che ho scelto di scrivere un articolo, anziché contribuire a sistemare un problema della documentazione. Sebbene AWS e altri CSP esistano ancora in-tree, in una versione universale del cloud controller manager, non è quella la versione usata in pratica. AWS e altri CSP usano la propria implementazione specifica per CSP, come aws-cloud-controller-manager, anziché il vecchio cloud-controller-manager universale all-in-one in-tree.
I diversi CSP stanno completando la migrazione dall'in-tree universale all'out-of-tree specifico per CSP a ritmi diversi. Un altro elemento un po' confondente è che questo lavoro complesso è stato suddiviso in due parti. La funzionalità integrata in-tree originale includeva la logica per il provisioning di storage e LB dei CSP. Non solo è stata portata out-of-tree, ma è stata ulteriormente disaccoppiata, così che i driver CSI per lo storage CSP siano diventati un componente isolato a sé, con tempistiche di migrazione separate.
- Quando ci si rende conto della scala di complessità di quel refactor, alcune cose iniziano ad avere senso. Primo: non c'è da stupirsi se il refactor ha richiesto oltre 4 anni. Le implementazioni out-of-tree dei cloud provider hanno raggiunto lo stato beta nella versione 1.11, a maggio 2019. Secondo: capendo che sono stati introdotti diversi feature freeze per supportare il processo di migrazione, si capisce anche perché bug come quelli legati all'implementazione di
ExternalTrafficPolicy: Localsugli AWS LB abbiano richiesto anni per essere corretti. E perché per anni non ci siano stati molti miglioramenti funzionali sulla logica integrata di provisioning degli AWS LB.
4.) "Legacy AWS Cloud Provider" si riferisce sostanzialmente alla funzionalità di provisioning dei load balancer di default disponibile in un'installazione standard di EKS o di Kubernetes su AWS.
Ci sono alcune sfumature che impediscono a questa affermazione di essere accurata al 100%, ma è abbastanza vicina alla realtà da risultare utile.
Le sfumature sono le seguenti:
- Legacy AWS Cloud Provider può riferirsi alla logica specifica AWS che esisteva in-tree, nel cloud-controller-manager (universale CSP), e che permetteva il provisioning di volumi AWS EBS e AWS LB.
- Legacy AWS Cloud Provider può anche riferirsi alla logica di provisioning dei load balancer di default presente in aws-cloud-controller-manager.
- aws-cloud-controller-manager è spesso invisibile agli utenti.
– Se si usa EKS, aws-cloud-controller-manager gira sui master node gestiti, che non sono visibili.
– Se si usano kops o kubeadm, che impiegano master node self-hosted, lo si vede.
– Se si usa RKE2 non lo si vede, a causa di alcuni dettagli implementativi di sicurezza in-depth che eseguono certi componenti del control plane come processi isolati da Kubernetes.
- Legacy AWS Cloud Provider può quindi riferirsi a due cose diverse, ma nel contesto degli AWS LB sono di fatto la stessa cosa, perché supportano le stesse annotazioni. Le 22 annotazioni originali si trovano cercando in questa pagina la stringa
const ServiceAnnotationLoadBalancer. Si noti che, al momento della stesura, cercando la stringaservice.beta.kubernetes.io/aws-load-balancernella pagina della documentazione se ne vedono solo 21. Si tratta semplicemente di un problema della documentazione, non di una modifica al codice.
Ecco l'elenco delle 22 annotazioni disponibili di default:
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.) Il progetto AWS Load Balancer Controller è concettualmente simile al progetto AWS EBS CSI Driver:
Entrambi rappresentano il disaccoppiamento di logica del controller Kubernetes che era in-tree nel cloud-controller-manager universale all-in-one. Avevano in comune l'obiettivo di garantire la retrocompatibilità. In parte mi chiedo se proprio questo abbia influito sulla decisione del progetto di riutilizzare alcune annotazioni.
6.) I progetti EBS CSI Driver Add-on e AWS LB Controller Add-on sono nati da gruppi diversi.
Il progetto EBS CSI Driver Add-on è nato in AWS. Il progetto AWS LB Controller Add-on è nato originariamente da Ticketmaster e CoreOS ed era precedentemente noto come "AWS ALB Ingress Controller". È stato donato a Kubernetes SIG-AWS nel 2018. In origine l'ALB Ingress Controller si descriveva al meglio come Application Load Balancer Controller. Dopo qualche tempo, lo scope del progetto si è ampliato fino a coprire anche la gestione degli NLB. Così, a luglio 2021, il progetto è stato ribattezzato "AWS Load Balancer Controller".
Perché le cose stanno così?
Se la logica del cloud-controller-manager universale all-in-one non fosse stata migrata out-of-tree in add-on esterni disaccoppiati, il debito tecnico avrebbe rallentato in modo permanente lo sviluppo di tutte le funzionalità future e la correzione dei bug. Ricordo un'epoca in cui i bug legati a externalTrafficPolicy: local continuavano a ripresentarsi e ci sono voluti anni per correggerli per bene. Ora che la logica è disaccoppiata dal codice, dal processo di rilascio e dai test del progetto Kubernetes ufficiale, i bug si risolvono in mesi invece che in anni e le richieste di funzionalità tornano a essere prese in considerazione.
Lo sviluppo più rapido ha portato a grandi miglioramenti, come rendere più facile l'implementazione del concetto di Software Defined Perimeter tramite Authn/z Proxy, grazie alla nuova integrazione di AWS Cognito con la logica di provisioning degli ALB. Anche il progetto AWS LB Controller offre più opzioni per il provisioning degli NLB tramite annotazioni. Una nuova funzionalità che apprezzo particolarmente è l'annotazione service.beta.kubernetes.io/aws-load-balancer-nlb-target-type:, che permette di scegliere come instradare il traffico verso i pod backend. Il valore di default "instance" fa sì che il traffico segua il percorso nELB -> NodePort -> servizio Kube -> Pod. Il nuovo valore "ip" permette invece al traffico di andare nELB -> Pod, in modo simile a come funziona aELB.
Riferimento abbreviato:
nELB = network Elastic Load Balancer (LB di livello L4 as a service)
aELB/ALB = application Elastic Load Balancer (LB di livello L7 as a service)
cELB = classic Elastic Load Balancer (LB di livello L4/L7 as a service)
Sospetto che parte del motivo per cui si è verificato lo scope creep dell'inclusione della gestione degli nELB nel progetto un tempo noto come ALB Ingress Controller sia che quel progetto era probabilmente più aperto a modifiche e nuove funzionalità in un periodo in cui aws-cloud-controller-manager aveva un feature freeze a supporto della migrazione in-tree.
Quanto al motivo per cui AWS Load Balancer Controller non è più simile all'AWS EBS CSI Driver Add-on, credo dipenda dal fatto che AWS ha avuto il controllo del progetto EBS CSI dall'inizio alla fine. Il progetto LB Controller, invece, è stato adottato in seconda battuta, e le grandi organizzazioni tendono a implementare i cambiamenti lentamente a causa della legge di Brooks. (L'overhead di comunicazione nelle grandi organizzazioni rallenta in modo significativo i cambiamenti.)
Suggerimenti di troubleshooting per AWS LB Controller
Questi suggerimenti di troubleshooting non vogliono essere esaustivi: l'obiettivo è darvi quanto basta per sbloccarvi e indirizzarvi verso gli argomenti giusti su cui approfondire.
1.) Verificare se AWS LB Controller è installato
kubectl get deployments --namespace=kube-system
È un controllo importante perché può determinare cambiamenti significativi di comportamento. Se avete due cluster con il 99% degli stessi workloads YAML e della stessa configurazione e l'unica differenza dell'1% è la presenza o meno di AWS LB Controller, lo stesso 99% di YAML può produrre risultati diversi.
2.) Valutate seriamente l'aggiornamento alla versione più recente
Per vedere quale versione state eseguendo potete usare il comando seguente:
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
Ecco un recente scenario reale in cui restare aggiornati ha pagato:
EKS 1.21 è arrivato a End of Life il 15 febbraio 2023. Alcuni utenti di AWS LB Controller hanno avuto disservizi finché non sono passati dalla 2.3.x alla 2.4.x. I disservizi erano dovuti al fatto che l'upgrade da Kubernetes 1.21 a 1.22 ha rimosso molte API deprecate. AWS LB Controller 2.4.x supporta la più recente API Ingress networking.k8s.io/v1, mentre la 2.3.x supporta solo la vecchia API networking.k8s.io/v1beta1, rimossa da Kubernetes 1.22. Le issue ticket del progetto aws-lb-controller hanno individuato il problema in anticipo e fatto sì che le versioni 2.4.x funzionassero con Kubernetes 1.19++, dando alle organizzazioni il tempo di migrare. Le organizzazioni che seguono la best practice di mantenere aggiornati i propri add-on hanno evitato i disservizi. Quelle che fanno una manutenzione minima si sono probabilmente imbattute nel problema dopo aver finalmente aggiornato Kubernetes per restare su una release supportata.
3.) Leggete tutta la documentazione di installazione, da cima a fondo: è facile perdersi qualche requisito.
Oltre a installare aws-load-balancer-controller nel namespace kube-system e a configurare correttamente i ruoli IAM, è necessario anche taggare correttamente le subnet della VPC.
# Snippet of Terraform VPC Config as Codemodule vpc { ... public_subnet_tags = { "kubernetes.io/role/elb" = "1" } private_subnet_tags = { "kubernetes.io/role/internal-elb" = "1" }}
/*Additional Background Contextual Info:If you look at the EKS docshttps://aws.amazon.com/premiumsupport/knowledge-center/eks-load-balancer-controller-subnets/You'll see a reference to"kubernetes.io/cluster/${local.cluster_name}" = "shared"That tag used to be required by older versions of aws-load-balancer-controller*/4.) Per fare il debug di un oggetto ingress, controllate quali Ingressclass sono installate
kubectl get ingressclass
Se ne vedete più di una, eseguite kubectl describe ingressclass e verificate se una di esse ha un'annotazione che la imposta come default.
Se la ingress class alb non è marcata come default, indicate esplicitamente la ingress class desiderata sull'oggetto ingress di cui state facendo il debug.
5. Per il debug di annotazioni di provisioning di LB specifiche per oggetti service, le cose si complicano un po'… Ecco perché:
Avreste di fatto due controller diversi in esecuzione nello stesso cluster contemporaneamente.
Nel caso di EKS, trattandosi di un servizio gestito con Kubernetes Master Node gestiti, ne potete vedere visivamente solo uno dei due. (Non vedrete aws-cloud-controller-manager, perché gira sui master node gestiti.)
I due controller hanno molte sovrapposizioni in termini di funzionalità e di oggetti di cui sono responsabili:
– aws-cloud-controller-manager: fa il provisioning di cELB e nELB
– aws-load-balancer-controller: fa il provisioning di aELB e nELB
5A.) Capire quale controller sta gestendo attivamente il vostro oggetto service Kubernetes.
Secondo questa documentazione, se annotate un servizio Kubernetes con una di queste opzioni:
service.beta.kubernetes.io/aws-load-balancer-type: nlb-ip
service.beta.kubernetes.io/aws-load-balancer-type: external
il controller aws-cloud-controller-manager ignorerà l'oggetto, lasciando che sia aws-load-balancer-controller a gestirlo.
5B.) Se è aws-load-balancer-controller a gestire un servizio, kubectl describe service diventa utile!
Chi ha provato opzioni avanzate sui LB si sarà probabilmente imbattuto in scenari in cui il LB resta bloccato in stato pending e si rifiuta di andare in provisioning. Diciamo che eseguite kubectl describe service $NAME per fare debug. Se il Legacy AWS Controller Manager sta gestendo il servizio, otterrete con tutta probabilità un messaggio di errore inutile. Se invece è aws-load-balancer-controller a gestirlo, otterrete messaggi di errore davvero utili per il debug. (Sono ottimi nel segnalare se avete sbagliato un passaggio dell'installazione, come l'assenza dei diritti IAM o il mancato tagging delle subnet.)
5C.) Date un'occhiata alle release notes per individuare eventuali cambiamenti di cui tenere conto:
- aws-cloud-controller-manager fa di default il provisioning di LB con IP pubblici. Per fare il provisioning con IP privati serve aggiungere configurazione. Per aws-load-balancer-controller vale il contrario. (a partire dalla v2.2.0)
- aws-cloud-controller-manager fa di default il provisioning di cELB. aws-load-balancer-controller fa di default il provisioning di nELB (per quelli annotati con
service.beta.kubernetes.io/aws-load-balancer-type: external, dato che è questo a stabilire quale controller è responsabile). - Le immagini container di aws-cloud-controller-manager erano disponibili su Docker Hub, ma a partire dalla v2.4.6 saranno ospitate solo sul container registry public.ecr.aws.
5D.) La maggior parte degli oggetti Kubernetes supporta loop di reconciliation che fanno transitare lo stato attuale verso quello desiderato. I controller dei Load Balancer hanno alcuni edge case in cui per applicare modifiche iterative bisogna eliminare e ricreare l'oggetto.
Di solito non serve, ma a volte vale la pena provarci: l'annotazione del punto 5A è un esempio in cui la documentazione consiglia di ricreare anziché modificare. Vale anche la pena ricordare che i valori nlb-ip ed external sono specifici di AWS LB Controller, mentre il Legacy Controller usa i valori nlb e (vuoto, che fa il provisioning di un cELB). Questo dettaglio può essere importante per chi utilizza un controller GitOps come ArgoCD o Flux per applicare modifiche iterative, dato che questi tendono ad aggiornare i manifest anziché eliminare e ricreare le risorse. Quindi, se un utente di ArgoCD o Flux stesse testando modifiche iterative in un ambiente di sviluppo, potrebbe dover intervenire manualmente in questo edge case per vedere applicate le proprie modifiche.
Avevo due motivi principali per scrivere questo articolo. Il primo era condividere conoscenza, e questa parte è fatta. Il secondo era contribuire a stimolare cambiamenti capaci di rendere tutto questo meno confuso. Ci sono tre cambiamenti che i maintainer del progetto e della documentazione potrebbero introdurre e che farebbero molto per dissipare la confusione. Tutti e tre puntano a rendere aws-load-balancer-controller più simile al progetto EBS-CSI:
- Aggiungere il progetto all'elenco degli add-on ufficiali di EKS, installabili tramite la GUI della AWS Console.
- Aggiornare la documentazione in più punti per rendere immediatamente evidente che aws-load-balancer-controller è un add-on.
- Aggiornare le annotazioni in modo che, anziché fare riferimento a
kubernetes.io, siano più simili aebs.csi.aws.com. In questo modo lo status di add-on diventa evidente a colpo d'occhio e si ottiene un effetto SEO (search engine optimization) che migliorerebbe l'esperienza degli utenti nella ricerca della documentazione pertinente.