Pular para o conteúdo

Migrar de Ingress para Gateway API

Avançado16 min de leiturakubernetes

A Gateway API é a sucessora do Ingress: separa responsabilidades (quem opera a infraestrutura configura o Gateway; quem opera o serviço configura a HTTPRoute), padroniza o que hoje vive em anotações proprietárias e resolve divisão de tráfego e roteamento por header sem depender de extensões.

A migração pode e deve ser feita em paralelo, um serviço por vez, sem janela.

O trabalho real da migração está nas anotações — é ali que mora o comportamento que não está no spec.

Janela do terminal
kubectl get ingress -A -o json | jq -r '.items[] |
"\(.metadata.namespace)/\(.metadata.name)\t\(.metadata.annotations // {} | keys | join(","))"'

Classifique cada anotação em três grupos:

  • Vira campo nativo: reescrita de caminho, redirecionamento, timeouts, divisão de tráfego, roteamento por header.
  • Vira recurso de política do controlador (BackendTLSPolicy, filtros específicos).
  • Não tem equivalente ainda: anote e decida — adiar a migração daquele serviço costuma ser melhor que forçar.
Janela do terminal
kubectl apply -f \
https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml
kubectl get crd | grep gateway.networking.k8s.io

Depois instale (ou habilite) um controlador que a implemente — Istio, Cilium, Envoy Gateway, NGINX Gateway Fabric, ou o controlador da sua nuvem. Verifique a versão da API suportada e se ele cobre o canal standard ou também o experimental, porque parte dos recursos ainda está no segundo.

Este recurso é de quem cuida da infraestrutura, e é compartilhado por vários times.

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata: { name: producao }
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata: { name: borda, namespace: infra }
spec:
gatewayClassName: producao
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: "*.exemplo.com.br"
tls:
mode: Terminate
certificateRefs: [{ name: curinga-tls }]
allowedRoutes:
namespaces: { from: Selector, selector: { matchLabels: { rotas: permitidas } } }

allowedRoutes é o controle que o Ingress não tinha: só namespaces marcados podem anexar rotas a esta borda.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: { name: loja, namespace: loja }
spec:
parentRefs: [{ name: borda, namespace: infra }]
hostnames: ["loja.exemplo.com.br"]
rules:
- matches: [{ path: { type: PathPrefix, value: /api } }]
filters:
- type: URLRewrite
urlRewrite: { path: { type: ReplacePrefixMatch, replacePrefixMatch: / } }
backendRefs: [{ name: api, port: 80 }]
- matches: [{ path: { type: PathPrefix, value: / } }]
backendRefs:
- { name: loja-estavel, port: 80, weight: 90 }
- { name: loja-canario, port: 80, weight: 10 } # nativo, sem anotação

Equivalências que respondem a maior parte das dúvidas:

Ingress (nginx) Gateway API
rewrite-target filtro URLRewrite
canary-weight weight no backendRefs
ssl-redirect listener HTTP com filtro RequestRedirect
configuration-snippet geralmente sem equivalente — reavalie a necessidade
ingressClassName parentRefs apontando para o Gateway

A transição segura usa hostnames diferentes antes de trocar o tráfego real:

  1. Publique a HTTPRoute com um host de teste (loja-gw.exemplo.com.br) apontando para o mesmo backend.
  2. Compare respostas, cabeçalhos e códigos entre as duas bordas.
    Janela do terminal
    for p in / /api/health /produtos/1; do
    echo "$p"
    curl -s -o /dev/null -w ' ingress %{http_code} %{time_total}s\n' https://loja.exemplo.com.br$p
    curl -s -o /dev/null -w ' gateway %{http_code} %{time_total}s\n' https://loja-gw.exemplo.com.br$p
    done
  3. Confira o que costuma divergir: barra final, sensibilidade a maiúsculas no caminho, cabeçalhos de encaminhamento (X-Forwarded-*), timeouts e tamanho máximo de corpo.
  4. Mude o DNS do host real para a borda nova, com TTL já reduzido.
  5. Observe erro e latência por pelo menos um ciclo de pico.

Só depois da estabilidade confirmada, remova o Ingress antigo — e mantenha o controlador anterior instalado até o último serviço migrar.

Janela do terminal
kubectl get ingress -A # o alvo é esta lista ficar vazia
kubectl delete ingress loja -n loja
Sintoma Causa provável
HTTPRoute com Accepted=False Namespace não permitido pelo allowedRoutes, ou hostname fora do listener
404 na rota nova Ordem de match: caminhos mais específicos precisam vir antes
TLS não funciona certificateRefs em outro namespace exige ReferenceGrant
Comportamento diferente do Ingress Uma anotação sem equivalente ficou para trás
Rota some após upgrade Recurso do canal experimental não suportado na versão instalada
Janela do terminal
kubectl describe httproute loja -n loja | sed -n '/Status/,$p'
kubectl get gateway borda -n infra -o jsonpath='{.status.conditions}' | jq
  • Inventário de anotações feito e classificado.
  • Controlador compatível instalado, com versão da API conferida.
  • Gateway com allowedRoutes restrito.
  • Rotas comparadas lado a lado com host de teste.
  • Corte feito por DNS com TTL baixo, e monitorado.
  • Ingress antigo removido apenas após estabilidade.