Este site utiliza cookies

Utilizamos cookies para melhorar sua experiência de navegação, personalizar conteúdo e analisar nosso tráfego. Ao clicar em 'Aceitar', você concorda com o uso de cookies conforme nossa Política de Privacidade.

Virtualização

Migrando do Ingress NGINX para o Gateway API com Istio – O Guia do Procrastinador

VMware
02 de abril de 2026
13 min de leitura
Compartilhar:
Migrando do Ingress NGINX para o Gateway API com Istio – O Guia do Procrastinador

Por que Você Está Lendo Isso (e Por Que Não É Tarde Demais)

O prazo final: 31 de março de 2026 — três dias a partir de agora. A situação: Ingress NGINX deixa de receber patches de segurança para sempre. A realidade: Você ainda o está executando em produção.

Em novembro de 2025, o projeto Kubernetes anunciou a descontinuação do Ingress NGINX. Se você esperou até o último minuto, não está sozinho; a atividade de migração aumentou 300% em fevereiro-março de 2026, enquanto as equipes corriam para cumprir o prazo. Migrei um conjunto de demonstração com múltiplos aplicativos (Bookstore, Reader, Chatbot) em dois clusters VMware vSphere Kubernetes Service (VKS) com zero tempo de inatividade em menos de 8 horas. Um cluster usa Helm, o outro Kustomize + ArgoCD. Este é o playbook exato que segui, incluindo os três "problemas" que consumiram horas de depuração.

O substituto: Gateway API — o sucessor oficial do Ingress, com mais de 20 implementações oficialmente disponíveis (GA) em 2026. É mais expressivo, mais portátil e elimina o vendor lock-in através da proliferação de anotações.

Por que Istio? O VKS o oferece como um pacote padrão (add-on), o que significa nenhuma complexidade de instalação personalizada. Além disso, é a implementação de Gateway API número 1 em termos de adoção e abre as portas para recursos de service mesh posteriormente. Para um guia detalhado do Istio no VKS, consulte nosso guia anterior. As alternativas (Cilium, Envoy Gateway, Traefik) são todas viáveis, mas o Istio teve o caminho mais curto para ambientes VKS e fiquei intrigado com esta análise.

O Que Mudou

A migração afetou três camadas: pré-requisitos (nível de cluster), templates de Helm chart e manifestos do Kustomize. Aqui está exatamente o que mudou e por quê.

Antes: Ingress NGINX

Cada aplicativo tinha um recurso Ingress com anotações específicas do NGINX:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: bookstore-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
spec:
  ingressClassName: nginx
  rules:
    - host: bookstore-test.corp.vmbeans.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app-service
                port:
                  number: 80

Cada personalização de comportamento era uma anotação específica do fornecedor. Trocar de controller? Reescrever todas as anotações.

Depois: Gateway API + Istio

Um recurso Gateway compartilhado define o ponto de entrada, e cada aplicativo recebe um HTTPRoute portátil:

yaml
# Gateway -- um por cluster, compartilhado por todos os aplicativos
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: demo-gateway
  annotations:
    cert-manager.io/cluster-issuer: demo-issuer
spec:
  gatewayClassName: istio
  listeners:
    - name: http
      port: 80
      protocol: HTTP
      allowedRoutes:
        namespaces:
          from: All
    - name: https
      port: 443
      protocol: HTTPS
      tls:
        mode: Terminate
        certificateRefs:
          - name: demo-tls
      allowedRoutes:
        namespaces:
          from: All
yaml
# HTTPRoute -- um por aplicativo, referenciando o Gateway compartilhado
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: bookstore-route
spec:
  parentRefs:
    - name: demo-gateway
      namespace: bookstore
  hostnames:
    - "bookstore-test.corp.vmbeans.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: app-service
          port: 80

Sem anotações de fornecedor. O HTTPRoute é portátil em qualquer implementação de Gateway API. O Gateway é onde você escolhe seu controller (gatewayClassName: istio), e essa é a única linha específica do fornecedor.

TLS: Automático com cert-manager

Em vez de gerenciar certificados manualmente, o cert-manager monitora o Gateway e emite certificados automaticamente:

yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: demo-issuer
spec:
  selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: demo-tls
spec:
  secretName: demo-tls
  duration: 2160h # 90 dias
  renewBefore: 720h # Renovar 30 dias antes da expiração
  issuerRef:
    name: demo-issuer
    kind: ClusterIssuer
  dnsNames:
    - bookstore-test.corp.vmbeans.com
    - reader-test.corp.vmbeans.com
    - chatbot-test.corp.vmbeans.com

Para este ambiente de demonstração, usei um issuer autoassinado. Em produção, troque selfSigned: {} por um issuer Let's Encrypt ou de CA corporativa. O resto permanece o mesmo.

