Chris McGrath, de DoiT, te explica el AWS LB Controller de Kubernetes y cómo funciona por dentro.

BLUF
Dentro de la comunidad de Kubernetes existe una convención: lo que viene integrado en Kubernetes hace referencia a kubernetes.io en su nombre, mientras que los Add-ons no. Los Add-ons suelen seguir una convención autodescriptiva como ebs.csi.aws.com, que permite identificar de un vistazo que se trata de un add-on. El add-on aws-load-balancer-controller rompe con esta convención.
Público objetivo
Este artículo está pensado para tres tipos de lectores y propósitos:
1. Administradores de Kubernetes que corren EKS o distribuciones genéricas de Kubernetes en AWS: no hace falta que lo leas ahora, pero te recomiendo que lo guardes en favoritos y tengas presente que existe como material de referencia, por si algún día necesitas depurar el aprovisionamiento de AWS Load Balancer con servicios de Kubernetes que usen anotaciones del tipo service.beta.kubernetes.io/aws-load-balancer-*.
2. Fanáticos de Kubernetes a los que les gustan los artículos a fondo que ayudan a entender mejor la plataforma.
3. Mantenedores de EKS, aws-cloud-controller-manager, aws-load-balancer-controller y de la documentación de AWS: mi intención con este artículo es poner el foco sobre una inconsistencia confusa propia del aprovisionamiento de Load Balancers de Kubernetes en AWS. Espero que sirva para impulsar un cambio hacia la coherencia con el resto de la comunidad de Kubernetes. (El asunto abarca varios repos de git y sitios de documentación, así que no se resuelve fácilmente con unos cuantos merge requests.)
Introducción
Hace poco arranqué una prueba de concepto que implicaba aprovisionar AWS Load Balancers para un cluster de EKS (Elastic Kubernetes Service) usando servicios de Kubernetes del tipo LoadBalancer con anotaciones de la forma service.beta.kubernetes.io/aws-load-balancer-*, listadas en esta página.
Al principio, algunas anotaciones no funcionaban como esperaba. Pude resolverlo, pero vale la pena destacar que para hacerlo tuve que entender por qué no funcionaban. La documentación de la página enlazada explica decentemente cómo funciona todo, pero las explicaciones no son muy amigables para principiantes.
Por eso, este post funciona como una explicación a fondo de varios temas:
- Por qué el aws-load-balancer-controller resulta confuso
- Información de contexto que ayudará a los principiantes a ponerse al día
- Detalles sobre por qué las cosas funcionan como funcionan
- Algunos consejos básicos pero útiles de troubleshooting
- Ideas sobre cómo los distintos grupos de mantenedores podrían volver esto menos confuso a futuro
Reto: un caso de identidad equivocada
Mencioné que la página enlazada arriba no me parece muy amigable para principiantes. Para que se entienda: el proyecto me resultó tan confuso que me llevó un día entero hacerme una idea clara de cómo funciona. Es una mala señal, considerando que soy SME de Kubernetes desde julio de 2018. Después de descifrarlo, lo primero que pensé fue: "Ah, ¡así que era esto! Hoy aprendí que existen dos controladores específicos de AWS para Kubernetes que pueden terminar usando anotaciones agregadas a servicios de Kubernetes del tipo Load Balancer para aprovisionar y administrar AWS LBs". Lo segundo que pensé fue: "Vaya... ¿Cómo se supone que el resto de la gente va a entender esto sin un experto al lado? Tengo que escribir un artículo sobre el tema".
Esta es la lista de cosas que vuelven confuso al proyecto AWS Load Balancer Controller:
1.) Parece funcionalidad oficial integrada, ¡pero no lo es!
Cuando busqué en Google "aws service of type lb":
Primer resultado: docs.aws.amazon.com/eks/latest/userguide/network-load-balancing.html
Segundo resultado: kubernetes-sigs.github.io/aws-load-balancer-controller/v2.4/guide/service/annotations/
Y la sección relevante de la documentación oficial de Kubernetes, que es el primer resultado al buscar "kubernetes service of type loadbalancer":
https://kubernetes.io/docs/concepts/services-networking/service/
Las tres páginas tienen pinta de documentación oficial y todas parecen hablar del mismo tema, porque las mismas anotaciones aparecen en las tres.
Si haces Ctrl+F en las tres páginas buscando:
service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags
El mismo recurso aparece en las tres. Lo que te hace pensar, a primera vista, que los tres sitios hablan de lo mismo.
En realidad, el aws-load-balancer-controller es un Add-on de Kubernetes que extiende la funcionalidad integrada. Así que dos de los enlaces anteriores cubren funcionalidad integrada y el tercero es un add-on pensado para ofrecer funcionalidad ampliada.
2.) La convención de nombres del sitio web del proyecto y de las anotaciones es muy poco intuitiva. Te hace creer que las anotaciones se refieren a funcionalidad integrada:
2A.) El DNS donde se aloja la documentación del proyecto es kubernetes-sigs.github.io
lo que da la impresión de que podría tratarse de funcionalidad integrada de Kubernetes.
2B.) Las anotaciones del add-on referencian service.beta.kubernetes.io, que normalmente está reservado para funcionalidad integrada.
3.) La página principal del sitio de documentación del proyecto no deja inmediatamente claro que se trata de un Add-on de Kubernetes pensado para extender la funcionalidad integrada.
Recién cerca del final de la segunda página de la documentación
al ver helm install aws-load-balancer-controller tu cabeza hace clic: "¡Ahhh! Es un add-on, ahora tiene sentido".
4.) El patrón que usa la API es inconsistente con el patrón habitual del resto de la comunidad de Kubernetes:
Voy a usar Cert Manager y EBS Volume CSI (Container Storage Interface) Driver como dos ejemplos de patrones normales:
- En el caso de la documentación de cert-manager, el 95% de sus anotaciones usa
cert-manager.io. A simple vista queda claro que las anotaciones corresponden a un add-on de terceros. - La primera oración de la página de inicio de la documentación es "cert-manager adds certificates and certificate issuers as resource types in Kubernetes clusters…"; eso aclara desde el inicio que el proyecto es una extensión que agrega funcionalidad.
- En el caso del EBS Volume CSI Driver, se usa una convención de nombres que distingue de un vistazo, intuitivamente, que es algo distinto de la funcionalidad integrada.
La Storage Class de AWS integrada usa provisioner: kubernetes.io/aws-ebs
La Storage Class del Add-on de EBS usa provisioner: ebs.csi.aws.com
- Es muy común que las páginas iniciales de varios sitios de documentación de EBS CSI repitan desde el inicio que se trata de un add-on que no se instala por defecto. La documentación de este proyecto incluso incluye a propósito la palabra "driver" para hacerlo más 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". Y, por si la gente cae en la página de GitHub en lugar de en la documentación, hasta la página de GitHub del proyecto incluye un enlace a "Driver Installation".
5.) La interfaz y la documentación de AWS también son inconsistentes en lo que respecta al aws-load-balancer-controller:
AWS Load Balancer Controller tiene una guía de usuario en docs.aws.amazon.com titulada "Installing the AWS Load Balancer Controller add-on".
Pero si miras en la GUI no aparece como un add-on oficial, ni siquiera al hacer clic en "Get more add-ons" donde sí ves Amazon EBS CSI Driver y AWS Distro for OpenTelemetry.

