Pular para o conteúdo
fernando.moretes.com
BlogEstudosCursosE-booksOpen SourcePodcasts
Loading…
Fernando Azevedo

Arquiteto de TI Especialista

Arquitetura, AWS, IA em produção, sistemas financeiros e FinOps, escritos a partir do que foi operado, com os números.

  • LinkedIn
  • GitHub
  • E-mail

Conteúdo

  • Blog
  • Estudos de arquitetura
  • Cursos
  • E-books
  • Open Source
  • Podcasts
  • Assuntos
  • Trilhas

Ferramentas

  • Well-Architected self-check
  • Arquitetura deste site
  • Números públicos
  • Histórico de estudo

Sobre

  • Comunidade
  • IA Builder
  • Perfil
  • Currículo (CV)
  • Trabalhe comigo
  • Media kit
  • RSS do blog
  • RSS dos estudos
  • Artigos narrados (podcast)
  • llms.txt
  • Termos, privacidade e uso de IA

(c) 2026 Fernando Francisco Azevedo

Blog/Artigo
RSSMarkdownLLMs
AWS & CloudHistória de Migração

Migração para Plataformas Stateful Cloud Native no AWS EKS

26 de mai. de 2026 11 minEspecialista Com apoio de IA000 visualizações00 reproduções
Ouvir artigo

22:37 · voz do Fernando

Plataformas cloud native stateful multitenant são o novo campo minado da engenharia de infraestrutura. Quando o estado importa, e em sistemas financeiros ele sempre importa, a promessa de elasticidade do Kubernetes colide com a realidade de consistência, isolamento de dados entre tenants e falhas parciais que não têm rollback simples. Eu já vi essa migração ser feita de forma apressada, com equipes que trataram pods stateful como se fossem funções Lambda e pagaram o preço em incidentes de corrupção de dados e violações de isolamento entre clientes. O que apresento aqui é a jornada estruturada que eu recomendaria, e que executei, para mover uma plataforma financeira de VMs legadas para um EKS multitenant com garantias reais.

O Ponto de Partida: VMs, Estado Implícito e a Ilusão de Controle

A plataforma original rodava em instâncias EC2 r6i.4xlarge com discos EBS gp2 montados diretamente, um banco de dados PostgreSQL por tenant em RDS Single-AZ, e uma camada de cache Redis gerenciada manualmente via scripts de bootstrap. O modelo funcionava, até não funcionar. Cada tenant tinha seu próprio conjunto de instâncias, o que garantia isolamento forte mas tornava o custo operacional proibitivo: 40 tenants significavam 40 stacks de infraestrutura, 40 pipelines de patch, 40 runbooks de failover. A equipe de operações passava mais tempo gerenciando infraestrutura do que entregando valor.

O estado era implícito em toda parte: sessões de usuário em memória local, filas de processamento em tabelas PostgreSQL sem particionamento adequado, e configurações de tenant espalhadas em arquivos .env versionados manualmente. Não havia um inventário confiável de qual instância servia qual tenant em um dado momento. Quando um nó falhava, o processo de recuperação envolvia SSH, verificação manual de logs e restauração de snapshots EBS, um MTTR médio de 47 minutos para incidentes de dados.

A pressão para migrar veio de dois lados: custo (a conta EC2 crescia linearmente com o número de tenants) e compliance (um audit de SOC 2 Type II identificou a falta de separação lógica auditável entre tenants como um achado de alto risco). A decisão de ir para EKS não foi tomada por modismo, foi tomada porque o modelo de operadores Kubernetes oferecia a automação de ciclo de vida que a equipe precisava para escalar sem crescer o headcount de operações proporcionalmente.

