Ingress: roteando tráfego externo

1. Introdução ao Ingress no Kubernetes

Em um cluster Kubernetes, expor aplicações ao mundo externo é um desafio fundamental. Três abordagens principais existem:

  • NodePort: expõe cada serviço em uma porta estática em todos os nós. Problemático para produção — portas limitadas (30000–32767), sem balanceamento de carga inteligente, e expõe IPs dos nós.
  • LoadBalancer: cria um balanceador de carga externo (ex: ELB na AWS). Funcional, mas cada serviço consome um recurso de nuvem caro.
  • Ingress: um único ponto de entrada que roteia tráfego para múltiplos serviços baseado em regras de hostname e path. Econômico, flexível e padronizado.

O Ingress é um recurso da API Kubernetes que gerencia acesso externo a serviços no cluster, tipicamente HTTP/HTTPS. Ele fornece balanceamento de carga, terminação SSL e roteamento baseado em regras.

Ciclo de vida de uma requisição externa:
1. Usuário acessa app.exemplo.com
2. DNS resolve para IP do Ingress Controller (ex: IP do LoadBalancer)
3. Ingress Controller recebe a requisição, analisa hostname e path
4. Encaminha para o Service correto no namespace apropriado
5. Service faz load balance para um Pod saudável
6. Pod processa e retorna a resposta

2. Componentes Fundamentais do Ingress

Dois componentes distintos trabalham juntos:

O recurso Ingress (objeto YAML de configuração):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: meu-ingress
spec:
  rules:
  - host: app.exemplo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: meu-servico
            port:
              number: 80

O Ingress Controller (implementação real que processa as regras):
- NGINX Ingress Controller: mais popular, mantido pela comunidade Kubernetes
- Traefik: moderno, suporte nativo a Let's Encrypt
- HAProxy Ingress: alta performance, rico em recursos
- AWS Load Balancer Controller: integração nativa com ALB/NLB

A diferença crucial: o Ingress é apenas a configuração declarativa; sem um Controller instalado no cluster, ele não faz nada.

3. Configuração Básica de um Ingress

Vamos criar um exemplo prático: dois serviços sendo roteados por um único IP.

Pré-requisito: instalar o NGINX Ingress Controller:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/cloud/deploy.yaml

Manifesto completo:

# Serviço de backend API
apiVersion: v1
kind: Service
metadata:
  name: api-svc
spec:
  selector:
    app: api
  ports:
  - port: 80
    targetPort: 3000
---
# Serviço de frontend web
apiVersion: v1
kind: Service
metadata:
  name: web-svc
spec:
  selector:
    app: web
  ports:
  - port: 80
    targetPort: 8080
---
# Ingress com roteamento baseado em path
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-servico-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: meuapp.exemplo.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-svc
            port:
              number: 80
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              number: 80

Neste exemplo:
- Requisições para meuapp.exemplo.com/api vão para o serviço api-svc
- Requisições para meuapp.exemplo.com/ vão para o serviço web-svc
- A anotação rewrite-target: / remove o prefixo /api antes de encaminhar

Roteamento por hostname (virtual hosting):

spec:
  rules:
  - host: api.exemplo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-svc
            port:
              number: 80
  - host: web.exemplo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              number: 80

4. Criptografia com TLS/HTTPS no Ingress

Para habilitar HTTPS, precisamos de um Secret TLS e referenciá-lo no Ingress.

Criando certificado auto-assinado (para testes):

# Gerar certificado
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout tls.key -out tls.crt \
  -subj "/CN=meuapp.exemplo.com"

# Criar Secret no Kubernetes
kubectl create secret tls meuapp-tls \
  --cert=tls.crt --key=tls.key

Ingress com TLS:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-com-tls
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - meuapp.exemplo.com
    secretName: meuapp-tls
  rules:
  - host: meuapp.exemplo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              number: 80

Redirecionamento HTTP para HTTPS automático (com NGINX):

metadata:
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"

Para produção, use cert-manager com Let's Encrypt:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@exemplo.com
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
    - http01:
        ingress:
          class: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-producao
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - app.exemplo.com
    secretName: app-tls-prod
  rules:
  - host: app.exemplo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              number: 80

5. Técnicas Avançadas de Roteamento

Roteamento canário (traffic splitting):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-canario
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"  # 10% do tráfego
spec:
  ingressClassName: nginx
  rules:
  - host: app.exemplo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-v2-svc
            port:
              number: 80

Anotações úteis:

metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"    # Limite de tamanho do corpo
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"  # Timeout de leitura
    nginx.ingress.kubernetes.io/limit-rps: "100"          # Rate limiting (req/segundo)
    nginx.ingress.kubernetes.io/affinity: "cookie"        # Sticky sessions
    nginx.ingress.kubernetes.io/session-cookie-name: "route"

6. Operações e Troubleshooting

Comandos essenciais:

# Listar todos os Ingress
kubectl get ingress --all-namespaces

# Detalhes de um Ingress específico
kubectl describe ingress meu-ingress

# Logs do Ingress Controller
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller

# Verificar endpoints dos serviços
kubectl get endpoints meu-servico

Problemas comuns e soluções:
- DNS não resolvido: verifique se o hostname no Ingress corresponde ao registro DNS apontando para o IP do LoadBalancer
- Portas conflitantes: NGINX Controller usa portas 80 e 443 por padrão; verifique se não há conflito com outros serviços
- Certificados expirados: monitore a data de expiração com kubectl get secret meu-tls -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -enddate
- Regra não funcionando: verifique pathType (Prefix, Exact, ImplementationSpecific) e a ordem das regras (a primeira correspondência vence)

7. Integração com o Ecossistema DevOps

GitOps com ArgoCD: o manifesto Ingress é versionado no Git e sincronizado automaticamente:

# Exemplo de aplicativo ArgoCD
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: meu-app
spec:
  source:
    repoURL: https://github.com/equipe/gitops-repo
    path: k8s/ingress
  destination:
    server: https://kubernetes.default.svc
    namespace: producao
  syncPolicy:
    automated:
      prune: true

Monitoramento com Prometheus: o NGINX Ingress Controller expõe métricas em /metrics (porta 10254). Configure um ServiceMonitor:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: ingress-nginx-monitor
spec:
  endpoints:
  - interval: 30s
    port: metrics
  selector:
    matchLabels:
      app.kubernetes.io/component: controller

Integração com HPA: o Ingress não escala diretamente, mas você pode escalar os Pods baseado em métricas do Ingress:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Pods
    pods:
      metric:
        name: nginx_ingress_controller_requests
      target:
        type: AverageValue
        averageValue: 1000

Namespaces e isolamento: use namespaces para ambientes (dev, staging, prod) e Ingress específicos para cada um:

kubectl create namespace staging
kubectl apply -f ingress-staging.yaml -n staging

O Ingress é a peça central para expor aplicações Kubernetes de forma profissional. Combinado com GitOps, monitoramento e autoscaling, ele se torna a fundação de uma plataforma DevOps robusta e escalável.

Referências