02 - Ambassador Pattern (Proxy sidecar)
video: https://youtu.be/... no frontmatter da nota.Ambassador Pattern (Proxy sidecar)
O Ambassador Pattern coloca um processo acompanhante ao lado de cada instância de aplicação, responsável por intermediar toda a comunicação de rede dela com o mundo externo. Em vez de cada serviço implementar retry, timeout, TLS, coleta de métricas e log de requisições, essas responsabilidades cruzam para um proxy co-localizado que a aplicação sequer precisa conhecer, pois ele escuta em localhost e repassa o tráfego. O nome vem do papel de embaixador: o proxy representa a aplicação perante a rede e traduz as políticas de infraestrutura em comportamento de conexão. O padrão nasceu da constatação de que implementações de resiliência em bibliotecas de cliente se multiplicam por linguagem, por versão e por time, e nunca ficam consistentes. Em produção, ele é a base técnica do sidecar em Kubernetes e a unidade de construção do service mesh. Dominar o padrão é entender por que plataformas modernas movem cada vez mais lógica de rede para fora do código de negócio.
Conceito
O ambassador é um processo auxiliar que vive no mesmo host ou no mesmo pod da aplicação e atua como intermediário de rede em uma direção específica. Um ambassador de saída recebe as conexões que a aplicação faz para serviços externos e as encaminha aplicando políticas; um ambassador de entrada recebe conexões de clientes e as entrega à aplicação com as mesmas garantias. A aplicação fala com o ambassador em protocolo simples, geralmente HTTP ou TCP plano, e o ambassador fala com o mundo em protocolo rico, com mTLS, retries e telemetria.
A co-localização é o detalhe que define o padrão. Como o ambassador rota por localhost ou por interface local, a latência de rede adicional é mínima e a falha do nó derruba aplicação e proxy juntos, o que simplifica a semântica de vida dos dois. No Kubernetes, essa co-localização materializa-se no pod: múltiplos contêineres compartilham namespaces de rede e volumes, e o contêiner acompanhante recebe o nome de sidecar.
- Sidecar de saída (outbound): intercepta chamadas da aplicação a outros serviços e a APIs externas, aplicando resiliência e segurança.
- Sidecar de entrada (inbound): termina TLS, valida autenticação e expõe métricas do tráfego que chega à aplicação.
- Ambassador de serviço: variação que roda como deployment compartilhado por vários pods de um nó, trocando densidade por isolamento.
O problema que resolve
Resiliência de rede escrita dentro da aplicação apodrece de três formas. Primeiro, por fragmentação: cada linguagem tem sua biblioteca, cada time sua versão, e a política de retry que vale para o serviço Java não existe no serviço Python legado. Segundo, por acoplamento: mudar a política exige novo build e novo deploy da aplicação, o que transforma ajuste operacional em projeto de desenvolvimento. Terceiro, por omissão: serviços esquecidos nunca ganham retry nem TLS, e descobrem isso em produção, durante um incidente.
O ambassador centraliza essas preocupações em um componente operado pela equipe de plataforma, com configuração versionada e aplicação uniforme. O desenvolvedor de negócio passa a escrever apenas lógica de domínio e confia que toda saída de rede passará pelo mesmo funil de políticas. A diferença aparece com clareza em eventos de failover: quando um banco muda de endpoint, um ambassador recarrega a nova resolução sem que nenhuma aplicação seja recompilada ou reiniciada.
Funcionamento interno
O ciclo de uma chamada com sidecar de saída tem quatro estágios. A aplicação abre conexão para um endereço local de aparência comum, como localhost:15001. O sidecar recebe a conexão e consulta a configuração, que define destino real, política de retry, timeout por rota e política de TLS. O sidecar aplica as políticas na sequência correta, resolvendo DNS, negociando mTLS e escolhendo um endpoint saudável do pool. Por fim, ele registra a observabilidade da requisição, com duração, bytes, códigos e rótulos de destino, e encaminha a resposta de volta à aplicação.
A interceptação em Kubernetes normalmente usa iptables ou eBPF para redirecionar tráfego transparentemente, o que explica por que a aplicação não precisa de mudança nenhuma. Em ambientes sem mesh, o padrão também funciona de forma explícita: a aplicação aponta para um endereço local fixo e o ambassador resolve o destino, como um proxy sidecar para um banco gerenciado que centraliza conexão, credencial e controle de falha.
# Pod Kubernetes com sidecar ambassador para chamadas a serviço externo
apiVersion: v1
kind: Pod
metadata:
name: pedidos-api
labels:
app: pedidos
spec:
containers:
- name: app # aplicação de negócio, sem lógica de rede
image: registry/pedidos:2.4.1
env:
- name: PAGAMENTOS_ENDPOINT # aponta para o localhost do sidecar
value: "http://localhost:15001"
- name: ambassador # proxy acompanhante com políticas
image: envoyproxy/envoy:v1.30.0
ports:
- containerPort: 15001
volumeMounts:
- name: envoy-config # configuração declarativa de políticas
mountPath: /etc/envoy
volumes:
- name: envoy-config
configMap:
name: ambassador-pedidos
A política de resiliência vive no configMap do sidecar e muda sem rebuild da aplicação:
# Trecho de configuração do ambassador: retry e timeout fora do código
route:
cluster: pagamentos_cluster
retry_policy:
retry_on: "5xx,connect-failure,reset" # tenta de novo nesses cenários
num_retries: 3 # no máximo três tentativas
per_try_timeout: 2s # cada tentativa tem teto próprio
timeout: 8s # teto total da requisição
Aplicação prática: ambassador para banco de dados
A variação mais útil em produção é o ambassador na frente de um banco de dados gerenciado, por exemplo um contêiner de pgbouncer ou ProxySQL rodando como sidecar de cada pod da aplicação. O sidecar concentra o pool de conexões por instância, o que protege o banco do erro clássico de cada réplica da aplicação abrir seu próprio pool e multiplicar conexões até esgotar o limite do servidor. Em failover do banco, o ambassador detecta a troca de endpoint e reconecta ao novo primário, e a aplicação apenas espera a chamada seguinte, sem código de descoberta de topologia.
O mesmo desenho serve para caches e filas. Um sidecar na frente do Redis pode centralizar sharding por chave, autenticação por ACL e coleta de comandos lentos, sem que cada cliente da aplicação implemente a mesma lógica. A regra é a mesma do padrão geral: tudo que é política de rede, e não decisão de negócio, pertence ao acompanhante.
# Sidecar de pool de conexões na frente do banco gerenciado
containers:
- name: app
image: registry/pedidos:2.4.1
env:
- name: DATABASE_URL # aplicação fala só com localhost
value: "postgres://app@localhost:6432/pedidos"
- name: pgbouncer-ambassador
image: edoburu/pgbouncer:latest
env:
- name: DB_HOST # destino real resolvido pelo proxy
value: "pedidos.cluster-xyz.rds.amazonaws.com"
- name: POOL_MODE
value: "transaction" # pool transacional, máxima reutilização
- name: MAX_CLIENT_CONN
value: "200" # teto local que protege o banco
Ambassador versus biblioteca cliente
A alternativa clássica ao ambassador é encapsular resiliência em bibliotecas, como clientes HTTP com retry embutido ou drivers que fazem reconexão automática. As duas abordagens competem diretamente, e a escolha afeta linguagens suportadas, custo operacional e latência.
| Critério | Ambassador (sidecar) | Biblioteca cliente |
|---|---|---|
| Consistência entre times | Uniforme, uma configuração | Variável por linguagem e versão |
| Mudança de política | Reload do proxy, sem deploy | Novo build e rollout completo |
| Custo de runtime | CPU e memória extra por pod | Dentro do processo da aplicação |
| Latência adicional | Um salto local por chamada | Praticamente nula |
| Depuração | Rede observável como componente | Misturada no stack da aplicação |
| Requisito de plataforma | Orquestrador ou processo gerenciado | Nenhum, só dependência no build |
A regra prática de escolha é a escala da frota. Com poucos serviços e uma única linguagem, a biblioteca é mais simples e barata. Com dezenas de serviços, várias linguagens e times independentes, o custo de manter consistência por biblioteca supera o custo de recursos do sidecar, e o ambassador vence no ciclo completo de operação.
Service mesh como generalização
Um service mesh é, na essência, uma frota de ambassadors gerenciada centralmente. Cada pod recebe seu sidecar injetado automaticamente, e um plano de controle distribui configuração de roteamento, mTLS e telemetria para todos eles. O Istio com Envoy, o Linkerd e o AWS App Mesh são implementações desse desenho, e o próprio conceito de sidecar do Kubernetes foi popularizado por essa combinação.
A generalização adiciona três capacidades que um ambassador artesanal raramente oferece. A descoberta de serviço com health checking contínuo mantém o pool de endpoints sempre atualizado. A emissão e rotação de certificados mTLS por identidade de workload elimina gestão manual de credenciais. O controle de tráfego declarativo, com split por peso, mirroring e circuit breaking, transforma operações de release em mudança de configuração auditável. O custo é complexidade de plataforma, e a decisão de adotar mesh deve considerar se a frota realmente precisa dessas garantias.
A evolução recente do modelo ataca justamente o custo de densidade do sidecar. Projetos de ambient mesh e o modo sidecar-less do Istio movem as políticas para proxies por nó ou para captura em eBPF no kernel, reduzindo o número de processos por pod e a sobra de memória ociosa. A promessa é manter as garantias do padrão com menos recursos, e acompanhar essa evolução é relevante porque o custo por pod do sidecar clássico é a principal objeção técnica à adoção de mesh em frotas grandes.
Custos de recursos e latência
O sidecar não é gratuito e o preço aparece em três medidas. Em recursos, cada pod passa a hospedar um segundo contêiner que consome dezenas a centenas de megabytes de memória e fração de um vCPU ocioso, o que multiplica por toda a frota; em clusters de milhares de pods, o custo agregado de sidecars torna-se parte relevante da conta. Em latência, cada salto por localhost adiciona tipicamente menos de um milissegundo, mas chamadas em cadeia com muitos saltos acumulam o custo em cada hop, inclusive no caminho de resposta. Em operação, o sidecar entra no caminho crítico, e um proxy mal configurado ou esgotado derruba a aplicação saudável junto, o que exige monitorar o componente acompanhante com o mesmo rigor do negócio.
Erros comuns
- Tráfego furando o sidecar: chamadas que não passam pela interceptação deixam de ter política e telemetria sem que ninguém perceba; audite a cobertura de mTLS por workload.
- Sidecar sem limites de recurso: contêiner acompanhante sem requests e limits compete com a aplicação por CPU e memória no mesmo nó.
- Retry sem budget: o ambassador reprocessa falhas e amplifica tempestades de erro no destino; combine retries com limites globais e circuit breaking.
- Configuração divergente: sidecars editados à mão em pods específicos criam comportamento inconsistente; toda política deve nascer no repositório de plataforma.
- Health check errado: sonda apontando para o sidecar em vez da aplicação, o que mantém pods doentes recebendo tráfego ou derruba pods saudáveis.
Boas práticas
Versione toda configuração de ambassador em infraestrutura como código e trate mudança de política como mudança de produção, com revisão e rollout gradual. Padronize timeouts por classe de dependência, mais agressivos para chamadas síncronas de usuário e mais folgados para processamento em lote, e documente a decisão. Monitore o próprio sidecar com métricas dedicadas, incluindo taxa de retries, tempo de resolução DNS e uso de memória do proxy. Em migrar para service mesh, comece com mTLS em modo permissivo e avance para estrito depois de validar cobertura, pois o caminho reverso tende a gerar incidentes de conectividade difíceis de diagnosticar.