A Jornada de Migração: Seis Fases com Decisões Reais

  1. 1

    Fase 1: Inventário de Estado e Classificação de Workloads

    Antes de tocar em qualquer infraestrutura, mapeamos todos os pontos de estado: dados transacionais (PostgreSQL), cache de sessão (Redis), filas de jobs (tabelas PG), blobs de documentos (S3 já existente) e configuração de tenant (arquivos locais). Cada categoria recebeu uma classificação: stateless, stateful-ephemeral ou stateful-durable. Workloads stateless foram os primeiros a migrar. Stateful-durable foram os últimos, e exigiram operadores dedicados.

  2. 2

    Fase 2: Design do Modelo de Multitenancy no EKS

    Avaliamos três modelos: cluster por tenant (forte isolamento, custo alto), namespace por tenant no mesmo cluster (custo eficiente, isolamento via RBAC e NetworkPolicy), e namespace por tenant com node pools dedicados por tier de criticidade. Escolhemos o terceiro: namespaces por tenant com node groups separados para tenants Gold (instâncias r6i.2xlarge dedicadas com taints) e Silver/Bronze (node group compartilhado com m6i.xlarge). Isso balanceou custo e isolamento de blast radius.

  3. 3

    Fase 3: Persistência: EBS CSI, EFS e Aurora Serverless v2

    Para dados transacionais, migramos de RDS Single-AZ para Aurora PostgreSQL Serverless v2 com réplicas de leitura por tenant-group. O driver EBS CSI com StorageClass gp3 (3000 IOPS base, throughput de 125 MB/s) substituiu os volumes gp2 montados manualmente. Para artefatos compartilhados entre pods de um mesmo tenant (relatórios, uploads), usamos EFS com access points por namespace, garantindo isolamento de sistema de arquivos sem compartilhamento acidental entre tenants.

  4. 4

    Fase 4: Operadores Kubernetes para Ciclo de Vida de Tenant

    Desenvolvemos um operador customizado (usando controller-runtime) que reagia a um CRD TenantWorkspace. Ao criar um TenantWorkspace, o operador provisionava: namespace com labels de tenant, ResourceQuota (CPU/memória/PVC), NetworkPolicy de isolamento, ServiceAccount com IRSA binding para o KMS key do tenant, e um segredo no AWS Secrets Manager referenciado via External Secrets Operator. O tempo de provisionamento de um novo tenant caiu de 4 horas (manual) para 8 minutos (automatizado).

  5. 5

    Fase 5: Migração de Dados com Janela de Corte Controlada

    Usamos AWS DMS com replicação contínua (CDC) para sincronizar os bancos RDS legados com os novos clusters Aurora durante um período de shadow de 72 horas. O cutover foi executado tenant por tenant, começando pelos de menor volume transacional. Cada cutover seguia o padrão: (1) drenar conexões do app legado, (2) confirmar lag de replicação < 5 segundos, (3) promover Aurora como primário, (4) atualizar DNS interno via Route 53 weighted routing, (5) monitorar por 30 minutos antes de descomissionar a instância legada.

  6. 6

    Fase 6: Observabilidade e Validação de SLOs

    Instrumentamos todos os serviços com OpenTelemetry SDK (traces e métricas), exportando para AWS X-Ray (traces) e CloudWatch Container Insights (métricas de infraestrutura). Um dashboard Datadog consolidou SLOs por tenant: disponibilidade de 99,9% (janela de 30 dias), latência P99 < 800ms para operações de escrita, e taxa de erro < 0,1%. Alertas de burn rate foram configurados para disparar quando o error budget consumia mais de 5% em 1 hora, muito antes de violar o SLO.

O Modelo de Isolamento: Além do Namespace

Namespace por tenant é necessário, mas longe de suficiente em um ambiente financeiro. O namespace é uma fronteira de nomenclatura e RBAC, ele não impede que um pod mal configurado acesse a rede de outro tenant, nem que uma chave de criptografia seja compartilhada inadvertidamente.

O modelo de isolamento que implementamos tem quatro camadas:

1. Isolamento de rede: NetworkPolicy padrão nega todo tráfego ingress e egress dentro do cluster, exceto rotas explicitamente permitidas. Cada tenant só pode se comunicar com seu próprio namespace e com o namespace platform-services (que contém o proxy de saída e o serviço de autenticação). Usamos Calico como CNI para suporte a GlobalNetworkPolicy, que aplica regras antes mesmo das políticas de namespace.

