Ingress Controllers Comparados: NGINX, Traefik, HAProxy e a Chegada da Gateway API
O que um Ingress Controller realmente faz, como NGINX, Traefik e HAProxy se diferenciam, e por que a Gateway API está substituindo o Ingress.
Neste artigo
Você aplicou um manifesto de Ingress no cluster, apontou o DNS, e nada acontece. Nenhum tráfego entra, o endereço não responde, e o objeto está lá, criado, aparentemente saudável. Esse é o mal-entendido número um do Kubernetes na borda: achar que o recurso Ingress, sozinho, faz alguma coisa. Ele não faz. O Ingress é só um pedaço de configuração declarativa — um conjunto de regras dizendo "tráfego para este host e este path vai para aquele Service". Quem realmente escuta na porta 443, termina o TLS e roteia a requisição é outra peça completamente separada: o Ingress Controller.
Sem um controller instalado, seus objetos Ingress são poesia que ninguém lê. O controller é um proxy reverso rodando dentro do cluster que observa a API do Kubernetes, vê os recursos Ingress que você criou, e traduz aquelas regras na configuração real de um servidor de borda. É essa distinção entre a especificação (o objeto Ingress) e a implementação (o controller) que organiza toda a discussão — e é também a raiz do problema que a Gateway API veio resolver.
Neste guia você vai entender o que um Ingress Controller efetivamente faz, por que existe uma dúzia deles com filosofias diferentes, como NGINX, Traefik e HAProxy se posicionam, por que o modelo do Ingress esbarrou num teto de vidro feito de annotations, e o que muda com a Gateway API — o sucessor oficial que separa papéis e devolve expressividade à borda do cluster.
O que um Ingress Controller realmente faz
No fundo, um Ingress Controller é um proxy reverso de camada 7 (HTTP) com uma peculiaridade: ele se reconfigura sozinho observando o cluster. Você não edita um arquivo de configuração e recarrega o processo à mão; você cria objetos Kubernetes, e o controller reage. Esse loop de observação e reconfiguração é o que o torna nativo do ambiente dinâmico onde pods aparecem e somem o tempo todo.
As funções que ele concentra são as clássicas de um proxy de borda. Ele faz terminação de TLS, descriptografando o tráfego HTTPS que chega e apresentando os certificados corretos por host. Faz roteamento baseado em host e path, decidindo que api.exemplo.com vai para um Service e loja.exemplo.com/checkout vai para outro — o famoso virtual hosting, que permite muitos sites atrás de um único IP público. Faz balanceamento de carga entre os pods de cada Service, respeitando a saúde deles. E, dependendo do controller, faz reescrita de path, redirecionamentos, rate limiting, autenticação, compressão e políticas de CORS.
O ponto delicado é justamente esse "dependendo do controller". A especificação do Ingress cobre bem o básico — host, path, TLS, backend —, mas tudo que é avançado não tem lugar no objeto padrão. Para expressar rate limiting, reescrita, timeouts, buffers, ou qualquer comportamento sofisticado, você recorre a annotations: pares chave-valor colados no objeto Ingress que o controller interpreta. E aqui mora o problema estrutural do modelo, que vamos retomar adiante.
Por que as annotations são o calcanhar de Aquiles
As annotations resolvem o problema imediato — dão acesso aos recursos avançados do proxy — mas a um custo caro: elas não são portáveis. Uma annotation como nginx.ingress.kubernetes.io/rewrite-target só faz sentido para o ingress-nginx; o Traefik ignora ela e usa a sua própria. Se você configurou dezenas de comportamentos por annotation e um dia decide trocar de controller, boa parte dessa configuração precisa ser reescrita do zero, porque cada implementação inventou o seu próprio vocabulário fora da especificação comum.
Pior: annotations são strings soltas, sem validação de schema forte, sem estrutura, sem tipos. Um erro de digitação numa annotation falha silenciosamente ou se comporta de forma inesperada, e não há um contrato claro que o cluster possa validar antes de aplicar. O resultado é que o Ingress, na prática, virou um denominador comum mínimo cercado por um cinturão de extensões proprietárias — exatamente o que uma API padronizada deveria evitar. Guarde essa dor: ela é a motivação inteira da Gateway API.
Como os principais controllers pensam
Existem muitos controllers, e comparar por benchmark de requisições por segundo costuma ser inútil, porque todos são rápidos o bastante e o gargalo raramente é o proxy. O que diferencia de verdade é a filosofia de cada um.
O ingress-nginx é o mais difundido, mantido pela comunidade Kubernetes e construído sobre o venerável NGINX. Seu modelo mental é o de sempre: ele gera um arquivo de configuração do NGINX a partir dos Ingress observados e recarrega o processo quando algo muda. É maduro, extremamente documentado, presente em quase todo cluster, e você encontra resposta para qualquer problema em segundos. A contrapartida é o acoplamento pesado a annotations e o fato de que mudanças grandes podem provocar reloads que, sob carga altíssima, exigem cuidado. Vale não confundi-lo com o "NGINX Ingress Controller" comercial mantido pela própria F5/NGINX, que é um projeto distinto com annotations e recursos próprios.
O Traefik parte de outra premissa: ele nasceu para ambientes dinâmicos de containers e trata a descoberta de configuração como cidadã de primeira classe. Em vez de gerar e recarregar arquivos, ele reconfigura suas rotas dinamicamente, sem reload disruptivo. Traz um dashboard visual, integração fácil com múltiplos provedores (não só Kubernetes), e um conjunto de CRDs próprios (os IngressRoute) que oferecem uma expressividade muito além do Ingress padrão — middlewares encadeáveis, por exemplo. O preço é sair do padrão: ao adotar os CRDs do Traefik, você adota o vocabulário do Traefik.
O HAProxy Ingress é a escolha de quem valoriza o pedigree de proxy de altíssimo desempenho e controle fino de conexão do HAProxy, tradicionalmente forte em cenários de L4 e L7 exigentes, com métricas ricas e comportamento previsível sob pressão. E há toda uma família baseada no Envoy — como o Contour e o Emissary —, que usa o proxy que também está no coração de service meshes modernos, com um plano de configuração dinâmico e recursos de tráfego avançados. Cada um resolve o mesmo problema básico com um trade-off diferente entre maturidade, dinamismo, expressividade e proximidade do padrão.
A Gateway API: o sucessor que separa papéis
A Gateway API é a resposta oficial do projeto Kubernetes às dores do Ingress, e ela não é um controller — é uma nova API padronizada, mais rica e mais bem desenhada, que os controllers implementam. A ideia central é reconhecer que a borda do cluster envolve pessoas diferentes com responsabilidades diferentes, e dar a cada uma o seu recurso.
O modelo se organiza em papéis. O provedor de infraestrutura (ou o time de plataforma) define a GatewayClass, que descreve qual implementação está no comando, e o Gateway, que representa o ponto de entrada real — as portas, os protocolos, os certificados, o balanceador. Já o time de desenvolvimento de cada aplicação define as Routes — HTTPRoute, TCPRoute, GRPCRoute e afins — que descrevem como o tráfego que chega no Gateway se distribui entre os serviços daquele time, sem precisar tocar na configuração compartilhada da borda. Essa separação de responsabilidades é o coração da proposta: o dono da plataforma controla a infraestrutura de entrada, e cada time controla o roteamento das suas próprias rotas, com fronteiras claras de permissão.
O ganho técnico é grande. A HTTPRoute expressa de forma nativa e tipada aquilo que antes vivia em annotations improvisadas: correspondência por header, por método, por query; divisão de tráfego ponderada para canary; reescrita e redirecionamento; filtros de request e response. Tudo isso com schema forte, validação e portabilidade — uma HTTPRoute escrita para uma implementação conforme funciona em outra implementação conforme, porque a semântica é definida pela especificação, não pelo vendor. É o fim, ou pelo menos a grande redução, do inferno de annotations não portáveis.
A adoção já é real. A parte central da especificação, incluindo a HTTPRoute, atingiu maturidade estável (GA), e os principais controllers — inclusive NGINX, Traefik, Envoy-based e implementações de nuvens gerenciadas — oferecem suporte à Gateway API em paralelo ao velho Ingress. Ela também é o mecanismo de entrada preferido de várias arquiteturas de mesh, unificando o tráfego norte-sul (que entra no cluster) com políticas mais ricas.
Como decidir hoje, e por onde começar
Para um site simples com poucos hosts, terminação de TLS e roteamento por path, o Ingress clássico continua perfeitamente adequado — é onipresente, bem entendido e resolve o caso comum sem cerimônia. Não há vergonha em usá-lo, e migrar por moda seria toil desnecessário. O sinal de que você passou do ponto do Ingress é começar a acumular annotations complexas, brigar com comportamentos não portáveis, ou precisar de divisão de tráfego, roteamento por header e separação de responsabilidades entre times. Aí a Gateway API deixa de ser luxo e vira a ferramenta certa.
Na escolha do controller em si, deixe a filosofia guiar. Se você quer o caminho mais batido, com respostas prontas para qualquer dúvida, o ingress-nginx é o padrão seguro. Se o seu ambiente é muito dinâmico e você valoriza reconfiguração sem reload e um modelo de middlewares expressivo, o Traefik brilha. Se performance de conexão e previsibilidade sob carga extrema são a prioridade, olhe HAProxy ou as opções baseadas em Envoy, especialmente se você já caminha para service mesh.
Independentemente do controller escolhido, lembre-se de que ele é um ponto crítico da sua arquitetura: todo o tráfego de entrada passa por ele, então ele merece o mesmo cuidado operacional que qualquer serviço de produção. Isso significa rodar múltiplas réplicas para alta disponibilidade, definir requests e limits de recursos com folga para o pico de tráfego, e — talvez o mais esquecido — instrumentar o controller com métricas e logs. Um Ingress Controller sem observabilidade é uma caixa-preta na borda mais importante do cluster: quando a latência sobe ou os erros aparecem, você quer conseguir distinguir se o problema é do proxy, do backend ou da rede, e sem métricas de latência, taxa de erro por rota e saturação de conexões você fica adivinhando no pior momento possível.
Se está começando um projeto novo hoje, a recomendação pragmática é conhecer a Gateway API desde o início: entenda os objetos GatewayClass, Gateway e HTTPRoute, escolha um controller que a implemente bem, e prefira expressar suas rotas nela em vez de empilhar annotations. Você ganha portabilidade, validação e uma separação de papéis que vai poupar dor conforme o número de times e serviços cresce. O Ingress te trouxe até aqui; a Gateway API é para onde a borda do Kubernetes está indo.