Ingress no Kubernetes: levando sua aplicação para o mundo
1. Visão geral
Quando você já tem um Service rodando no cluster mas quer que usuários externos acessem por um domain bacana como api.nonladev.com em vez de um IP:porta confuso, é hora de usar Ingress. Este artigo explica o que é Ingress, como diferencia de Service type LoadBalancer, como instalar Ingress Controller e escrever Ingress resources para situações comuns: path-based routing, host-based routing, TLS. Depois de ler, você consegue expor sua aplicação Spring Boot para fora com um domain e HTTPS.
2. Por que precisa de Ingress
2.1. O problema com Service
Service type NodePort ou LoadBalancer funcionam bem, mas têm limitações:
LoadBalancer: cada Service precisa de um IP externo próprio → custa caro se tiver muitos services (cada cloud LB cobra separado).NodePort: expõe uma porta estranha (30000-32767), sem TLS termination, sem routing por domain/path.
Suponha que você tem 5 microservices para expor para fora, usar LoadBalancer significa 5 cloud load balancers, 5 IPs externos. Ingress resolve isso usando um entry point para rotear tráfego para muitos Services dentro do cluster, baseado no hostname ou path.
2.2. O que é Ingress
Ingress é um objeto de API que define regras de roteamento HTTP/HTTPS de fora para Services dentro do cluster. Ingress por si só não faz nada — precisa de um Ingress Controller (um Pod rodando um reverse proxy como NGINX, Traefik, HAProxy) para ler a regra e executá-la.
Cliente → Ingress Controller (LoadBalancer/NodePort) → Regras Ingress → Service → Pod
Nota: Se o cluster ainda não tem um Ingress Controller instalado, criar um Ingress resource não vai servir para nada — é só uma configuração “esperando” o controller ler.
3. Instalando o Ingress Controller
O mais comum é o ingress-nginx. Instale com Helm:
<!-- não aplicável — use Helm/kubectl, não é uma dependência Maven -->
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace
Este comando cria um namespace ingress-nginx, faz deploy do Ingress Controller junto com um Service type LoadBalancer para receber tráfego de fora. Verifique:
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
NAME TYPE EXTERNAL-IP PORT(S)
ingress-nginx-controller LoadBalancer 34.123.45.67 80:31234/TCP,443:31235/TCP
Este IP externo é o único ponto de entrada para todos os Ingresses do cluster.
4. Deployment e Service de exemplo
Antes de escrever o Ingress, você precisa de um Service para rotear tráfego. Suponha uma aplicação order-service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 2
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: nonladev/order-service:1.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
ports:
- port: 80
targetPort: 8080
O Service order-service expõe a porta 80, encaminhando para a porta 8080 do container. Note que este Service não precisa ser type LoadBalancer, usar ClusterIP (padrão) é suficiente, pois o Ingress Controller vai chamar o Service pela rede interna.
5. Ingress resource básico — host-based routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: order-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: api.nonladev.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80
Explicação de cada parte:
ingressClassName: nginx— especifica qual controller processa esta regra (importante quando o cluster tem vários controllers).rules.host— apenas tráfego com headerHost: api.nonladev.comvai corresponder esta regra.path+pathType: Prefix— qualquer requisição começando com/(tudo) será encaminhada paraorder-service:80.- annotation
rewrite-target— específica do ingress-nginx, usada para reescrever a URL antes de encaminhar (cada controller tem suas próprias annotations).
Aplique e teste:
kubectl apply -f order-ingress.yaml
curl -H "Host: api.nonladev.com" http://34.123.45.67/
{"service":"order-service","status":"UP"}
Em ambiente real, você aponta o DNS record api.nonladev.com para o IP externo do Ingress Controller, sem precisar fazer headers Host falsos como acima.
6. Path-based routing — múltiplos services compartilhando o mesmo domain
Situação comum: um domain, vários services em paths diferentes.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-gateway-ingress
spec:
ingressClassName: nginx
rules:
- host: api.nonladev.com
http:
paths:
- path: /orders
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80
- path: /customers
pathType: Prefix
backend:
service:
name: customer-service
port:
number: 80
Requisição para api.nonladev.com/orders/123 roteia para order-service, enquanto /customers/55 roteia para customer-service. pathType: Prefix significa corresponder por prefixo — diferente de Exact (tem que corresponder exatamente) e ImplementationSpecific (o controller interpreta por conta própria, geralmente regex).
Nota: A ordem dos paths não afeta o matching em Ingress v1 — o controller escolhe o path mais longo que corresponde primeiro. Mas escreva paths de forma clara, sem se sobrepor, para evitar bugs difíceis de debugar.
7. TLS — HTTPS para Ingress
Para ter HTTPS, você precisa de um Secret com cert e key, depois referenciar no Ingress.
kubectl create secret tls nonladev-tls \
--cert=tls.crt --key=tls.key
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: order-ingress-tls
spec:
ingressClassName: nginx
tls:
- hosts:
- api.nonladev.com
secretName: nonladev-tls
rules:
- host: api.nonladev.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80
spec.tls declara qual host usa qual cert. O controller automaticamente faz TLS termination — quer dizer, descriptografa HTTPS no Ingress, depois encaminha HTTP puro para o Service dentro. Seu Pod não precisa saber nada sobre TLS.
Na prática, você geralmente usa cert-manager para automaticamente pedir certificados Let’s Encrypt em vez de criar Secrets à mão:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: order-ingress-tls
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- api.nonladev.com
secretName: nonladev-tls
rules:
- host: api.nonladev.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80
A annotation cluster-issuer pede ao cert-manager para criar e renovar automaticamente o Secret nonladev-tls — você não precisa fazer mais nada manualmente.
8. Escrevendo testes para verificar endpoints depois de expor
Depois que o Ingress está funcionando, você pode escrever um test de integração simples para verificar que a classe controller do Spring Boot processa o path corretamente (teste na camada de aplicação Spring Boot, não teste o YAML diretamente):
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class OrderControllerIT {
@Autowired
private TestRestTemplate restTemplate;
@Test
void shouldReturnOrderWhenCalledWithOrdersPrefix() {
ResponseEntity<String> response =
restTemplate.getForEntity("/orders/123", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).contains("orderId");
}
}
Este teste garante que a aplicação Spring Boot responde corretamente para o path /orders/123 que o Ingress reescreve para — separando erros do código backend de erros de configuração do Ingress.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
9. Erros comuns
- Esqueceu de
ingressClassName: se o cluster tem vários Ingress Controllers (por exemplo, tanto nginx quanto traefik), o Ingress não sabe qual controller processa → não funciona ou é processado errado pelos dois. - Tipo de Service errado: deixar o Service backend como
LoadBalanceré desnecessário, gasta recursos — use apenasClusterIP. pathTypenão coincide com o esperado: usarExactquando precisa dePrefixfaz com que requisições filhas (/orders/123) retornem 404 porque apenas/orderscorresponde exatamente.- DNS ainda não aponta: teste com
curl -H "Host: ..."antes de configurar DNS real, evite perder tempo esperando DNS propagar. - Annotation de rewrite errada para o controller: as annotations do ingress-nginx não funcionam para Traefik ou AWS ALB Ingress Controller — cada controller tem seu próprio conjunto de annotations, leia cuidadosamente a documentação correspondente.
Quando NÃO usar Ingress: se sua aplicação usa um protocolo que não é HTTP/HTTPS (por exemplo, TCP puro, gRPC streaming complexo, ou UDP), Ingress padrão não suporta bem — considere
Gateway APIou Service typeLoadBalancerdireto para TCP/UDP.
10. Conclusão
Ingress é uma camada de roteamento HTTP/HTTPS centralizada que ajuda você a expor múltiplos Services para fora por um único entry point, economizando custos com LoadBalancer e facilitando o gerenciamento de domain/path/TLS. O ponto-chave a lembrar: Ingress resource é só uma regra, você precisa de um Ingress Controller para executar; escolha o ingressClassName e pathType corretos; use cert-manager para automatizar TLS. Para aplicações que não são HTTP puro, considere usar Gateway API em vez de forçar Ingress.