2. Isolamento de identidade: Cada ServiceAccount de tenant tem uma IAM Role dedicada via IRSA (eks.amazonaws.com/role-arn annotation). A IAM Role tem uma condition StringEquals no sts:AssumeRoleWithWebIdentity que verifica o sub do token OIDC, garantindo que apenas pods do namespace correto possam assumir aquela role. Isso previne privilege escalation mesmo que um pod consiga criar um ServiceAccount em outro namespace.

3. Isolamento de criptografia: Cada tenant tem uma KMS Customer Managed Key (CMK) própria. Os volumes EBS, os segredos no Secrets Manager e os dados no S3 de cada tenant são criptografados com a CMK do tenant. A key policy da CMK usa kms:ViaService e aws:SourceAccount conditions para garantir que apenas chamadas originadas dos serviços corretos possam usar a chave.

4. Isolamento de recursos: ResourceQuota e LimitRange por namespace previnem que um tenant monopolize CPU ou memória do node group compartilhado. Para tenants Gold, os taints nos nodes dedicados garantem que nenhum pod de outro tenant seja agendado lá, mesmo em situações de pressão de scheduling.

Arquitetura da Plataforma Stateful Multitenant no EKS

Fluxo de provisionamento e isolamento de tenant: do CRD TenantWorkspace ao estado persistente, com camadas de segurança e observabilidade.

🤖 EKS: Operator Plane
  • TenantWorkspace · Operator (controller-runtime)
  • External Secrets · Operator
🔐 AWS: Security & Identity
  • IRSA / OIDC · per-tenant IAM Role
  • KMS CMK · per-tenant key
  • Secrets Manager · per-tenant secret
📦 EKS: Tenant Namespace (Gold/Silver/Bronze)
  • Namespace · + NetworkPolicy + ResourceQuota
  • Stateful App Pods · (gp3 EBS PVC)
  • Redis StatefulSet · ephemeral-stateful
🗄️ AWS: Persistent Storage
  • Aurora PostgreSQL · Serverless v2 (per tenant-group)
  • EFS Access Point · per-namespace
  • S3 Bucket · SSE-KMS per tenant
📊 Observability
  • OTel Collector · traces + metrics
  • Datadog · SLO dashboards

Operadores Kubernetes: A Diferença entre Automação Real e Scripts com Kubectl

A decisão de investir em um operador customizado em vez de scripts Helm + kubectl foi a que mais gerou debate interno. O argumento contra era legítimo: operadores têm custo de desenvolvimento alto, introduzem um componente crítico no plano de controle e são difíceis de depurar quando o reconciliation loop entra em estado inconsistente.

O argumento a favor, que prevaleceu, foi baseado em três propriedades que scripts não têm:

Reconciliação contínua: Um script roda uma vez. Um operador observa continuamente o estado desejado versus o estado atual. Quando um engenheiro acidentalmente deletou uma NetworkPolicy de um tenant em produção (aconteceu), o operador a recriou em menos de 30 segundos, antes que qualquer tráfego não autorizado pudesse ocorrer. Com scripts, isso seria um incidente de segurança.

Gestão de ciclo de vida completo: O operador gerencia criação, atualização e deleção (com finalizers para garantir que dados não sejam deletados antes do backup). Um script de provisionamento raramente inclui lógica de deprovisioning segura, e quando inclui, é testada com muito menos rigor.

Status e observabilidade nativos: O CRD TenantWorkspace tem um campo .status.conditions com condições como StorageProvisioned, NetworkPolicyApplied, SecretsSync. Qualquer ferramenta que consuma a API do Kubernetes pode observar o estado de cada tenant em tempo real. Isso foi fundamental para o time de suporte: em vez de SSH em nodes, eles fazem kubectl get tenantworkspace -n platform-ops e veem o estado de todos os tenants em segundos.

