Chris McGrath, da DoiT, explica o Kubernetes AWS LB Controller e como ele funciona nos bastidores.

BLUF
Existe uma convenção na comunidade Kubernetes pela qual recursos nativos do Kubernetes referenciam kubernetes.io no nome, enquanto Add-ons do Kubernetes não fazem isso. Os Add-ons costumam seguir uma convenção autoexplicativa, como ebs.csi.aws.com, em que dá para perceber de cara que se trata de um add-on. O add-on aws-load-balancer-controller foge dessa convenção.
Público-alvo
Este artigo tem três públicos/objetivos:
1. Administradores Kubernetes que rodam EKS ou distribuições genéricas de Kubernetes na AWS: você não precisa ler agora, mas recomendo salvar nos favoritos e guardar na memória que ele existe como material de referência, caso um dia precise depurar o provisionamento de AWS Load Balancers usando Kubernetes Services com anotações como service.beta.kubernetes.io/aws-load-balancer-*.
2. Curiosos de Kubernetes que gostam de artigos aprofundados para entender melhor a plataforma.
3. Mantenedores de EKS, aws-cloud-controller-manager, aws-load-balancer-controller e da documentação da AWS: minha intenção com este artigo é jogar luz sobre uma inconsistência confusa, exclusiva do provisionamento de Load Balancers Kubernetes na AWS. Espero que ele incentive uma aproximação com o padrão do restante da comunidade Kubernetes. (O problema atravessa vários repositórios git e sites de documentação, então não dá para resolver com alguns merge requests.)
Introdução
Recentemente comecei uma prova de conceito que envolvia provisionar AWS Load Balancers para um cluster EKS (Elastic Kubernetes Service) usando Kubernetes services do tipo LoadBalancer com anotações no formato service.beta.kubernetes.io/aws-load-balancer-*, listadas nesta página.
De início, algumas anotações não funcionaram como eu esperava. Consegui resolver, mas vale destacar que, para isso, precisei entender por que não estavam funcionando. A documentação da página linkada explica razoavelmente bem como tudo funciona, mas as explicações não são muito amigáveis para quem está começando.
Por isso, este post servirá como uma explicação aprofundada de vários tópicos:
- Por que o aws-load-balancer-controller é confuso
- Informações de contexto que vão ajudar iniciantes a se situarem
- Detalhes sobre por que as coisas funcionam do jeito que funcionam
- Algumas dicas básicas, mas úteis, de troubleshooting
- Ideias de como diferentes grupos de mantenedores poderiam tornar isso menos confuso no futuro
Desafio: um caso de identidade trocada
Mencionei que a página linkada acima não me parece muito amigável para iniciantes. Para deixar claro: achei o projeto confuso o bastante para gastar um dia inteiro até entender direito. Isso é um péssimo sinal, considerando que sou SME de Kubernetes desde julho de 2018. Depois que a ficha caiu, meu primeiro pensamento foi: "Ah, é isso que está rolando. TIL (Today I learned, ou "hoje aprendi") que existem dois Kubernetes Controllers diferentes, específicos da AWS, que podem acabar usando anotações em Kubernetes Services do tipo Load Balancer para provisionar e gerenciar AWS LBs." O segundo pensamento foi: "poxa... como é que outras pessoas vão descobrir isso sem um especialista por perto? Preciso escrever um artigo sobre isso."
Veja a lista de pontos que tornam o AWS Load Balancer Controller Project confuso:
1.) Parece funcionalidade oficial nativa, mas não é!
Quando pesquisei no Google por "aws service of type lb":
Primeiro 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/
E a seção correspondente da documentação oficial do Kubernetes, que é o primeiro resultado quando você busca por "kubernetes service of type loadbalancer":
https://kubernetes.io/docs/concepts/services-networking/service/
As três páginas têm cara de documentação oficial e parecem tratar do mesmo assunto, porque as mesmas anotações aparecem em todas elas.
Se você der Ctrl+F nas três páginas procurando por:
service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags
O mesmo recurso aparece em todas. Isso passa a impressão, à primeira vista, de que os três sites estão falando da mesma coisa.
Na prática, o aws-load-balancer-controller é um Kubernetes Add-on que estende a funcionalidade nativa. Ou seja, dois dos links acima cobrem funcionalidade nativa e o terceiro é um add-on que oferece funcionalidade estendida.
2.) A convenção de nomes usada pelo site do projeto e pelas anotações é muito pouco intuitiva. Ela leva você a pensar que as anotações se referem a funcionalidade nativa:
2A.) O nome DNS onde a documentação do projeto está hospedada é kubernetes-sigs.github.io
e isso passa a impressão de que poderia ser funcionalidade nativa do Kubernetes.
2B.) As anotações do add-on referenciam service.beta.kubernetes.io, o que normalmente é reservado para funcionalidade nativa.
3.) A página inicial do site de documentação do projeto não deixa claro de cara que se trata de um Kubernetes Add-On para estender a funcionalidade nativa.
Só quando você chega perto do final da segunda página da documentação
e bate o olho em helm install aws-load-balancer-controller é que cai a ficha: "Aaah! É um add-on, ok, agora faz sentido."
4.) O padrão da API destoa do padrão usado no resto da comunidade Kubernetes:
Vou usar Cert Manager e EBS Volume CSI (Container Storage Interface) Driver como exemplos de padrões normais:
- No caso da documentação do cert-manager, 95% das anotações usam
cert-manager.io. Isso já deixa intuitivamente claro, à primeira vista, que as anotações se referem a um add-on de terceiros. - A primeira frase da página inicial da documentação é "cert-manager adds certificates and certificate issuers as resource types in Kubernetes clusters…". Isso ajuda a deixar claro logo de cara que o projeto é uma extensão que adiciona funcionalidade.
- No caso do EBS Volume CSI Driver, é usada uma convenção de nomes que ajuda a distinguir claramente, à primeira vista, que se trata de algo diferente da funcionalidade nativa.
A Storage Class nativa da AWS usa provisioner: kubernetes.io/aws-ebs
A Storage Class do Add-on EBS usa provisioner: ebs.csi.aws.com
- É bem comum que as páginas iniciais de várias documentações do EBS CSI deixem claro repetidamente, logo de cara, que se trata de um add-on que não vem instalado por padrão. A documentação deste projeto chega a incluir propositalmente a palavra-chave "driver" para tornar isso mais 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, caso a pessoa caia na página do GitHub em vez de na documentação, até a página inicial do projeto no GitHub traz um link para "Driver Installation".
5.) A UI e a documentação da AWS também são inconsistentes quando o assunto é o aws-load-balancer-controller:
O AWS Load Balancer Controller tem um guia do usuário em docs.aws.amazon.com intitulado "Installing the AWS Load Balancer Controller add-on".
Mas, se você olhar na GUI, ele não aparece como add-on oficial, nem mesmo quando você clica em Get more add-ons e vê Amazon EBS CSI Driver e AWS Distro for OpenTelemetry.