O Helm Chart: Alternância Compatível com Versões Anteriores

Não queria quebrar o chart para quem ainda estava usando Ingress NGINX. A solução: uma alternância global.gatewayAPI.enabled que é true por padrão, mas pode ser definida como false para o modo legado.

values.yaml:

yaml
global:
  gatewayAPI:
    enabled: true
    className: istio
  tls:
    enabled: true
    issuer: demo-issuer

Templates Ingress (arquivos existentes, envolvidos em uma condicional):

yaml
{{- if not .Values.global.gatewayAPI.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
# ... recurso Ingress existente inalterado ...
{{- end }}

Templates HTTPRoute (novos arquivos):

yaml
{{- if .Values.global.gatewayAPI.enabled }}
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
# ... novo recurso HTTPRoute ...
{{- end }}

Resultado: helm template produz exatamente os recursos certos para cada modo:

ModoGatewayHTTPRouteCertificateIngress
Gateway API (padrão)1310
Ingress Legado0003

Para retornar ao Ingress NGINX em qualquer cluster:

bash
helm install demo ./helm/demo-suite \
  --set global.domain=example.com \
  --set global.gatewayAPI.enabled=false \
  --set global.tls.enabled=false \
  --set ingress-nginx.enabled=true

Passo a Passo: Como Apliquei a Migração

1. Instalar Pré-requisitos

No VKS, Istio e cert-manager estão disponíveis como pacotes padrão (add-ons). Instalei-os via UI de Automação VCF em Kubernetes Management Add-ons (você também pode usar recursos AddonInstall no servidor de API do Supervisor). A principal mudança de configuração: defina gateways.ingress.enabled: true no YAML do add-on Istio. Sem isso, o Istio instala o control plane, mas não o componente ingress gateway. Para o add-on cert-manager, as configurações padrão funcionam imediatamente.

Os CRDs do Gateway API não estão incluídos no add-on Istio e devem ser instalados separadamente em cada cluster de workload:

bash
kubectl apply --server-side \
  -f "https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml"

Nota crítica de compatibilidade: Istio 1.28/1.29 requer CRDs do Gateway API v1.4.x. A instalação da v1.5.x faz com que o istiod falhe devido a incompatibilidades de campos de API (istio/istio#59443). Este é um problema conhecido em várias implementações de Gateway API no início de 2026 — sempre fixe a versão do CRD em produção.

Para clusters não VKS, criei um script de uso único (scripts/install-prerequisites.sh) que instala Istio, cert-manager e os CRDs via Helm com versões fixadas.

2. Corrigir Pod Security Admission

Este foi o "problema" que me custou um pouco de tempo. Os namespaces VKS padrão usam o Pod Security Standard restrito. Os pods de gateway proxy provisionados automaticamente pelo Istio não incluem um seccompProfile em seu contexto de segurança, então o Kubernetes os rejeita:

Error creating: pods "demo-gateway-istio-..." is forbidden: violates PodSecurity "restricted:latest": seccompProfile (pod or container "istio-proxy" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")

A correção: relaxar a política PSA no namespace onde o recurso Gateway reside:

bash
kubectl label namespace bookstore \
  pod-security.kubernetes.io/enforce=privileged \
  pod-security.kubernetes.io/warn=privileged \
  pod-security.kubernetes.io/audit=privileged \
  --overwrite

Importante: Após aplicar os labels, o ReplicaSet fica preso em exponential backoff devido às falhas anteriores. Você precisa reiniciar o deployment para forçar uma nova tentativa:

bash
kubectl rollout restart deploy/demo-gateway-istio -n bookstore

Isso é algo que o projeto Istio deveria corrigir upstream (adicionando seccompProfile: RuntimeDefault ao template do gateway proxy), mas por enquanto, o label do namespace é a solução alternativa.

3. Helm Upgrade (cluster-01)

bash
helm upgrade demo-test ./helm/demo-suite \
  -f ./helm/demo-suite/values-small.yaml \
  --set global.domain=corp.vmbeans.com \
  --set global.storageClassName=vsan-default-storage-policy \
  --set bookstore.ingress.host=bookstore-test.corp.vmbeans.com \
  --set reader.ingress.host=reader-test.corp.vmbeans.com \
  --set bookstore.readerBrowserURL=https://reader-test.corp.vmbeans.com \
  --set ingress-nginx.enabled=false \
  --set chatbot.enabled=false \
  --timeout 10m

Principais mudanças em relação ao comando de instalação anterior:

  • Removido ingress-nginx.enabled=true (Gateway API o substitui)
  • Alterado readerBrowserURL de http:// para https:// (TLS está agora ativado)
  • global.gatewayAPI.enabled e global.tls.enabled são true por padrão, sem necessidade de override.

4. ArgoCD Sync (cluster-02)

Para o cluster Kustomize/ArgoCD, a base Kustomize foi atualizada para referenciar gateway.yaml, httproute.yaml e tls.yaml em vez de ingress.yaml. Os patches de overlay foram atualizados para definir o hostname correto.

bash
argocd app set bookstore --sync-policy automated --auto-prune --self-heal
argocd app sync bookstore

O ArgoCD removeu automaticamente o antigo recurso Ingress e criou o Gateway, HTTPRoute, Certificate e ClusterIssuer. A sincronização levou 6 segundos.

5. Atualizar DNS

O gateway proxy do Istio obtém seu próprio IP de LoadBalancer, que será diferente do IP antigo do ingress-nginx. Após o upgrade:

bash
# Obter o novo IP do gateway
kubectl get svc demo-gateway-istio -n bookstore -o jsonpath='{.status.loadBalancer.ingress[0].ip}'

Atualize seus registros DNS A para apontar para o novo IP.

O Resultado

bash
$ kubectl get gateway,httproute,certificate -A
NAMESPACE   NAME                         CLASS   ADDRESS      PROGRAMMED   AGE
bookstore   gateway/demo-gateway         istio   32.32.0.22   True         5m

NAMESPACE   NAME                               HOSTNAMES                                AGE
bookstore   httproute/bookstore-route          ["bookstore-test.corp.vmbeans.com"]      5m
reader      httproute/reader-route             ["reader-test.corp.vmbeans.com"]         5m

NAMESPACE   NAME                         READY   SECRET     AGE
bookstore   certificate/demo-tls         True    demo-tls   5m

O aplicativo carrega via HTTPS com um certificado emitido pelo cert-manager. O navegador mostra o cadeado (com um aviso de autoassinado, esperado para um ambiente de laboratório). Todo o tráfego flui através do gateway proxy do Istio.

Problemas e Lições Aprendidas (os Economizadores de Tempo)

Estes são os problemas que me custaram horas. Aprenda com minha dor:

  1. A compatibilidade da versão do CRD da Gateway API é crítica. Istio 1.28/1.29 falha com CRDs da Gateway API v1.5. Fixe na v1.4.0. Isso afetou múltiplas implementações (Cilium, Envoy Gateway) no início de 2026 — não é específico do Istio.
  2. O VKS Pod Security Admission bloqueia os gateway proxies do Istio. Os pods provisionados automaticamente não possuem seccompProfile, acionando violações da política restrita. Rotule o namespace como privileged. Este é um padrão do VKS; o Kubernetes vanilla geralmente usa baseline ou privileged por padrão.
  3. A armadilha do backoff do ReplicaSet. Após corrigir os labels do PSA, o ReplicaSet não tenta novamente imediatamente. Ele está em exponential backoff esperando 2-5 minutos entre as tentativas. kubectl rollout restart é necessário para forçar uma nova tentativa imediatamente. Sem isso, você pensará que a correção não funcionou.
  4. O add-on Istio VKS vem com gateways.ingress.enabled: false. Você deve habilitá-lo explicitamente no YAML do AddonInstall ou não haverá gateway proxy para lidar com o tráfego. O control plane é instalado corretamente, mas nada realmente roteia.
  5. Não instale Istio ou cert-manager como subcharts do Helm. Ambos os projetos desaconselham fortemente isso devido a colisões de nomes de template e problemas de ciclo de vida do CRD (eles precisam de instalação em nível de cluster). Instale-os como componentes de nível de cluster separadamente e, em seguida, referencie-os a partir do seu chart de aplicativo. Esta é a melhor prática documentada para ambos os projetos.
  6. Alterações no DNS são necessárias. O gateway proxy do Istio obtém um novo IP de LoadBalancer. O antigo IP do ingress-nginx torna-se obsoleto. Planeje a transição do DNS. Use um TTL baixo (300s) durante a migração para que você possa reverter rapidamente, se necessário.
  7. A alternância compatível com versões anteriores vale o esforço. Ser capaz de alternar entre Gateway API e Ingress NGINX com um único flag --set torna a migração reversível e permite que diferentes clusters executem diferentes networking stacks durante a transição. Isso me salvou quando descobri o problema da versão do CRD no meio da migração.
  8. As melhores práticas de produção do cert-manager importam. Execute 2+ réplicas de controller e 3+ réplicas de webhook para alta disponibilidade. Especialmente o webhook — se estiver inativo, todas as operações de Certificado falham em todo o cluster. Defina duration: 2160h (90d) e renewBefore: 720h (30d) explícitos para dar tempo suficiente para a renovação.

Resumo das Alterações de Arquivo

ArquivoAlteração
VKS AddOnInstallNovo — instala Istio, cert-manager
charts/bookstore/templates/gateway.yamlNovo — recurso Gateway compartilhado (listeners HTTP + HTTPS)
charts/bookstore/templates/httproute.yamlNovo — HTTPRoute do bookstore
charts/reader/templates/httproute.yamlNovo — HTTPRoute do reader
charts/chatbot/templates/httproute.yamlNovo — HTTPRoute do chatbot
charts/bookstore/templates/tls.yamlNovo — ClusterIssuer + Certificate
charts/bookstore/templates/ingress.yamlModificado — envolvido em {{- if not .Values.global.gatewayAPI.enabled }}
charts/reader/templates/ingress.yamlModificado — adicionada condicional gatewayAPI.enabled
charts/chatbot/templates/ingress.yamlModificado — adicionada condicional gatewayAPI.enabled
helm/demo-suite/values.yamlModificado — adicionadas seções global.gatewayAPI e global.tls
helm/demo-suite/values-small.yamlModificado — comentários atualizados
kubernetes/base/gateway.yamlNovo — Gateway base do Kustomize
kubernetes/base/httproute.yamlNovo — HTTPRoute base do Kustomize
kubernetes/base/tls.yamlNovo — ClusterIssuer + Certificate base do Kustomize
kubernetes/base/kustomization.yamlModificado — substituído ingress.yaml por gateway/httproute/tls
kubernetes/overlays/prod/httproute-patch.yamlNovo — override de hostname para produção
kubernetes/overlays/prod/tls-patch.yamlNovo — override de nome DNS para produção
kubernetes/overlays/dev/httproute-patch.yamlNovo — override de hostname para desenvolvimento
kubernetes/overlays/dev/tls-patch.yamlNovo — override de nome DNS para desenvolvimento
kubernetes/overlays/*/kustomization.yamlModificado — substituído ingress-patch por httproute-patch + tls-patch

O Resumo: Você Pode Realmente Fazer Isso em Um Dia?

Sim. Aqui está o cronograma realista:

  • 1-2 horas: Instalar pré-requisitos (Istio, cert-manager, CRDs do Gateway API), depurar problemas de PSA, fazer um aplicativo de teste funcionar.
  • 2-3 horas: Construir o padrão de alternância Helm compatível com versões anteriores, testar cenários de rollback.
  • 1-2 horas: Migrar os aplicativos restantes, atualizar DNS, testes paralelos.
  • 1-2 horas: Monitorar o tráfego de produção, finalizar a documentação, limpar os recursos Ingress antigos.

Investimento total de tempo: 5-9 horas, dependendo da complexidade e do número de clusters.

O cronograma real: A maior parte do tempo é gasta esperando — pela propagação do DNS, para o cert-manager emitir certificados, pelos ciclos de sincronização do ArgoCD. O trabalho prático real é concentrado em explosões.

Migração com zero tempo de inatividade: A chave é executar ambas as stacks (Ingress NGINX + Gateway API) em paralelo em IPs de LoadBalancer separados. Você faz a transição via DNS, não substituindo recursos. Se algo quebrar, você aponta o DNS de volta para o IP antigo e soluciona o problema.

Vale a pena? Após 31 de março, você estará por conta própria para CVEs. O projeto ingress-nginx está arquivado, sem mais patches de segurança. A Gateway API é o caminho endossado pela comunidade Kubernetes — você está migrando para uma API de primeira classe, não para um controller de terceiros. Faça isso agora ou faça sob pressão quando o primeiro CVE pós-descontinuação surgir. Se você está lendo isso entre 28 e 31 de março, ainda há tempo. Siga este playbook, adapte os labels do PSA ao seu ambiente, fixe a versão do seu CRD e conclua. A alternativa é executar infraestrutura não suportada a partir do momento em que abril começar.

O Que Vem Por Aí

  • Troque o ClusterIssuer autoassinado por Let's Encrypt ou CA interna em produção:
    • Use Issuers separados para ambientes de desenvolvimento/preparação/produção
    • Defina rotationPolicy: Always em Certificates para segurança aprimorada
    • Monitore a expiração de certificados com métricas Prometheus: certmanager_certificate_expiration_timestamp_seconds
  • Explore os recursos de service mesh do Istio agora que o control plane está instalado (mTLS, políticas de tráfego, observabilidade com Kiali). Para mais informações sobre add-ons do VKS e recursos estendidos, consulte nosso guia completo.
  • Considere implementar ReferenceGrants entre namespaces para melhores limites de segurança.
  • Descubra mais no Blog VMware Cloud Foundation (VCF).
  • Assine para receber as últimas postagens em seu e-mail.

Como parceiro certificado, a VirtuAllIT pode auxiliar sua empresa na implementação desta e de outras soluções de modernização de infraestrutura, garantindo uma transição suave e otimizada para suas operações.

Precisa de ajuda com suas soluções de TI?

A VirtuAllIT Solutions oferece consultoria especializada em virtualização, cloud computing e infraestrutura tecnológica.