O custo real do operador foi de aproximadamente 3 sprints de desenvolvimento e 1 sprint de hardening de testes de integração. O break-even operacional foi atingido no quarto mês, quando o número de tenants ultrapassou 60 e a complexidade de gerenciamento teria exigido contratar mais um engenheiro de operações.

Antes e Depois: Métricas Operacionais da Migração

47min → 4min
MTTR médio para incidentes de dados
Reconciliação automática do operador + alertas de burn rate eliminaram a fase de diagnóstico manual
4h → 8min
Tempo de provisionamento de novo tenant
CRD TenantWorkspace + operador substituiu 4 horas de trabalho manual com scripts e aprovações
68% ↓
Redução de custo de infraestrutura por tenant
Node groups compartilhados para Silver/Bronze + Aurora Serverless v2 (escala a zero em horários ociosos) vs. EC2 dedicado 24/7

Persistência Stateful no Kubernetes: O Que Ninguém Te Conta Sobre PVCs em Produção

PersistentVolumeClaims com EBS têm uma limitação fundamental que frequentemente surpreende equipes em migração: um volume EBS só pode ser montado em um único node por vez (ReadWriteOnce). Isso tem implicações diretas em estratégias de deployment.

Com Deployment (não StatefulSet), um rolling update pode tentar criar o novo pod em um node diferente antes que o pod antigo libere o volume, resultando em um estado onde o novo pod fica em ContainerCreating indefinidamente, aguardando o volume ser desanexado. Em ambientes financeiros com janelas de manutenção curtas, isso pode ser catastrófico.

A solução que adotamos foi tripla: (1) usar StatefulSet para todos os workloads com PVCs EBS, o que garante que o pod antigo seja terminado antes do novo ser criado; (2) configurar podManagementPolicy: Parallel apenas para StatefulSets onde a ordem de startup não importa (cache Redis), mantendo OrderedReady para os que têm dependências de inicialização; (3) implementar PodDisruptionBudget com minAvailable: 1 para garantir que drenos de node (durante upgrades do EKS) não removam o único pod de um tenant crítico sem um substituto pronto.

Para o caso de uso de artefatos compartilhados entre múltiplos pods do mesmo tenant (relatórios gerados assincronamente, por exemplo), EFS com ReadWriteMany foi a escolha correta, mas com uma ressalva importante: EFS tem latência de escrita significativamente maior que EBS para operações síncronas (tipicamente 1-5ms vs. 0.1-0.5ms para gp3). Qualquer path de código que escrevia no EFS de forma síncrona foi refatorado para escrita assíncrona via SQS, com o EFS sendo o destino final após processamento.

Riscos Críticos Que Quase Nos Custaram a Migração

1. Vazamento de estado entre tenants via cache compartilhado: Em uma versão inicial, o Redis era compartilhado entre tenants Silver com prefixos de chave como separador. Um bug de prefixo em uma versão de código expôs dados de sessão de um tenant para outro por 12 minutos antes da detecção. A correção foi mover para Redis StatefulSets por tenant-group (não por tenant individual, custo proibitivo) com autenticação ACL por tenant. 2. EBS volume attachment storm durante upgrades de node group: Ao fazer rolling upgrade de um node group com 30 tenants, todos os volumes EBS tentaram ser desanexados e reanexados simultaneamente. O limite de 28 volumes EBS por instância r6i.2xlarge foi atingido, causando falhas de scheduling. A solução foi configurar maxUnavailable: 1 no node group e usar PodDisruptionBudgets para forçar um ritmo controlado de migração de pods. 3. Drift de configuração de NetworkPolicy: Sem o operador de reconciliação ativo por 40 minutos durante uma janela de manutenção, um deploy manual de emergência criou um pod sem as labels corretas de tenant, que ficou fora das NetworkPolicies e com acesso irrestrito à rede interna do cluster. Isso reforçou a regra: o operador nunca pode ser desativado, mesmo em manutenção, ele deve ser atualizado com zero downtime via rolling update.

Observabilidade em Plataformas Multitenant: O Tenant Como Dimensão de Primeira Classe