6.) O projeto não traz informações de contexto
A página de anotações de service da documentação menciona rapidamente dois tópicos que são úteis de entender (porque entendê-los facilita o troubleshooting) e quase impossíveis de um iniciante absorver sem explicação adicional. Se você tentar pesquisar esses tópicos no Google, vai encontrar informações vagas, fragmentadas e aparentemente contraditórias, a menos que consiga captar muitas nuances.
Os dois tópicos que cito, mencionados rapidamente sem explicação na documentação, são:
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."
Em um mundo ideal, haveria uma definição resumida do que cada termo significa e um link para leitura adicional para quem se interessasse. Resumindo do meu jeito: tecnicamente são duas coisas diferentes, mas, na prática, dá quase no mesmo. O Legacy AWS Cloud Provider é o que fornece a funcionalidade nativa padrão de provisionar services do tipo Load Balancer para clusters Kubernetes rodando na AWS.
Informações de contexto
Sempre que estou fazendo troubleshooting, a primeira coisa que faço é tentar entender o assunto. O tema de provisionamento de AWS LBs exige bastante informação de contexto para ser totalmente compreendido. Infelizmente, até hoje, esse conteúdo estava espalhado, nunca aprofundado e cheio de nuances que dificultam o entendimento. Esta é minha tentativa de consolidar algumas peças-chave de contexto e deixá-las fáceis de digerir.
Contexto dos tópicos-chave:
1.) kube-controller-manager vs cloud-controller-manager vs aws-cloud-controller-manager
Existem nuances no que "in-tree" e "Legacy AWS Cloud Provider" significam, e elas são difíceis de entender sem o contexto desses tópicos relacionados, então vamos começar por aqui.
Antigamente, o Kubernetes tinha quatro componentes de control plane: o controller-manager, o scheduler, o api-server e o etcd. Você rodava ou o kube-controller-manager ou o cloud-controller-manager, nunca os dois.
O cloud-controller-manager era a opção usada em 95% dos casos. Ele tinha as mesmas funcionalidades do kube-controller-manager, além de suporte nativo para conversar com várias APIs de CSP (Cloud Service Provider). Como sabia se comunicar com APIs de CSPs, conseguia fazer coisas como provisionar volumes AWS EBS e AWS Load Balancers.
O kube-controller-manager é uma implementação cloud-agnostic, então não tem a capacidade nativa de fazer coisas como provisionar automaticamente Storage de CSP e Load Balancers de CSP.
O Kubernetes de hoje normalmente tem cinco componentes de control plane:
etcd, kube-api-server, kube-scheduler, kube-controller-manager e um controller manager específico de CSP, como o aws-cloud-controller-manager. Os diagramas da documentação oficial do Kubernetes foram atualizados para refletir essa nova arquitetura. Você também pode confirmar isso usando métodos de implantação como kops ou kubeadm, que permitem ver o control plane. A principal mudança é que agora você tem cloud controller managers dedicados a um único cloud service provider, e a ideia é que rodem ao lado do kube-controller-manager. Já o cloud-controller-manager original era mais uma solução universal tudo-em-um.
2.) "In-tree" se refere à época em que bibliotecas em Go que sabiam conversar com várias APIs de CSP ficavam dentro do repositório do Kubernetes para construir uma imagem de contêiner universal do Kubernetes Cloud Controller Manager:
In-tree: código que vive no repositório principal do Kubernetes, k8s.io/kubernetes.
Out-of-Tree: código que vive em um repositório externo, fora do repositório git k8s.io/kubernetes.
O code base do Kubernetes 1.14 trazia APIs para 8 CSPs diferentes embutidas. Outros provedores queriam entrar e, como tudo estava agrupado, todos precisavam atingir estabilidade ao mesmo tempo para um release. Era um padrão insustentável do ponto de vista de manutenção. Para resolver, foi aprovado um KEP (Kubernetes Enhancement Proposal) propondo desacoplar a funcionalidade de CSP do Kubernetes e refatorá-la em add-ons.
Esse desacoplamento simplificaria o processo de release do Kubernetes e permitiria que os cloud providers lançassem features e correções de bugs no próprio ritmo, independentemente do ciclo e dos processos de release do Kubernetes. Foi uma decisão de pagar dívida técnica para garantir a saúde do projeto no longo prazo.
3.) Se você tentar pesquisar o tema por conta própria, é fácil topar com informações que, à primeira vista, parecem conflitantes, até captar várias nuances. Veja algumas, em ordem aleatória:
- Aparentemente, a migração de in-tree para out-of-tree está levando anos. Também há muita informação sugerindo que ela começou há muito tempo e terminou há muito tempo. Que começou e terminou em momentos diferentes. E que ainda está em andamento.
- Mencionei antes que o code base do Kubernetes 1.14 tinha APIs para oito CSPs diferentes.
Se você olhar o code base do Kubernetes 1.26, ainda vai ver quatro CSPs diferentes in-tree. A AWS continua na lista de CSPs in-tree. Mas há um repositório git out-of-tree referenciando o aws-cloud-provider que dá a entender que a AWS encerrou a migração lá pela versão 1.20.
Já o KEP sugere que a migração será concluída por volta da versão 1.27?
É exatamente por causa de coisas assim que escolhi escrever um artigo em vez de tentar corrigir um problema na documentação. Embora a AWS e outros CSPs ainda existam in-tree, em uma versão universal de cloud controller manager, essa versão não é a usada na prática. A AWS e outros CSPs usam sua própria implementação específica, como o aws-cloud-controller-manager, em vez do antigo cloud-controller-manager universal tudo-em-um in-tree.
Os CSPs estão concluindo a migração do universal in-tree para o específico out-of-tree em ritmos diferentes. Outra coisa um pouco confusa é que esse esforço complexo foi dividido em duas partes. A funcionalidade nativa original in-tree incluía a lógica para provisionar storage de CSP e LBs de CSP. Não só isso foi para fora da árvore (out-of-tree), como também foi mais desacoplado: os CSI drivers para storage de CSP viraram um componente isolado, com cronogramas próprios de migração.
- Quando você dimensiona a complexidade desse refactor, algumas coisas começam a fazer sentido. Primeiro, não é à toa que ele já passou de 4 anos. Implementações out-of-tree de cloud provider chegaram ao status beta na versão 1.11, lá em maio de 2019. Segundo, quando você percebe que houve vários feature freezes para apoiar o processo de migração, começa a fazer sentido por que bugs como os associados à implementação de
ExternalTrafficPolicy: Localem AWS LBs levaram anos para serem corrigidos. Isso também explica por que a lógica nativa de provisionamento de AWS LBs ficou anos sem grandes melhorias.
4.) "Legacy AWS Cloud Provider" basicamente se refere à funcionalidade padrão de provisionamento de load balancer disponível em uma instalação padrão de EKS ou Kubernetes na AWS.
Algumas nuances impedem que essa frase seja 100% precisa, mas ela está perto o suficiente da verdade para ser útil.
As nuances são as seguintes:
- Legacy AWS Cloud Provider pode se referir à lógica específica da AWS que existia in-tree, no cloud-controller-manager (universal de CSP), e que conseguia provisionar AWS EBS Volumes e AWS LBs.
- Legacy AWS Cloud Provider também pode se referir à lógica padrão de provisionamento de load balancer presente no aws-cloud-controller-manager.
- O aws-cloud-controller-manager muitas vezes é invisível para os usuários.
– Se você usa EKS, o aws-cloud-controller-manager está rodando nos managed master nodes, que você não consegue ver.
– Se você usa kops ou kubeadm, que utilizam master nodes self-hosted, você consegue vê-lo.
– Se você usa RKE2, não vai vê-lo, por causa de detalhes de implementação de segurança defense in-depth que rodam certos componentes do control plane como processos isolados do Kubernetes.
- Legacy AWS Cloud Provider pode se referir a duas coisas diferentes, mas, no contexto de AWS LBs, elas são, na prática, a mesma coisa, já que suportam as mesmas anotações. Você pode encontrar as 22 anotações originais buscando, nesta página, pela string
const ServiceAnnotationLoadBalancer. Note que, na data em que escrevo isto, ao buscar a stringservice.beta.kubernetes.io/aws-load-balancerna página da documentação, você verá apenas 21 anotações. Isso é só um problema na documentação, e não uma mudança de código.
Veja a lista das 22 anotações disponíveis por padrão:
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.) O AWS Load Balancer Controller Project é conceitualmente parecido com o AWS EBS CSI Driver Project:
Ambos representam o desacoplamento da lógica de Kubernetes Controller que existia in-tree no cloud-controller-manager universal tudo-em-um. Os dois tinham o objetivo comum de garantir compatibilidade retroativa. Fico imaginando se isso pesou na decisão do projeto de reaproveitar algumas anotações.
6.) Os projetos do EBS CSI Driver Add-on e do AWS LB Controller Add-on foram iniciados por grupos diferentes.
O EBS CSI Driver Add-on Project nasceu na AWS. Já o AWS LB Controller Add-on Project foi originalmente iniciado por Ticketmaster e CoreOS e era conhecido como "AWS ALB Ingress Controller". Ele foi doado ao Kubernetes SIG-AWS em 2018. No início, o ALB Ingress Controller era melhor descrito como um Application Load Balancer Controller. Com o tempo, o escopo do projeto se expandiu para também controlar NLBs. Por isso, em julho de 2021, o projeto foi rebatizado como "AWS Load Balancer Controller".
Por que as coisas são do jeito que são?
Se a lógica do cloud-controller-manager universal tudo-em-um não tivesse sido migrada para fora da árvore, em add-ons externos desacoplados, a dívida técnica teria desacelerado permanentemente todo o desenvolvimento futuro de features e correções de bugs. Lembro de uma época em que bugs relacionados a externalTrafficPolicy: local ficavam reaparecendo e levaram anos para serem corrigidos direito. Agora que a lógica está desacoplada do código, do processo de release e dos testes do projeto Kubernetes oficial, os bugs passaram a ser corrigidos em meses, e não anos, e os pedidos de feature voltaram a ser considerados.
Um desenvolvimento mais ágil trouxe grandes melhorias, como facilitar a implementação do conceito de Software Defined Perimeter via Authn/z Proxy, graças à nova integração do AWS Cognito com a lógica de provisionamento de ALB. O AWS LB Controller project também tem mais opções para provisionar NLBs via anotações. Uma feature nova de que gosto muito é a anotação service.beta.kubernetes.io/aws-load-balancer-nlb-target-type:, que permite escolher como o tráfego será roteado para os pods de backend. O valor padrão "instance" faz o tráfego seguir nELB -> NodePort -> Kube service -> Pod. Um valor recém-adicionado, "ip", faz com que o tráfego possa ir nELB -> Pod, parecido com o jeito que o aELB funciona.
Referência abreviada:
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)
Suspeito que parte do scope creep que trouxe o gerenciamento de nELBs para o projeto antes conhecido como ALB Ingress Controller aconteceu porque o ALB Ingress Controller project provavelmente era mais aberto a mudanças e novas features justamente na época em que o aws-cloud-controller-manager estava com feature freeze para ajudar na migração in-tree.
Quanto ao motivo de o AWS Load Balancer Controller não ser mais parecido com o AWS EBS CSI Driver Add-on, acho que tem a ver com o fato de a AWS ter tido controle total sobre o projeto EBS CSI do começo ao fim. Já o LB Controller project foi adotado, e organizações grandes tendem a implementar mudanças devagar por causa da Lei de Brooks. (O overhead de comunicação em organizações grandes desacelera bastante as mudanças.)
Dicas de troubleshooting do AWS LB Controller
Estas dicas de troubleshooting não pretendem ser extensas nem exaustivas. A ideia é que sejam úteis o bastante para tirar você do impasse e apontar a direção certa para tópicos relevantes em pesquisas posteriores.
1.) Verifique se o AWS LB Controller está instalado
kubectl get deployments --namespace=kube-system
Isso é importante porque pode causar mudanças significativas de comportamento. Se você tem dois clusters com 99% dos mesmos workloads YAML e da mesma configuração implantados e a diferença de 1% entre eles é se o AWS LB Controller está ou não instalado, esses 99% de YAML semelhante podem produzir resultados diferentes.
2.) Considere seriamente atualizar para a versão mais recente
Você pode usar o seguinte comando para ver qual versão está rodando:
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
Veja um cenário recente em que a prática de manter tudo atualizado fez diferença:
O EKS 1.21 chegou ao fim da vida em 15/02/2023. Alguns usuários do AWS LB Controller tiveram indisponibilidades até atualizarem da 2.3.x → 2.4.x. As indisponibilidades aconteceram porque a atualização do Kubernetes 1.21 para o 1.22 removeu várias APIs descontinuadas. O AWS LB Controller 2.4.x suporta a API Ingress mais nova networking.k8s.io/v1. Já a 2.3.x suporta apenas a API antiga networking.k8s.io/v1beta1, que foi removida no Kubernetes 1.22. Os issue tickets do projeto aws-lb-controller perceberam que isso seria um problema e fizeram com que as versões 2.4.x funcionassem com Kubernetes 1.19++, dando tempo para as organizações migrarem. Quem segue a boa prática de manter os add-ons atualizados se livrou das indisponibilidades. Já quem faz manutenção mínima provavelmente esbarrou nesse problema depois de finalmente atualizar o Kubernetes para se manter em uma release suportada.
3.) Leia toda a documentação de instalação de ponta a ponta; é fácil deixar passar algum requisito:
Além de instalar o aws-load-balancer-controller no namespace kube-system e configurar corretamente as IAM roles, você também precisa marcar (tag) corretamente as subnets das VPCs.
# Trecho de Terraform VPC Config as Codemodule vpc { ... public_subnet_tags = { "kubernetes.io/role/elb" = "1" } private_subnet_tags = { "kubernetes.io/role/internal-elb" = "1" }}
/*Informações de contexto adicionais:Se você olhar a documentação do EKShttps://aws.amazon.com/premiumsupport/knowledge-center/eks-load-balancer-controller-subnets/Vai ver uma referência a"kubernetes.io/cluster/${local.cluster_name}" = "shared"Essa tag costumava ser obrigatória em versões mais antigas do aws-load-balancer-controller*/4.) Se você precisa depurar um objeto ingress, verifique quais Ingressclasses estão instaladas
kubectl get ingressclass
Se aparecer mais de uma, rode kubectl describe ingressclass e verifique se uma delas tem uma anotação marcando-a como padrão.
Se a ingress class do alb não estiver marcada como padrão, liste explicitamente a ingress class desejada no objeto ingress que você está tentando depurar.
5. Se você precisa depurar anotações de provisionamento de LB específicas para objetos service, a coisa fica um pouco mais complicada… Por que é complicado:
Você teria, na prática, dois controllers diferentes rodando no mesmo cluster ao mesmo tempo.
No caso do EKS, como é um serviço gerenciado/com Kubernetes Master Nodes gerenciados, você só consegue enxergar um dos dois controllers. (Você não vai ver o aws-cloud-controller-manager, porque ele está rodando nos managed master nodes.)
Os dois controllers têm bastante sobreposição em termos de funcionalidade e dos objetos pelos quais respondem:
– aws-cloud-controller-manager: provisiona cELBs e nELBs
– aws-load-balancer-controller: provisiona aELBs e nELBs
5A.) Identifique qual controller está gerenciando ativamente o seu objeto Kubernetes service.
Segundo esta documentação, se você anotar um Kubernetes service com qualquer uma destas opções:
service.beta.kubernetes.io/aws-load-balancer-type: nlb-ip
service.beta.kubernetes.io/aws-load-balancer-type: external
Então o controller aws-cloud-controller-manager vai ignorar o objeto, para que o aws-load-balancer-controller possa gerenciá-lo.
5B.) Se o aws-load-balancer-controller estiver gerenciando um service, o kubectl describe service se torna útil!
Quem já testou opções avançadas de LB provavelmente já caiu naquele cenário em que o LB fica preso no status pending e se recusa a provisionar. Suponha que você rode kubectl describe service $NAME para depurar. Se o Legacy AWS Controller Manager estiver gerenciando o service, você provavelmente vai receber uma mensagem de erro inútil. Já se for o aws-load-balancer-controller, vai receber mensagens de erro de fato úteis para depuração. (Elas são ótimas para sinalizar quando você errou alguma etapa de instalação, como permissões IAM faltando ou falha em marcar as subnets.)
5C.) Dê uma olhada nas release notes para revisar mudanças que precisam ser consideradas:
- O aws-cloud-controller-manager provisiona LBs com IPs públicos por padrão. É preciso adicionar configuração para provisionar IPs privados. Com o aws-load-balancer-controller é o contrário. ( desde a v2.2.0)
- O aws-cloud-controller-manager provisiona cELBs por padrão. Já o aws-load-balancer-controller provisiona nELBs por padrão (para qualquer service anotado com
service.beta.kubernetes.io/aws-load-balancer-type: external, já que isso controla qual controller está no comando). - As imagens de contêiner do aws-cloud-controller-manager costumavam estar disponíveis no Docker Hub, mas, a partir da v2.4.6, daqui em diante elas só serão hospedadas no container registry public.ecr.aws.
5D.) A maioria dos objetos Kubernetes suporta loops de reconciliação que levam o estado atual ao estado desejado. Os Load Balancer controllers tendem a ter alguns edge cases em que é preciso deletar e recriar para que mudanças iterativas tenham efeito.
Normalmente isso não é necessário, mas às vezes vale a tentativa; a anotação em 5A é um exemplo em que a documentação recomenda recriar em vez de modificar. Também vale destacar que os valores nlb-ip e external são específicos do AWS LB Controller; o Legacy Controller usa os valores nlb e (em branco provisiona um cELB). Esse detalhe pode ser importante para quem usa um GitOps controller como ArgoCD ou Flux para fazer mudanças iterativas, já que esses costumam atualizar manifestos em vez de deletar e recriar recursos. Então, se um usuário do ArgoCD ou Flux estiver testando mudanças iterativas em um ambiente de dev, pode precisar de intervenção manual nesse edge case para ver as alterações aplicadas.
Tive dois motivos principais para escrever isto. O primeiro foi compartilhar conhecimento, e essa parte está pronta. O segundo foi incentivar mudanças que possam tornar tudo isso menos confuso. Há três mudanças que mantenedores de projetos e de documentação poderiam fazer e que ajudariam muito a esclarecer essa confusão. Todas envolvem deixar o aws-load-balancer-controller mais parecido com o projeto EBS-CSI:
- Adicionar o projeto à lista de add-ons oficiais do EKS, instaláveis pela GUI do AWS Console.
- Atualizar a documentação em vários pontos para deixar imediatamente claro que o aws-load-balancer-controller é um add-on.
- Atualizar as anotações para que, em vez de referenciarem
kubernetes.io, fiquem mais parecidas comebs.csi.aws.com. Isso, além de tornar o status de add-on óbvio só de bater o olho, tem um efeito de SEO (search engine optimization) que melhoraria a experiência ao buscar a documentação relevante.