Fase 4b: DNS Resiliency - a dependência escondida

Último teste de falha, e o mais sutil. Ainda desconectado (FIS + iptables ativos), uma pergunta: o monitoring on-prem da Fase 7 sobrevive? Ele roda 100% nos hybrid nodes... mas o Grafana consulta o Prometheus pelo NOME (prometheus.onprem-monitoring), e resolver esse nome exige o CoreDNS. Onde roda o CoreDNS?

kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide

No deploy padrão do EKS, as réplicas do CoreDNS ficam nos nodes da NUVEM. Durante a desconexão, o hybrid node não alcança o CoreDNS - o DNS dá timeout e TODA aplicação on-prem que resolve nomes quebra, mesmo com o workload inteiro rodando local. O dashboard fica lento e sem dados, não porque o Prometheus caiu, mas porque o nome dele não resolve. O monitoring "local" tinha uma dependência escondida da nuvem.

Só um teste de caos revela esse tipo de dependência. A stack foi desenhada para sobreviver ao disconnect, mas a camada mais básica - resolução de nomes - ainda morava na nuvem.

O fix tem DOIS componentes e AMBOS têm que estar aplicados na PREPARAÇÃO (antes de qualquer desconexão). Não dá para aplicar durante o disconnect - o Cilium do node não atualiza rotas/serviços sem o API server.

  1. CoreDNS rodando em CADA node (inclusive os dois hybrid), 1/1 Ready.
  2. internalTrafficPolicy: Local no service kube-dns. ESTE É O PONTO CRÍTICO: sem ele, o pod consulta o CoreDNS pelo ClusterIP em round-robin entre TODAS as réplicas, e parte das queries cai no CoreDNS da nuvem (inalcançável no disconnect) - falha intermitente. Com Local, cada pod resolve SÓ pelo CoreDNS do próprio node. Medido: sem o fix ~1/3 de falha; com o fix 8/8 durante o disconnect.

Por que não Topology Aware Routing (hints): em cluster pequeno/assimétrico os hints quase nunca populam (validado - annotation topology-mode e trafficDistribution, ambos com hints vazios), então não é confiável. internalTrafficPolicy: Local não depende de hints.

Aplicar no prep (Parte 1), com o ambiente CONECTADO para o Cilium propagar:

# 1. CoreDNS em cada node schedulable (spread por hostname, honrando taints)
kubectl -n kube-system patch deploy coredns --type merge -p '{"spec":{"replicas":4,"template":{"spec":{"topologySpreadConstraints":[{"maxSkew":1,"topologyKey":"kubernetes.io/hostname","whenUnsatisfiable":"DoNotSchedule","nodeTaintsPolicy":"Honor","labelSelector":{"matchLabels":{"k8s-app":"kube-dns"}}}]}}}}'

# 2. O ponto crítico: cada pod usa o CoreDNS do próprio node
kubectl -n kube-system patch svc kube-dns --type merge -p '{"spec":{"internalTrafficPolicy":"Local"}}'
Nota (Cilium)

Com internalTrafficPolicy: Local, TODO node que roda pods precisa de um CoreDNS local, senão o DNS é dropado nele. Garanta a cobertura (o spread por hostname resolve). E o NodeLocal DNSCache "vanilla" (interceptação por iptables) NÃO funciona com Cilium - o Cilium bypassa iptables. Para usar NodeLocal como camada de cache, é obrigatório o Cilium Local Redirect Policy (LRP): um recurso CiliumLocalRedirectPolicy que redireciona o tráfego DNS para o pod NodeLocal local via eBPF. Neste lab o fix é só CoreDNS-per-node + internalTrafficPolicy Local (sem NodeLocal); LRP + NodeLocal fica como evolução de cache. Ref: docs.cilium.io - Local Redirect Policy.

Confirmar (CoreDNS 1/1 em cada node, incl. mi-*, e a policy Local):

kubectl get pods -n kube-system -l k8s-app=kube-dns -o custom-columns='POD:.metadata.name,NODE:.spec.nodeName,READY:.status.containerStatuses[0].ready'
kubectl get svc kube-dns -n kube-system -o jsonpath='internalTrafficPolicy={.spec.internalTrafficPolicy}{"\n"}'
Nota (produção)

O CoreDNS aqui é um managed addon do EKS. Estes kubectl patch persistem (o addon só reconcilia em create/update), mas um aws eks update-addon futuro pode sobrescrevê-los.

Recomendação: em produção, aplique a config (replicaCount, topologySpreadConstraints) via configurationValues do addon com resolveConflicts: PRESERVE, em vez de patch cru - assim o addon mantém a config através de updates.

Ref: Manage CoreDNS for DNS in Amazon EKS 

Com a réplica local no ar, o mesmo teste que falhava agora responde:

ssh -i ~/.ssh/id_ecdsa lopbruno@192.168.3.51

Já no node, resolução + query de dentro do container do Grafana:

GID=$(sudo crictl ps --name grafana -q | head -1)
sudo crictl exec $GID wget -qO- --timeout=5 http://prometheus.onprem-monitoring:9090/-/healthy

Resultado: Prometheus Server is Healthy - o Grafana volta a popular os painéis, resolvendo o nome via CoreDNS on-prem, sem tocar a nuvem. O Prometheus continua configurado por DNS (idiomático) - quem ficou resiliente foi a plataforma.

Três camadas de resolução, três comportamentos na falha da região:

  • Nomes internos do cluster (*.svc.cluster.local): resolvidos SÓ pelo CoreDNS - nunca tocam o Route 53. Fix: réplica local (acima).
  • Nomes públicos via resolver próprio do DC (internet): sobrevivem - o data plane do Route 53 é global (edge locations anycast, SLA 100%), desenhado para manter disponibilidade mesmo quando o control plane degrada. Falha em sa-east-1 NÃO derruba a resolução pública.
  • Nomes resolvidos via Route 53 Resolver endpoint na VPC: o endpoint é REGIONAL e alcançado pelo link privado - a falha da região ou do link quebra esse caminho, mesmo com o R53 global saudável. Recomendação: o DC resolve nomes públicos pelo resolver local dele, sem depender do caminho da VPC.

Refs: Resilience in Amazon Route 53  | Control and data plane concepts  | CoreDNS em hybrid nodes