O erro mais comum que vejo em plataformas multitenant é tratar observabilidade como uma preocupação de infraestrutura, métricas de CPU, memória e latência agregadas no nível do cluster. Isso é inútil quando um cliente liga reclamando de lentidão: você não consegue isolar o problema sem dimensões de tenant.

A decisão arquitetural mais impactante na fase de observabilidade foi definir tenant_id como uma dimensão obrigatória em todas as métricas, traces e logs da plataforma. Isso foi implementado em três camadas:

Aplicação: O OTel SDK foi configurado com um Resource que inclui tenant.id e tenant.tier como atributos. Todos os spans herdam esses atributos automaticamente. No lado de métricas, usamos exemplars para vincular métricas de alta cardinalidade a traces específicos, fundamental para investigar P99 de um tenant específico.

Infraestrutura: CloudWatch Container Insights foi configurado com enhanced observability no EKS, que coleta métricas por pod com labels de Kubernetes. Um filtro de métricas no CloudWatch Logs Insights extrai tenant_id dos logs estruturados e cria métricas customizadas com essa dimensão.

SLO por tenant: No Datadog, cada tenant tem um SLO monitor independente. O burn rate alert usa uma janela de 1 hora (alerta rápido) e 6 horas (alerta de tendência). Quando o burn rate de 1 hora ultrapassa 14,4x (consumindo 2% do budget em 1 hora), um PagerDuty alert é criado com o tenant_id no título, o on-call sabe imediatamente qual tenant está impactado sem precisar investigar dashboards.

O custo de ingestão de métricas com alta cardinalidade foi uma preocupação real. A solução foi usar histogram_quantile no Prometheus (rodando como Managed Service via AMP) para métricas de latência, em vez de gauges por percentil, reduzindo a cardinalidade em 80% com precisão equivalente para SLOs.

Avaliação pelos Pilares Well-Architected

Segurança

Isolamento em quatro camadas (rede, identidade, criptografia, recursos) com IRSA + KMS CMK por tenant. NetworkPolicy default-deny com Calico GlobalNetworkPolicy. Auditoria via CloudTrail de todas as chamadas KMS por tenant_id.

Confiabilidade

StatefulSets com PodDisruptionBudgets garantem disponibilidade durante upgrades. Aurora Serverless v2 com réplicas de leitura e failover automático < 30s. Operador com reconciliação contínua previne drift de configuração.

FA
Minha Nota de Curadoria
Arquiteto de TI Especialista

Se eu fosse começar essa migração hoje, a única coisa que faria diferente seria investir no operador Kubernetes antes de migrar o primeiro tenant, não depois do quinto. A tentação de usar Helm charts e scripts bash para os primeiros tenants é enorme, e o débito técnico que isso cria é desproporcional. A lição mais dura que carrego dessa jornada é que isolamento em plataformas multitenant não é uma feature que você adiciona depois: é uma propriedade que precisa ser provada matematicamente antes do primeiro tenant de produção, com testes de penetração de namespace e simulações de falha de NetworkPolicy. Em ambientes financeiros, um vazamento de dados entre tenants não é um bug de severidade 2, é um evento regulatório.

Veredicto: Plataformas Stateful Cloud Native São Viáveis em Produção Financeira: Com as Condições Certas

A migração para uma plataforma stateful cloud native multitenant no EKS é tecnicamente viável e operacionalmente superior ao modelo de VMs por tenant, mas apenas se você aceitar que o investimento inicial é maior do que parece. O operador Kubernetes, o modelo de isolamento em quatro camadas e a observabilidade com dimensão de tenant não são otimizações opcionais: são pré-requisitos para operar com segurança em escala. Os números falam por si: 68% de redução de custo por tenant, MTTR de 47 minutos para 4 minutos, e provisionamento de 4 horas para 8 minutos são resultados reais, mas foram precedidos por 3 meses de trabalho de plataforma que não entregou nenhuma feature de negócio. Se a sua organização não tem tolerância para esse investimento upfront, o modelo de VMs por tenant, por mais caro que seja, é mais seguro do que uma plataforma Kubernetes mal isolada. A cloud native não é o destino certo para todo mundo, mas para quem faz o trabalho direito, a vantagem operacional composta ao longo do tempo é difícil de contestar.