6.) Al proyecto le falta información de contexto
La página de anotaciones de servicio de la documentación menciona brevemente dos temas que conviene entender (porque entenderlos ayuda al troubleshooting) y que son casi imposibles de asimilar para un recién llegado sin más explicación. Si intentas buscarlos en Google, la información que encuentras es muy vaga, fragmentada y, en apariencia, contradictoria, salvo que logres captar muchos matices.
Los dos temas a los que me refiero, mencionados de pasada y sin explicación en la documentación, son:
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."
En un mundo ideal habría una definición resumida de qué significan esos términos y un enlace a lecturas adicionales para quien quiera profundizar. Así los resumiría yo: técnicamente son dos cosas distintas, pero, a efectos prácticos, son lo mismo. El Legacy AWS Cloud Provider es lo que provee la funcionalidad integrada por defecto para aprovisionar servicios del tipo Load Balancer en clusters de Kubernetes que corren en AWS.
Información de contexto
Cada vez que hago troubleshooting de algo, lo primero que intento es entenderlo. El tema del aprovisionamiento de AWS LBs requiere bastante contexto para comprenderlo a fondo. Lamentablemente, hasta hoy esa información estaba dispersa, nunca se explicaba en profundidad y estaba llena de matices difíciles de digerir. Este es mi intento de consolidar algunas piezas clave de contexto y volverlas fáciles de entender.
Contexto de los temas clave:
1.) kube-controller-manager vs cloud-controller-manager vs aws-cloud-controller-manager
Hay matices en lo que significan "in-tree" y "Legacy AWS Cloud Provider" que cuesta entender sin tener algo de contexto sobre estos temas relacionados, así que partamos de aquí.
En el pasado, Kubernetes tenía cuatro componentes en el plano de control: el controller-manager, el scheduler, el api-server y etcd. Corrías kube-controller-manager o cloud-controller-manager, pero no los dos.
El cloud-controller-manager era la opción que se usaba el 95% de las veces. Tenía la misma funcionalidad que el kube-controller-manager, más soporte integrado para interactuar con varias APIs de CSP (Cloud Service Provider). Como sabía cómo hablar con las APIs de CSP, podía hacer cosas como aprovisionar volúmenes AWS EBS y AWS Load Balancers.
El kube-controller-manager es una implementación cloud-agnostic, así que no trae integrada la capacidad de auto-aprovisionar almacenamiento de CSP ni Load Balancers de CSP.
Hoy en día, Kubernetes suele tener cinco componentes en el plano de control:
etcd, kube-api-server, kube-scheduler, kube-controller-manager y un controller manager específico de CSP, como aws-cloud-controller-manager. Los diagramas de la documentación oficial de Kubernetes se actualizaron para reflejar esta nueva arquitectura. También puedes verificarlo con métodos de despliegue como kops o kubeadm, que te permiten ver el plano de control. El cambio principal es que ahora hay cloud controller managers dedicados a un solo proveedor de servicios en la nube y están pensados para correr junto al kube-controller-manager. En cambio, el cloud-controller-manager original era más bien una solución universal todo-en-uno.
2.) "In-tree" se refiere a la época en la que las librerías de Go que sabían cómo interactuar con varias APIs de CSP estaban en el repo de Kubernetes para construir una imagen de contenedor universal de Kubernetes Cloud Controller Manager:
In-tree: código que vive en el repositorio principal de Kubernetes, k8s.io/kubernetes.
Out-of-Tree: código que vive en un repositorio externo, fuera del repo de git k8s.io/kubernetes.
El código base de Kubernetes 1.14 traía integradas APIs de 8 CSPs distintos. Se querían agregar más, y el hecho de que estuvieran todas empaquetadas juntas obligaba a que todas alcanzaran estabilidad al mismo tiempo para una release. Era un patrón insostenible desde el punto de vista de mantenimiento. Para resolverlo, se aprobó una KEP (Kubernetes Enhancement Proposal). Proponía desacoplar la funcionalidad de CSP de Kubernetes y refactorizarla en add-ons.
Este desacople simplificaría el proceso de release de Kubernetes y permitiría a los proveedores de nube lanzar funciones y correcciones de bugs de manera independiente al ciclo de release y a los procesos de Kubernetes. Fue una decisión para saldar deuda técnica y asegurar la salud a largo plazo del proyecto.
3.) Si intentas investigar este tema por tu cuenta, es fácil toparte con información que a primera vista parece contradictoria, hasta que captas varios matices. Aquí van algunos, sin un orden particular:
- Parece que la migración de in-tree a out-of-tree está tomando años. También hay mucha información que sugiere que arrancó hace mucho y terminó hace mucho. Que arrancó y terminó en momentos distintos. Y que sigue en curso.
- Antes mencioné que el código base de Kubernetes 1.14 tenía APIs para ocho CSPs distintos.
Si miras el código base de Kubernetes 1.26, todavía vas a ver cuatro CSPs distintos in-tree. AWS sigue apareciendo en la lista de CSPs in-tree. Pero existe un repo de git out-of-tree que referencia al aws-cloud-provider y da a entender que AWS terminó su migración allá por la 1.20.
Mientras que la KEP sugiere que la migración terminará alrededor de la versión 1.27.
Cosas como esta son la razón por la que preferí escribir un artículo en vez de contribuir a corregir un issue de la documentación. Aunque AWS y otros CSPs todavía existen in-tree, en una versión universal de CSP del cloud controller manager, esa versión no es la que se usa en la práctica. AWS y otros CSPs usan su propia implementación específica, como aws-cloud-controller-manager, en lugar del antiguo cloud-controller-manager universal todo-en-uno in-tree.
Cada CSP fue completando su migración del universal in-tree al específico de CSP out-of-tree a su propio ritmo. Otra cosa un poco confusa es que este esfuerzo complejo se dividió en dos partes. La funcionalidad integrada in-tree original incluía lógica para aprovisionar almacenamiento de CSP y LBs de CSP. No solo se sacó out-of-tree, sino que se desacopló todavía más, de modo que los drivers CSI para almacenamiento de CSP se convirtieron en un componente aislado, con sus propios cronogramas de migración.
- Cuando dimensionas la complejidad de ese refactor, varias cosas empiezan a tener sentido. Primero, no es de extrañar que haya tomado más de 4 años. La función de implementaciones out-of-tree de cloud provider alcanzó estado beta en la versión 1.11, en mayo de 2019. Segundo, cuando entiendes que se aplicaron varios feature freezes para apoyar la migración, se vuelve más claro por qué cosas como los bugs asociados a implementar
ExternalTrafficPolicy: Localen AWS LBs tardaron años en corregirse. También explica por qué la lógica integrada de aprovisionamiento de AWS LB no recibió muchas mejoras durante años.
4.) "Legacy AWS Cloud Provider" se refiere, básicamente, a la funcionalidad por defecto de aprovisionamiento de load balancer disponible en una instalación por defecto de EKS o Kubernetes en AWS.
Hay algunos matices que impiden que esta afirmación sea 100% precisa, pero está lo bastante cerca de la realidad como para ser útil.
Los matices son los siguientes:
- Legacy AWS Cloud Provider puede referirse a la lógica específica de AWS que existía in-tree, en el cloud-controller-manager (universal de CSP), capaz de aprovisionar volúmenes AWS EBS y AWS LBs.
- Legacy AWS Cloud Provider también puede referirse a la lógica de aprovisionamiento de load balancer por defecto presente en aws-cloud-controller-manager.
- aws-cloud-controller-manager suele ser invisible para los usuarios.
– Si usas EKS, aws-cloud-controller-manager corre en los managed master nodes que no puedes ver.
– Si usas kops o kubeadm, que usan master nodes auto-gestionados, sí lo ves.
– Si usas RKE2 no lo ves, por ciertos detalles de implementación de seguridad en profundidad que aplican para correr ciertos componentes del plano de control como procesos aislados de Kubernetes.
- Legacy AWS Cloud Provider puede referirse a dos cosas distintas, pero en el contexto de los AWS LBs son, en la práctica, lo mismo, ya que soportan las mismas anotaciones. Puedes encontrar las 22 anotaciones originales buscando en esta página la cadena
const ServiceAnnotationLoadBalancer. Ten en cuenta que, al momento de escribir esto, si buscas la cadenaservice.beta.kubernetes.io/aws-load-balanceren la página de documentación solo verás 21 anotaciones. Eso es solo un issue de la documentación, no un cambio en el código.
Aquí va la lista de las 22 anotaciones a las que tienes acceso por defecto:
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.) El proyecto AWS Load Balancer Controller es conceptualmente parecido al proyecto AWS EBS CSI Driver:
Ambos representan el desacople de lógica de Controller de Kubernetes que solía vivir in-tree en el cloud-controller-manager universal todo-en-uno. Los dos compartían el objetivo de garantizar la compatibilidad hacia atrás. Una parte de mí se pregunta si esto influyó en la decisión del proyecto de reutilizar algunas anotaciones.
6.) Los proyectos del Add-on EBS CSI Driver y del Add-on AWS LB Controller los iniciaron grupos distintos.
El proyecto del Add-on EBS CSI Driver lo arrancó AWS. El proyecto del Add-on AWS LB Controller lo iniciaron originalmente Ticketmaster y CoreOS, y antes se llamaba "AWS ALB Ingress Controller". Fue donado a Kubernetes SIG-AWS en 2018. Originalmente, al ALB Ingress Controller se lo describía mejor como un controlador de Application Load Balancer. Con el tiempo, el alcance del proyecto se amplió para cubrir también el control de NLBs. Por eso, en julio de 2021, el proyecto pasó a llamarse "AWS Load Balancer Controller".
¿Por qué las cosas son como son?
Si la lógica del cloud-controller-manager universal todo-en-uno no se hubiera migrado out-of-tree a add-ons externos desacoplados, la deuda técnica habría frenado de forma permanente todo el desarrollo futuro de funciones y correcciones de bugs. Recuerdo una época en la que los bugs relacionados con externalTrafficPolicy: local reaparecían una y otra vez y tardaron años en arreglarse bien. Ahora que la lógica está desacoplada del código, del proceso de release y del testing del proyecto oficial de Kubernetes, los bugs se arreglan en meses en vez de años, y se pueden volver a considerar solicitudes de nuevas funciones.
Un desarrollo más ágil ha derivado en grandes mejoras, como volver más fácil de implementar el concepto de un Software Defined Perimeter vía Authn/z Proxy, gracias a la nueva integración de AWS Cognito con la lógica de aprovisionamiento de ALB. El proyecto AWS LB Controller también tiene más opciones a la hora de aprovisionar NLBs vía anotaciones. Una nueva función que me gusta especialmente es la anotación service.beta.kubernetes.io/aws-load-balancer-nlb-target-type:, que te permite elegir cómo se enruta el tráfico hacia los pods backend. El valor por defecto "instance" hace que el tráfico vaya de nELB -> NodePort -> servicio Kube -> Pod. Un valor recién agregado, "ip", hace que el tráfico pueda ir nELB -> Pod, parecido a cómo funciona aELB.
Referencia abreviada:
nELB = network Elastic Load Balancer (LB L4 como servicio)
aELB/ALB = application Elastic Load Balancer (LB L7 como servicio)
cELB = classic Elastic Load Balancer (LB L4/L7 como servicio)
Sospecho que parte de la razón por la que el proyecto antes conocido como ALB Ingress Controller terminó incorporando la gestión de nELBs es que probablemente estaba más abierto a cambios y nuevas funciones en una época en la que el aws-cloud-controller-manager tenía un feature freeze para apoyar la migración in-tree.
¿Y por qué AWS Load Balancer Controller no se parece más al Add-on AWS EBS CSI Driver? Creo que tiene que ver con que AWS tuvo control sobre el proyecto EBS CSI de principio a fin. En cambio, el proyecto LB Controller fue adoptado, y las grandes organizaciones suelen implementar cambios despacio por la ley de Brooks. (La sobrecarga de comunicación en organizaciones grandes ralentiza significativamente los cambios.)
Tips de troubleshooting de AWS LB Controller
Estos tips de troubleshooting no pretenden ser extensos ni exhaustivos. Buscan ser apenas lo suficientemente útiles para sacarte del atasco y orientarte hacia temas que valga la pena investigar después.
1.) Determina si AWS LB Controller está instalado
kubectl get deployments --namespace=kube-system
Esto importa porque puede generar cambios significativos de comportamiento. Si tienes dos clusters con el 99% de los mismos workloads en YAML y la misma configuración desplegada, y la diferencia del 1% entre ellos es si AWS LB Controller está instalado o no, ese yaml casi idéntico puede dar resultados distintos.
2.) Considera seriamente actualizar a la versión más reciente
Puedes usar el siguiente comando para ver qué versión estás corriendo:
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
Aquí va un caso reciente del mundo real donde mantenerse al día resultó útil:
EKS 1.21 llegó al fin de su vida útil el 15 de febrero de 2023. Algunos usuarios de AWS LB Controller sufrieron interrupciones hasta que actualizaron de 2.3.x → 2.4.x. Las interrupciones se debieron a que la actualización de Kubernetes 1.21 a 1.22 eliminó muchas APIs en desuso. AWS LB Controller 2.4.x soporta la API Ingress más reciente networking.k8s.io/v1. La 2.3.x solo soporta la API más antigua networking.k8s.io/v1beta1, que se quitó en Kubernetes 1.22. Los issues del proyecto aws-lb-controller detectaron que esto sería un problema e hicieron que las versiones 2.4.x funcionaran con Kubernetes 1.19++, lo que dio tiempo a las organizaciones para migrar. Las que siguen la buena práctica de mantener sus add-ons al día evitaron las interrupciones. Las que hacen un mantenimiento mínimo probablemente se toparon con este problema cuando, eventualmente, tuvieron que actualizar Kubernetes para quedarse en una release soportada.
3.) Léete toda la documentación de instalación de punta a punta; es fácil pasar por alto algún requisito:
Además de instalar el aws-load-balancer-controller en el namespace kube-system y configurar correctamente los roles de IAM, también tienes que etiquetar bien las subnets de las VPCs.
# Snippet de configuración de VPC en Terraform como códigomodule vpc { ... public_subnet_tags = { "kubernetes.io/role/elb" = "1" } private_subnet_tags = { "kubernetes.io/role/internal-elb" = "1" }}
/*Información de contexto adicional:Si miras la documentación de EKShttps://aws.amazon.com/premiumsupport/knowledge-center/eks-load-balancer-controller-subnets/Verás una referencia a"kubernetes.io/cluster/${local.cluster_name}" = "shared"Esa etiqueta era requerida por versiones más antiguas de aws-load-balancer-controller*/4.) Si necesitas depurar un objeto ingress, revisa qué Ingressclasses están instaladas
kubectl get ingressclass
Si ves más de una, ejecuta kubectl describe ingressclass y revisa si alguna ingress class tiene una anotación que la marque como predeterminada.
Si la ingress class de alb no está marcada como predeterminada, lista explícitamente la ingress class deseada en el objeto ingress que quieres depurar.
5. Si necesitas depurar anotaciones de aprovisionamiento de LB específicas para objetos service, la cosa se complica un poco… Por qué se complica:
En la práctica, tendrías dos controladores distintos corriendo en el mismo cluster al mismo tiempo.
En el caso de EKS, al ser un servicio gestionado y tener Master Nodes de Kubernetes gestionados, solo puedes ver visualmente uno de los dos controladores. (No verás aws-cloud-controller-manager, porque corre en los managed master nodes.)
Los dos controladores se solapan bastante en cuanto a funcionalidad y a los objetos de los que son responsables:
– aws-cloud-controller-manager: aprovisiona cELBs y nELBs
– aws-load-balancer-controller: aprovisiona aELBs y nELBs
5A.) Determina qué controlador está gestionando activamente tu objeto service de Kubernetes.
Según esta documentación, si anotas un service de Kubernetes con cualquiera de estas opciones:
service.beta.kubernetes.io/aws-load-balancer-type: nlb-ip
service.beta.kubernetes.io/aws-load-balancer-type: external
Entonces el controlador aws-cloud-controller-manager ignorará el objeto, para que aws-load-balancer-controller pueda gestionarlo.
5B.) Si aws-load-balancer-controller está gestionando un service, ¡kubectl describe service se vuelve útil!
Quien haya probado opciones avanzadas de LB seguramente se habrá topado con un escenario donde el LB queda atascado en estado pending y se niega a aprovisionarse. Supongamos que ejecutas kubectl describe service $NAME para depurarlo. Si el service lo gestiona el Legacy AWS Controller Manager, lo más probable es que recibas un mensaje de error inservible. Si lo gestiona aws-load-balancer-controller, vas a recibir mensajes de error realmente útiles para depurar. (Son geniales para señalar si te equivocaste en algún paso de la instalación, como omitir permisos de IAM o saltarte el etiquetado de subnets.)
5C.) Echa un vistazo a las release notes para tener en cuenta los cambios que correspondan:
- aws-cloud-controller-manager aprovisiona LBs con IPs públicas por defecto. Hay que agregar configuración para aprovisionar IPs privadas. Con aws-load-balancer-controller pasa lo contrario. (desde la v2.2.0)
- aws-cloud-controller-manager aprovisiona cELBs por defecto. aws-load-balancer-controller aprovisiona nELBs por defecto (para cualquiera anotado con
service.beta.kubernetes.io/aws-load-balancer-type: external, ya que eso define qué controlador queda a cargo). - Las imágenes de contenedor de aws-cloud-controller-manager solían estar disponibles en Docker Hub, pero a partir de la v2.4.6 solo se alojarán en el registro de contenedores public.ecr.aws de aquí en adelante.
5D.) La mayoría de los objetos de Kubernetes soporta reconciliation loops que llevan el estado actual al estado deseado. Los controladores de Load Balancer suelen tener algunos casos límite donde hay que eliminar y volver a crear para que los cambios iterativos surtan efecto.
Casi nunca hace falta, pero a veces vale la pena intentarlo; la anotación de 5A es un ejemplo donde la documentación recomienda recrear en lugar de modificar. También vale la pena señalar que los valores nlb-ip y external son específicos del AWS LB Controller; el controlador legacy usa los valores nlb y (en blanco aprovisiona un cELB). Este detalle puede ser importante para quien use un controlador GitOps como ArgoCD o Flux para hacer cambios iterativos, ya que estos suelen actualizar manifiestos en lugar de eliminar y recrear recursos. Así que si un usuario de ArgoCD o Flux estuviera probando cambios iterativos en un entorno de desarrollo, podría necesitar intervenir manualmente en este caso límite para ver sus cambios aplicados.
Tuve dos motivos principales para escribir esto. El primero fue compartir conocimiento, y esa parte ya está hecha. El segundo, ayudar a impulsar cambios que vuelvan todo esto menos confuso. Hay tres cambios que los mantenedores del proyecto y de la documentación podrían hacer y que ayudarían muchísimo a despejar la confusión. Todos pasan por que aws-load-balancer-controller se parezca más al proyecto EBS-CSI:
- Sumar el proyecto a la lista de add-ons oficiales de EKS instalables desde la GUI de la AWS Console.
- Actualizar la documentación en varios lugares para dejar claro de inmediato que aws-load-balancer-controller es un add-on.
- Actualizar las anotaciones para que, en lugar de referenciar
kubernetes.io, se parezcan más aebs.csi.aws.com. Esto vuelve evidente su condición de add-on con solo inspeccionarlas y tiene un efecto SEO (search engine optimization) que mejoraría la experiencia al buscar la documentación relevante.