Pular para o conteúdo

Service mesh

Avançado18 min de leiturakubernetes

Quando dezenas de serviços conversam entre si, três perguntas aparecem sempre: o tráfego interno é criptografado e autenticado? Dá para ver latência e erro por chamada sem alterar cada aplicação? Dá para desviar 5% do tráfego para uma versão nova? Um service mesh move essas respostas da aplicação para a infraestrutura — e cobra por isso.

  • Sidecar (Linkerd, Istio clássico): um proxy por Pod intercepta todo o tráfego. Máximo de controle, custo de CPU e memória por Pod, e um container a mais em cada reinício.
  • Ambient / sem sidecar (Istio ambient): um agente por nó cuida de mTLS e telemetria; o proxy L7 entra apenas onde você precisa de política de camada 7.
  • eBPF no kernel (Cilium): identidade e política no datapath, sem proxy no caminho comum. Muito eficiente em L3/L4; recursos L7 ainda passam por um proxy.

Não existe escolha universal. Linkerd ganha em simplicidade e consumo, Istio em funcionalidade e ecossistema, Cilium quando você já usa o CNI dele e quer política eficiente.

Sem mesh, criptografar tráfego interno significa gerenciar certificado dentro de cada serviço. Com mesh, cada workload recebe uma identidade — a ServiceAccount — e o proxy negocia mTLS sem mudança de código.

apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata: { name: default, namespace: loja }
spec:
mtls: { mode: STRICT } # recusa tráfego em texto claro neste namespace
---
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata: { name: so-frontend, namespace: loja }
spec:
selector: { matchLabels: { app: pedidos } }
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/loja/sa/frontend"]

Isso é autorização por identidade, não por IP — mais forte que NetworkPolicy sozinha, e complementar a ela. Ative STRICT um namespace por vez, nunca no cluster inteiro de uma vez: qualquer carga que fale sem proxy (um job legado, um scraper externo) para na hora.

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata: { name: pedidos, namespace: loja }
spec:
hosts: [pedidos]
http:
- route:
- destination: { host: pedidos, subset: estavel }
weight: 95
- destination: { host: pedidos, subset: canario }
weight: 5
timeout: 3s
retries: { attempts: 2, perTryTimeout: 1s, retryOn: "5xx,connect-failure" }

Cuidado com retry: repetir uma chamada não idempotente duplica efeito, e retry em cascata entre serviços multiplica a carga exatamente quando o sistema já está sofrendo. Use timeout menor que o do chamador e limite as tentativas.

  • Recursos. Some CPU e memória do proxy por Pod; em centenas de Pods isso é um node group inteiro.
  • Diagnóstico. O proxy vira suspeito em todo incidente: 503 UF/UO do Envoy, ordem de inicialização entre app e sidecar, terminationGracePeriod curto demais.
  • Upgrades. O mesh tem ciclo de versões próprio e reinicia os Pods quando o proxy muda.
  • Aprendizado. Alguém do time precisa entender Envoy para os dias em que o YAML não explica o comportamento.
Janela do terminal
istioctl analyze -n loja # configuração inconsistente
istioctl proxy-status # proxies fora de sincronia
kubectl logs <pod> -c istio-proxy -n loja | tail -50

Provavelmente não com menos de dez serviços. Antes dele, tente o caminho mais barato: TLS terminado no Ingress ou na Gateway API, NetworkPolicy para segmentar, OpenTelemetry na aplicação para rastreamento e um controlador de rollout para deploy progressivo. Adote mesh quando mais de uma dessas necessidades for real e recorrente, e quando houver quem o opere. Se adotar, comece por um namespace, meça o overhead e só então expanda.

Próximo passo: você fechou a trilha de Kubernetes. Consolide com o Diagnóstico em Kubernetes e siga para Observabilidade para instrumentar o que o mesh passou a medir.