# Beanstalk Cluster Mode: o postmortem que escrevi antes do incidente

O Elastic Beanstalk ganhou um modo em que ambientes com o mesmo conjunto de subnets compartilham um cluster EKS operado pelo serviço. Isso muda o raio de explosão: um ajuste manual no cluster deixa todos os ambientes dele sem deploy até alguém reverter. Escrevi o postmortem desse incidente antes de ele acontecer, só com comportamento documentado, e listo o que configurar no dia zero.

- URL: https://fernando.moretes.com/blog/beanstalk-cluster-mode-o-postmortem-que-escrevi-antes-do-incidente

- Markdown: https://fernando.moretes.com/blog/beanstalk-cluster-mode-o-postmortem-que-escrevi-antes-do-incidente/article.md?lang=pt

- Published: 2026-09-18T10:14:32.031Z

- Category: AWS & Cloud

- Tags: elastic-beanstalk, eks, multi-tenancy, blast-radius, postmortem, finops, platform-engineering

- Reading time: 7 min

- Source: [AWS Elastic Beanstalk introduces Cluster Mode to run multiple applications on shared infrastructure](https://aws.amazon.com/about-aws/whats-new/2026/09/elastic-beanstalk-cluster-mode/)

---

O Cluster Mode do Elastic Beanstalk tem um dia de vida — foi anunciado em 17 de setembro de 2026 — e o incidente abaixo ainda não aconteceu com ninguém que eu conheça. Escrevi o postmortem mesmo assim, porque tudo que ele contém está na documentação: ambientes que usam o mesmo conjunto de subnets vão para o mesmo cluster EKS, o serviço detecta drift quando alguém mexe no cluster por fora, e enquanto o drift durar toda atualização de todo ambiente daquele cluster falha. Depois de 16 anos operando plataforma financeira, aprendi que a pergunta não é 'isso reduz custo?' — é 'quantos serviços param de aceitar hotfix quando uma pessoa erra às 17h de sexta?'.

## O que aconteceu (no ensaio)

**O cenário:** uma equipe de pagamentos com nove serviços em ambientes Standard separados migra todos para Cluster Mode nas mesmas três subnets privadas. O primeiro `create-environment` cria a stack `beanstalk-cluster-{uuid}` em cerca de dez minutos; os outros oito entram no mesmo cluster sem criar nada. A conta de EC2 cai porque o EKS Auto Mode empacota os containers, e a equipe comemora.

**O gatilho:** um engenheiro com `eks:*` na role de administrador nota um node pool que parece ocioso e o edita direto no EKS, como faria em qualquer cluster da empresa. O Beanstalk compara o cluster com a configuração service-managed que ele espera, registra `ERROR Cluster drift detected` no evento do ambiente e pausa a manutenção daquele cluster.

**A consequência:** a partir desse momento, o serviço não coloca ambiente novo nesse cluster, não aplica atualização de add-on e — o ponto que dói — rejeita qualquer `update-environment` dos nove ambientes. Os replicas continuam rodando; o tráfego continua chegando pelo ALB. O que morre é a capacidade de mudar. Duas horas depois, um bug no serviço de conciliação exige hotfix e o deploy falha com uma mensagem que ninguém do plantão tinha visto.

O retro que segue não procura culpado. Procura a fronteira que faltou.

## Linha do tempo

1. **T-14d — Consolidação** — Nove ambientes criados com o mesmo conjunto de subnets e as mesmas `cluster-role`, `node-role` e `observability-role`. Um cluster, um control plane, Kubernetes na versão que o Beanstalk escolheu e que fica fixa pela vida do cluster.

2. **T-0 17:05 — Edição manual** — Node pool alterado no console do EKS. Nenhum alarme dispara: o cluster está saudável do ponto de vista do Kubernetes.

3. **T+0h20 — Drift detectado** — O próximo `update-environment` faz o Beanstalk reavaliar o cluster e emitir `Cluster drift detected ... Service will skip cluster maintenance`. O evento fica na lista de eventos do ambiente — ninguém assina esse fluxo.

4. **T+2h10 — Hotfix bloqueado** — Deploy do serviço de conciliação falha. O plantão tenta em outro ambiente do mesmo cluster: falha igual. Nove serviços sem caminho de mudança.

5. **T+3h40 — Recuperação** — A mensagem de drift diz o que mudou; a equipe reverte a edição do node pool. A próxima operação de ambiente reavalia o cluster, o Beanstalk retoma a gestão e o deploy que falhou é repetido. Recuperação é por cluster, não por ambiente.

> **Causa raiz:** A causa raiz não foi a edição do node pool — foi tratar o conjunto de subnets como decisão de rede quando ele é, no Cluster Mode, a decisão de raio de explosão. A documentação é explícita: mesmo conjunto de subnets, mesmo cluster; falha de cluster afeta todo ambiente nele; subnets e roles não podem ser trocadas depois de criar o ambiente. A equipe consolidou nove serviços com SLOs diferentes numa única fronteira de falha e deixou humanos com permissão de escrita no EKS que o serviço considera dele.

## Subnets escolhem o cluster, o cluster define o raio de explosão

Dois conjuntos de subnets geram dois clusters service-managed. O drift congela só o cluster onde a edição manual aconteceu; o segundo segue aceitando deploy.

### 🟧 AWS — Elastic Beanstalk (control plane do serviço)

- Beanstalk agrupa por subnet set (compute)
- Detector de drift config esperada vs real (security)

### 🟧 AWS — Cluster A (subnets s-1,s-2,s-3) — DRIFTED

- EKS Auto Mode beanstalk-cluster-a (compute)
- eb-payments-api 3 replicas (compute)
- eb-reconciliation hotfix bloqueado (compute)
- Node pool editado à mão (network)

### 🟧 AWS — Cluster B (subnets s-4,s-5,s-6) — saudável

- EKS Auto Mode beanstalk-cluster-b (compute)
- eb-ledger node-pool dedicado (compute)

### 🟧 AWS — Observabilidade compartilhada

- CloudWatch 4 log groups sem retenção (data)

### Fluxos

- gha -> eb: update-environment
- eb -> eksa: mesmo subnet set → cluster A
- eb -> eksb: outro subnet set → cluster B
- eng -> np: edita direto no EKS
- np -> drift: config ≠ esperada
- drift -> pay: update falha
- drift -> rec: update falha
- eb -> ledger: deploy segue normal
- pay -> cw: OTel sidecar
- ledger -> cw: OTel sidecar

## Remediação: desenhar a fronteira antes do primeiro ambiente

**Subnets por domínio de falha, não por VPC:** a decisão mais barata do dia zero é a mais cara de corrigir depois — mudar subnet de ambiente existente é rejeitado, e a saída é criar ambiente novo e trocar CNAME em blue/green. Eu alocaria um conjunto de subnets por regime de SLO e de compliance: um cluster para o que está no escopo do PCI DSS e carrega dados de cartão, outro para o que pode ficar duas horas sem hotfix, outro para dev. Separar produção de desenvolvimento já é o caso que a própria documentação cita como comum.

**Humanos sem escrita no EKS do serviço:** o drift só existe porque alguém pôde editar. Uma SCP ou uma policy de permissão com `Deny` em `eks:Update*`, `eks:Delete*` e `eks:Create*` condicionada a `aws:ResourceTag` das stacks `beanstalk-cluster-*` deixa o caminho de mudança passando obrigatoriamente pelo `update-environment`. Leitura pode ficar liberada; é o que o runbook de verificação de deleção precisa.

**`node-pool` para o que não pode disputar CPU:** sem ele, replicas de ambientes diferentes dividem o mesmo nó. Dar ao serviço de ledger um valor de `node-pool` que nenhum outro ambiente usa tira o vizinho barulhento do caminho, mas mudar esse valor reinicia todos os replicas — decida na criação.

**Um `application-role` por ambiente:** a rede entre ambientes é bloqueada por padrão, mas a saída não é restrita e credencial compartilhada anula a separação. Role por ambiente, escopada ao que ele acessa, é o mínimo.

## Três fronteiras, três raios de explosão
| Critério | Como obter | O que separa | O que não separa | Quando usar |
| --- | --- | --- | --- | --- |
| Cluster compartilhado (padrão) | Mesmo conjunto de subnets | Namespace `eb-<env>` próprio; tráfego entre ambientes bloqueado | Control plane, nós, versão do Kubernetes, drift, saída de rede | Serviços de uma mesma aplicação, mesmo time, mesmo SLO |
| Nós dedicados | `node-pool` com valor único | CPU e memória do nó; vizinho barulhento | Control plane e drift continuam compartilhados | Serviço sensível a latência dentro de um cluster de confiança |
| Clusters separados | Conjuntos de subnets diferentes | Tudo: control plane, nós, rede, drift | Nada — mas cada cluster custa US$ 0,10/h a mais | Clientes distintos, código que você não controla, escopo regulatório |

## Os padrões que só aparecem às 2h da manhã

O retro do drift escondia um segundo incidente esperando a vez. Os padrões dos namespaces `aws:elasticbeanstalk:eks:*` são razoáveis para demo e perigosos para produção financeira.

**Probes desligadas:** readiness, liveness e startup vêm com `enabled=false`. Sem readiness, um replica novo recebe tráfego do ALB antes de abrir o pool de conexões; sem liveness, um processo travado fica no ar até alguém notar. Ligue as três, com `period-seconds` abaixo do padrão de 30 e `failure-threshold` de 3 — o que dá 90 segundos de detecção no pior caso.

**`cpu` de 250m sem `cpu-limit`:** a reserva é pequena e o teto não existe. Um replica com vazamento de CPU disputa o nó com quem estiver do lado. Defina `cpu-limit` e `memory-limit` (o padrão de memória é 1Gi) por serviço, medidos.

**Escala por CPU a 80%:** sem trigger explícito, o serviço escala entre `min-replica=1` e `max-replica=10` por utilização de CPU. Para fila de pagamentos, `scaler-type=metrics-api` lendo o backlog do seu endpoint é a métrica que importa; `min-replica=1` em produção é um único ponto de falha com nome bonito.

**Secrets sem `application-role`:** a opção `secrets` e a `scaler-auth-secret` montam via identidade do pod, que só existe com `application-role` definido. Sem ele, a montagem falha e os replicas nunca sobem — silenciosamente, no primeiro deploy.

**Log groups sem retenção:** os quatro `/aws/elasticbeanstalk/*` são compartilhados por conta e região e nascem sem política de expiração; cada deploy cria stream novo. Defina retenção no dia um.

## A conta que justifica — ou não — o cluster compartilhado

O argumento do Cluster Mode é custo por aplicação caindo conforme o número de aplicações sobe. A conta tem três parcelas fixas que o Standard não tinha.

**Control plane:** US$ 0,10 por cluster por hora, cerca de US$ 73 por mês por conjunto de subnets. Cada fronteira de falha que eu recomendei acima custa isso. Passado o período de suporte padrão do Kubernetes, o suporte estendido sobe para US$ 0,60/h — e como a versão fica fixa pela vida do cluster, esse relógio corre desde a criação.

**EKS Auto Mode:** taxa de gestão por instância além do EC2. No exemplo da página de preços, uma `m5a.xlarge` custa US$ 0,172/h de EC2 mais US$ 0,02064/h de Auto Mode — 12% em cima do compute.

**Métricas custom:** o Standard publica em `AWS/ElasticBeanstalk`, gratuito. O Cluster Mode publica em `ElasticBeanstalk/Infrastructure`, `/System` e `/Application`, namespaces custom cobrados por métrica, e as duas métricas de container saem por replica. Vinte replicas viram dezenas de métricas pagas antes de a aplicação emitir a primeira delas.

O próprio post de lançamento cita a régua: abaixo de cerca de US$ 500 por mês de carga, o overhead do EKS supera a economia e o Standard continua melhor. Minha leitura: o modo compensa quando você tem de seis a oito serviços do mesmo domínio, cada um subutilizando uma instância dedicada hoje, e uma plataforma disposta a pagar US$ 73 por fronteira de falha extra. Com dois serviços, é uma migração para pagar mais e mudar menos.

## Lentes do Well-Architected

- **security**: Rede entre ambientes bloqueada por padrão; abra só com `ingress-groups` ou allowlist no receptor. Saída não é restrita — trate no subnet. Cluster compartilhado é soft multi-tenancy; escopo PCI DSS ou cliente distinto pede subnets próprias. `application-role` por ambiente e `wafv2-acl-arn` no ALB.
- **reliability**: Raio de explosão é decidido pelo conjunto de subnets e é imutável por ambiente. Ligue as três probes, defina `min-replica` ≥ 2 e `max-unavailable=0` no rolling update, e assine os eventos do ambiente para alertar em `Cluster drift detected` — o evento existe, ninguém o lê por padrão.

## Anti-padrões

- **Uma VPC, um conjunto de subnets, todos os serviços:** transforma a conta inteira num único domínio de falha que só se desfaz recriando ambiente por ambiente.
- **Operar o cluster com `kubectl` porque 'é EKS':** é EKS, mas é do serviço; a primeira edição congela deploy de todos os vizinhos.
- **Passar namespaces clássicos (`aws:autoscaling:*`) no `.ebextensions` migrado:** o Cluster Mode devolve `InvalidParameterValueException` em vez de ignorar — o pipeline quebra no primeiro deploy.
- **`GetSecretValue` sem `DescribeSecret` no role da observabilidade custom:** o ambiente sobe, e cada refresh agendado da credencial falha depois — o Datadog para de receber dados sem erro no deploy.
- **Consolidar para economizar com dois serviços:** o control plane e a taxa do Auto Mode custam mais que a instância dedicada que você deixou de pagar.

> **Nota do curador:** Eu adotaria o Cluster Mode para o conjunto de serviços internos de uma mesma equipe — os que hoje pagam instância dedicada para servir 200 requisições por minuto — e não para nada que carregue dado de cartão nos primeiros seis meses. Antes do primeiro ambiente, desenharia o mapa de subnets como desenho um mapa de contas: cada conjunto é um cluster, cada cluster é o que para junto. Negaria escrita no EKS para todo humano, ligaria alarme no evento de drift e colocaria retenção nos log groups no mesmo commit. A lição dura por trás disso: uma plataforma que esconde o Kubernetes não esconde o raio de explosão — ela só muda o nome do botão que o define.

## Veredito

Use o Cluster Mode quando: os serviços pertencem ao mesmo time e ao mesmo SLO, somam mais de US$ 500 por mês em compute subutilizado, e a plataforma aceita pagar US$ 73 por mês por cada fronteira de falha adicional. Fique no Standard quando: são um ou dois serviços, a aplicação guarda estado em disco local, ou o escopo regulatório exige separação de infraestrutura que você não vai pagar em clusters separados. Em qualquer dos casos, a decisão que não tem volta é o conjunto de subnets — trate-a como decisão de arquitetura, com ADR, e não como campo de formulário.

**Rating:** adopt-with-boundaries

## Referências

- [AWS What's New — Elastic Beanstalk introduces Cluster Mode (17 Sep 2026)](https://aws.amazon.com/about-aws/whats-new/2026/09/elastic-beanstalk-cluster-mode/)
- [AWS News Blog — AWS Elastic Beanstalk introduces Cluster Mode](https://aws.amazon.com/blogs/aws/aws-elastic-beanstalk-introduces-cluster-mode/)
- [Elastic Beanstalk Developer Guide — Beanstalk Cluster architecture (grouping, drift, deletion)](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/beanstalk-cluster-concepts.html)
- [Elastic Beanstalk Developer Guide — Multi-tenancy for Beanstalk Cluster environments](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/beanstalk-cluster-multi-tenancy.html)
- [Elastic Beanstalk Developer Guide — Configuration options for Beanstalk Cluster environments](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-general-eks.html)
- [Elastic Beanstalk Developer Guide — Monitoring Beanstalk Cluster environments](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/monitoring-cluster-environments.html)
- [Amazon EKS pricing — control plane and Auto Mode](https://aws.amazon.com/eks/pricing/)
- [Amazon EKS Best Practices — Tenant isolation (soft vs hard multi-tenancy)](https://docs.aws.amazon.com/eks/latest/best-practices/tenant-isolation.html)
