Um pod no namespace shop chama http://api e a requisição dá timeout. O pod está rodando, o Service existe e seu EndpointSlice lista dois backends prontos. A falha pode estar no DNS, nas regras que o kube-proxy escreveu no nó, no overlay entre os nós ou em uma NetworkPolicy que alguém aplicou semana passada. Cada uma é uma camada separada, mantida por um componente separado.
Este post percorre essas camadas com um diagrama: o modelo de rede, o tráfego de pod para pod, os plugins CNI, os Services, o DNS, a NetworkPolicy e o tráfego de entrada e saída do cluster.
O modelo de rede do Kubernetes
O modelo de rede do Kubernetes tem três regras. Cada pod recebe seu próprio endereço IP em todo o cluster, compartilhado pelos seus contêineres. Cada pod consegue alcançar qualquer outro pod, em qualquer nó, sem proxies nem NAT. E os agentes de nó, como o kubelet, conseguem alcançar todos os pods do seu nó.
O Kubernetes define as APIs, e os componentes que você instala fazem o trabalho:
| Camada | O que ela oferece | Implementada por |
|---|---|---|
| Rede de pods | Um IP por pod, alcançabilidade de pod para pod | Um plugin CNI |
| Services | Um IP virtual estável e um nome para um conjunto de pods | kube-proxy ou um substituto eBPF |
| DNS | Nomes como api.shop.svc.cluster.local |
CoreDNS |
| NetworkPolicy | Regras de permissão para o tráfego dos pods | O plugin CNI |
| Ingress, Gateway API | Roteamento a partir de fora do cluster | Um controlador que você instala |
Essa divisão explica muitas surpresas, como uma NetworkPolicy que o servidor de API aceita, mas que o seu plugin ignora em silêncio.
De pod para pod no mesmo nó
Quando o runtime de contêineres inicia um pod, ele chama o plugin CNI com ADD. A maioria dos plugins cria um par veth, um cabo virtual com eth0 dentro do pod e a outra ponta no host, e atribui o IP. O Flannel liga a ponta do host a um bridge Linux, cni0; o Calico dispensa o bridge: cada pod recebe uma rota /32 e o host age como roteador dele. Nos dois casos, o tráfego dentro do mesmo nó não precisa de encapsulamento nem de NAT.
De pod para pod entre nós: overlay ou roteamento nativo
Cada nó normalmente é dono de uma fatia do intervalo de pods. Com o valor padrão de --node-cidr-mask-size do kube-controller-manager, que é 24, um intervalo 10.244.0.0/16 dá um /24 a cada um de 256 nós, ou seja, 256 endereços para os 110 pods que o kubelet aceita por padrão. Entre nós, o plugin tem duas opções:
| Overlay (VXLAN, Geneve, IP-in-IP) | Roteamento nativo (BGP, rotas da nuvem, IPs da VPC) | |
|---|---|---|
| A rede entre os nós enxerga | Apenas IPs de nós | IPs de pods |
| Exige | Alcançabilidade IP entre os nós | Uma rede que roteie os intervalos de pods, ou endereços da VPC para os pods |
| Overhead por pacote | 50 bytes para VXLAN com IPv4, 20 para IP-in-IP | Nenhum |
| Exemplos | Padrões do Flannel e do Cilium, Calico VXLAN | Calico com BGP, AWS VPC CNI, Azure CNI |
O overhead é um problema de MTU: em uma rede de 1.500 bytes, os pods atrás de VXLAN com IPv4 precisam de MTU de 1.450, segundo o guia de MTU do Calico. Se você errar isso, pacotes grandes somem, o que parece travamento aleatório.
Comparação dos plugins CNI
| Plugin | Tráfego entre nós | NetworkPolicy | Observações |
|---|---|---|---|
| Flannel | VXLAN por padrão (UDP 8472); host-gw em uma rede de camada 2 compartilhada |
Não é aplicada pelo Flannel; adicione kube-network-policies ou Calico | Pequeno e simples |
| Calico | BGP, ou overlay VXLAN (UDP 4789) ou IP-in-IP | Completa, mais as políticas do Calico por namespace e globais | Data planes iptables, nftables, eBPF, VPP e Windows |
| Cilium | VXLAN por padrão (UDP 8472), Geneve ou roteamento nativo | Completa, mais regras de camada 7 e baseadas em DNS | Caminho de dados eBPF |
| AWS VPC CNI | Sem overlay; os pods recebem endereços da VPC | Desde a v1.14, com enableNetworkPolicy |
Pods por nó limitados pelo tipo de instância |
O limite da AWS pesa cedo: o máximo padrão é ENIs × (IPs por ENI − 1) + 2, então uma m5.large com 3 interfaces de 10 endereços roda 3 × 9 + 2 = 29 pods. A delegação de prefixos aumenta esse número.
Services: um IP estável na frente de pods que mudam
Os IPs dos pods mudam sempre que um pod é substituído. Um Service dá a um conjunto de pods um IP virtual estável, o ClusterIP, e um nome DNS; os EndpointSlices acompanham os pods por trás dele.
| Tipo | O que você recebe |
|---|---|
| ClusterIP (padrão) | Um IP virtual dentro do cluster |
| NodePort | Também uma porta em cada nó, 30000–32767 por padrão |
| LoadBalancer | Também um balanceador de carga da nuvem ou de um add-on |
| ExternalName | Um alias DNS (CNAME), sem proxy |
Headless (clusterIP: None) |
Sem IP virtual; o DNS devolve os IPs dos pods |
Nenhuma máquina é dona de um ClusterIP. Em cada nó, o kube-proxy programa o kernel para que um pacote destinado a 10.96.48.20:80 seja reescrito (NAT de destino) para um endereço de pod como 10.244.2.22:8080 antes de sair do nó do cliente. O Service é uma etapa lógica, não um servidor. As regras dependem do modo de proxy:
| Modo | Status no Kubernetes 1.37 | Como funciona |
|---|---|---|
| iptables | Padrão no Linux | Regras por Service e endpoint; backend aleatório |
| nftables | GA desde a 1.33; o futuro padrão planejado | Atualizações mais rápidas em grande escala; exige kernel 5.13 ou posterior |
| ipvs | Obsoleto desde a 1.35; desativado por padrão na 1.40, removido na 1.43 | Tabelas IPVS do kernel, mais algoritmos de balanceamento |
| eBPF (Cilium, Calico) | Substitui o kube-proxy | Balanceamento de carga em programas eBPF |
Defina o modo explicitamente para que uma atualização não possa mudá-lo, e planeje a saída do IPVS. No modo nftables, os NodePorts escutam por padrão apenas nos endereços primários do nó.
DNS com CoreDNS
O CoreDNS é o DNS de cluster padrão, e o kubeadm o executa atrás de um Service que ainda se chama kube-dns. Cada Service recebe um nome, <service>.<namespace>.svc.cluster.local, que resolve para o seu ClusterIP, ou para os IPs dos pods em um Service headless. O kubelet escreve o /etc/resolv.conf de cada pod; em shop, em um cluster kubeadm, ele costuma ser assim:
nameserver 10.96.0.10
search shop.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
O problema é o ndots:5: um nome com menos de cinco pontos, como api.stripe.com, é tentado primeiro com cada domínio de busca, então uma consulta externa pode custar três consultas que falham. Coloque um ponto final nos nomes mais usados, reduza o ndots no dnsConfig do pod ou execute o NodeLocal DNSCache. Os nomes externos seguem então o caminho mostrado em como o DNS funciona.
NetworkPolicy: do permitir por padrão ao menor privilégio
Por padrão, cada pod aceita tráfego de qualquer lugar. Assim que qualquer NetworkPolicy seleciona um pod para ingress (ou egress), só passa o que alguma política permite; as respostas são permitidas automaticamente. As políticas só adicionam regras de permissão, então a ordem nunca importa. Comece cada namespace com um negar por padrão:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: shop
spec:
podSelector: {}
policyTypes:
- Ingress
Depois abra o que você precisa, aqui TCP 8080 de web para api:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow-web
namespace: shop
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: web
ports:
- protocol: TCP
port: 8080
Quatro detalhes pegam muita gente:
- A porta é a do pod, 8080, e não a porta 80 do Service.
- O negar por padrão isola também os pods web, então o Gateway precisa de uma regra própria para alcançá-los.
- Um hífen muda o significado. Um
namespaceSelectore umpodSelectorem uma mesma entradafromprecisam coincidir os dois; como duas entradas, basta um deles. - O negar por padrão em egress bloqueia o DNS, então permita primeiro a porta 53 para o
kube-dns.
A NetworkPolicy não tem regras de negação, nem escopo de cluster inteiro, nem nada para TLS; para TLS mútuo entre workloads, veja o diagrama de arquitetura de service mesh.
Tráfego de entrada e saída: Ingress, Gateway API e egress
O Ingress é estável, mas está congelado, e o projeto Kubernetes recomenda a Gateway API no lugar dele. O controlador comunitário Ingress NGINX foi aposentado em março de 2026 e não recebe mais correções de segurança, mas as instalações existentes continuam rodando sem que ninguém perceba.
A Gateway API divide o trabalho por papéis: os responsáveis pela plataforma operam o Gateway, com seus listeners e certificados, e as equipes de aplicação anexam HTTPRoutes a partir dos seus próprios namespaces. Ela chegou ao GA em outubro de 2023, e as versões de 2026 também tornaram TLSRoute, TCPRoute e UDPRoute padrão. O diagrama de ingress do Kubernetes segue esse caminho salto a salto.
O egress é a direção esquecida. O tráfego que sai do cluster costuma ser traduzido para o IP do nó, como o AWS VPC CNI faz para destinos fora da VPC. Limite-o com regras de egress, que enxergam destinos externos apenas como intervalos de IP, com regras que entendem DNS, como o toFQDNs do Cilium, ou com um egress gateway quando um parceiro precisa de um IP de origem fixo.
O diagrama de rede do Kubernetes
Conteúdo do diagrama
- worker-1 · pods 10.244.1.0/24
- worker-2 · pods 10.244.2.0/24
- Users
- public-gw
- web · 10.244.1.12
- coredns · 10.244.1.5
- api · 10.244.2.21
- api · 10.244.2.22
- api · 10.96.48.20
- api-allow-web
- HTTPS 443
- HTTPRoute
- DNS: api.shop.svc.cluster.local via kube-dns 10.96.0.10
- TCP 10.96.48.20:80
- DNAT 10.244.2.21:8080
- DNAT 10.244.2.22:8080
- VXLAN overlay over UDP · node IP to node IP
Como ler:
- Dois nós worker, cada um rotulado com o seu intervalo de pods /24.
- Azul é norte-sul: os usuários chegam a
public-gwpor HTTPS 443, e uma HTTPRoute os envia ao pod web. - Âmbar é DNS: web pergunta ao CoreDNS, por meio do
kube-dnsem 10.96.0.10, porapi.shop.svc.cluster.locale recebe 10.96.48.20. - Verde-azulado é o caminho do Service: web se conecta a 10.96.48.20:80, e as regras do kube-proxy no worker-1 reescrevem isso para um pod api na porta 8080.
- Cinza é o overlay: o pacote cruza para o worker-2 dentro de VXLAN, entre os IPs dos nós.
- Vermelho é a política:
api-allow-webdeixa apenas os podsapp=webalcançarem os pods api. - O bloco Markdown lista os padrões por trás dos números.
Como desenhar com clareza diagramas de rede do Kubernetes
- Rotule os nós com os intervalos de pods e os pods com os IPs, os detalhes que você procura nos logs.
- Desenhe o Service como uma etapa lógica e anote onde acontece a reescrita.
- Rotule as arestas com endereço, porta e protocolo, passando para a porta do pod depois do Service.
- Use cores diferentes para norte-sul e leste-oeste, e desenhe o overlay uma só vez, entre os nós.
- Ligue cada política aos pods que ela seleciona, com a origem permitida.
- Deixe de fora o kubelet, o servidor de API e as réplicas extras; o diagrama de arquitetura do Kubernetes cobre o plano de controle.
- Erros comuns: kube-proxy no caminho dos pacotes (ele escreve regras, quem encaminha é o kernel), ausência de DNS e uma política em um plugin que a ignora.
Monte no Archboard
- Entre com Google ou GitHub e crie um diagrama. A ferramenta gratuita Kubernetes YAML para diagrama transforma manifests existentes em um primeiro rascunho.
- Adicione dois nós Moldura do pack Básico para worker-1 e worker-2, rotulados com seus intervalos de pods.
- No pack Kubernetes, adicione quatro nós Pod com seus IPs: web e coredns no worker-1, dois pods api no worker-2.
- Adicione um Service (ClusterIP, porta 80 para 8080) entre as molduras, com arestas rotuladas a partir de web e para os dois pods api.
- Adicione uma NetworkPolicy que selecione
app=api, com arestas pontilhadas para os pods api. - Adicione um nó Internet do pack Rede e um Gateway com um listener HTTPS 443, e encadeie-os ao pod web.
- Desenhe uma aresta DNS tracejada de web para coredns e uma aresta VXLAN grossa e bidirecional entre as molduras.
- Adicione um bloco Markdown do pack Básico com os padrões, e notas curtas de Texto.
A página do caso de uso de Kubernetes lista mais objetos. O exemplo usa 11 nós de diagrama e fica dentro do plano Free.
Perguntas frequentes
Como os pods se comunicam entre nós no Kubernetes? Pelo plugin CNI: um overlay encapsula os pacotes dos pods entre os IPs dos nós, ou o roteamento nativo carrega diretamente os endereços dos pods. Nos dois casos, os pods enxergam os IPs reais uns dos outros.
Qual é a diferença entre um IP de pod e um ClusterIP? Um IP de pod pertence a um único pod e muda quando o pod é substituído. Um ClusterIP é o IP virtual estável de um Service, que o kube-proxy ou um substituto eBPF reescreve para um IP de pod atual.
Qual modo do kube-proxy devo usar? No Kubernetes 1.37, iptables é o padrão, nftables é GA desde a 1.33 e vai se tornar o padrão, e o IPVS está obsoleto. Com kernel 5.13 ou posterior, nftables é a melhor escolha a longo prazo.
As NetworkPolicies funcionam com todos os plugins CNI? Não. A API as aceita em qualquer lugar, mas só os plugins que implementam NetworkPolicy as aplicam: Calico, Cilium e o AWS VPC CNI com a política de rede ativada aplicam; o Flannel sozinho, não.
Devo usar Ingress ou a Gateway API? A Gateway API para o que for novo: o Kubernetes a recomenda, e o Ingress está congelado. Os recursos Ingress existentes continuam funcionando, mas planeje a saída do Ingress NGINX, que não recebe mais correções de segurança.