Referências

CNCF Blog: Stateful Cloud Native PlatformsAWS EKS Best Practices Guide: Multi-tenancyAWS EKS EBS CSI Driver DocumentationAWS IRSA: IAM Roles for Service AccountsAurora Serverless v2: How it worksKubernetes: Operator PatternExternal Secrets OperatorOpenTelemetry: Resource Semantic Conventions
#eks#stateful#kubernetes#multitenancy#migration#financial-grade#operators#observability
Compartilhar:LinkedInWhatsAppXBaixar em Markdown
Fonte analisada: Stateful cloud native platforms
Próximo passo
Trilha Arquiteto de IA, gratuitaFundamentos, LLMs, RAG, tools, MCP e arquitetura na AWS, em aulas curtas e interativas.Começar a trilhaAgentes de IA em produção na AWSComo eu desenho, oriento e audito agentes que vão ao ar, com os números e as fontes.Ver o IA Builder

Continue lendo

AWS & CloudAWS Network Firewall como Forward Proxy: Análise Técnica do PreviewA AWS reintroduziu o forward proxy como funcionalidade nativa do Network Firewall, unificando políticas de segurança entre os modos transparent e explicit proxy sob um único recurso. Esta análise examina o que mudou em relação ao preview de novembro de 2025, onde a funcionalidade genuinamente agrega valor em ambientes financeiros e onde os riscos operacionais ainda pedem cautela.Ler AWS & CloudMigrando Workloads de Alta Rede para EC2 R6in/R6idn em Paris e CanadáA disponibilização das instâncias R6in e R6idn na Europa (Paris) e Canadá (Central) em julho de 2026 fecha uma lacuna de residência de dados crítica para workloads financeiros e de analytics em tempo real. Este artigo narra a jornada de migração de instâncias R5n para R6in/R6idn, detalhando decisões de arquitetura, riscos operacionais e os ganhos mensuráveis de rede e IOPS que justificam o movimento.Ler AWS & CloudMigrando Workloads Financeiros para EC2 R8i: Decisões e Trade-offsA disponibilização das instâncias EC2 R8i (R8in, R8ib, R8idn, R8idb) em Tokyo, Frankfurt e Irlanda em julho de 2026 abre uma janela concreta de modernização para plataformas financeiras que ainda operam em R6i/R6in, gerações com limitações reais de banda de rede e throughput de EBS. Este artigo narra a jornada de migração como uma sequência de decisões de arquitetura, com os riscos gerenciados em cada etapa e os números que justificam a movimentação.Ler
AnteriorUma Organização ou Várias? O Postmortem que Ninguém Quer EscreverPróximoCloudWatch para OTel: Desmontando o Padrão de Bridge de Observabilidade
Gostou desta análise? Receba a próxima.

Deep dives de arquitetura, AWS, IA e mercado: direto no seu email. Grátis.

Sem spam · cancele quando quiser

Pergunte ao Fernando sobre isto

Uma resposta focada sobre este artigo, do meu assistente de IA, baseada no meu trabalho.

Participe da conversa

Entre para comentar

Confirme seu e-mail para participar, você também recebe a newsletter. Sem senha.

Neste artigo
O Ponto de Partida: VMs, Estado Implícito e a Ilusão de ControleA Jornada de Migração: Seis Fases com Decisões ReaisO Modelo de Isolamento: Além do NamespaceArquiteturaOperadores Kubernetes: A Diferença entre Automação Real e Scripts com KubectlPersistência Stateful no Kubernetes: O Que Ninguém Te Conta Sobre PVCs em ProduçãoObservabilidade em Plataformas Multitenant: O Tenant Como Dimensão de Primeira ClasseWell-ArchitectedVeredicto: Plataformas Stateful Cloud Native São Viáveis em Produção Financeira: Com as Condições CertasReferências