Pular para o conteúdo principal
Este guia orienta sobre a implantação completa da infraestrutura EKB EKS no AWS usando Terragrunt. Ele cobre instalação de ferramentas, configuração do ambiente e uma sequência de implantação em fases projetada para garantir a ordem adequada de dependências em todos os componentes da infraestrutura. As implantações são organizadas em nove fases:
  1. Gerenciamento de Estado — Inicializa o bucket S3 usado para armazenar o estado do Terraform do ambiente.
  2. Infraestrutura EKS — Provisiona a VPC, sub-redes, NAT gateways, funções IAM e o cluster EKS e node groups gerenciados.
  3. Armazenamento e Balanceamento de Carga — Implantar o EBS CSI driver para volumes persistentes e o AWS Load Balancer Controller para ingress ALB.
  4. Escalação Automática Karpenter — Configura provisionamento dinâmico de nós com suporte a instâncias Spot e tratamento de interrupção via SQS e EventBridge.
  5. Escalação Automática KEDA — Implantar o KEDA para escalação automática em nível de pod baseada em limites de CPU e memória.
  6. Serviços de Dados — Provisionar Supabase (auto-hospedado ou Cloud), ElastiCache Redis e Amazon MQ RabbitMQ.
  7. Serviços Odin — Implantar a pilha de aplicação EKB (Web, FastAPI, Celery, Automator) via Helm.
  8. Observabilidade SigNoz — Implantar rastreamento distribuído, métricas e agregação de logs via SigNoz e o agente k8s-infra.
  9. Implantação Final — Executar um terragrunt apply completo para reconciliar quaisquer recursos restantes.
Antes de começar, complete a lista de verificação de pré-requisitos com o cliente e certifique-se de que todos os placeholders <YOUR_*> no template do ambiente estejam preenchidos. Vários valores — incluindo o ID da VPC, endpoint do cluster EKS e endpoints Redis e RabbitMQ — só estão disponíveis após a conclusão de fases específicas, portanto o guia indica exatamente quando capturá-los e aplicá-los.

Pré-requisitos

  • AWS CLI configurada com permissões apropriadas
  • Terraform (>= 1.0)
  • Terragrunt (versão mais recente)
  • kubectl para gerenciamento do Kubernetes
  • helm para gerenciamento de charts Helm

Guia de Instalação

Instalando o Terragrunt

macOS (Homebrew)
brew install terragrunt
Linux (apt)
# Adicionar chave GPG da HashiCorp
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg

# Adicionar repositório HashiCorp
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list

# Atualizar e instalar
sudo apt update
sudo apt install terragrunt
Windows (Chocolatey)
choco install terragrunt

Instalando o kubectl

macOS (Homebrew)
brew install kubectl
Linux
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
Windows (Chocolatey)
choco install kubernetes-cli

Instalando o Helm

macOS (Homebrew)
brew install helm
Linux
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Windows (Chocolatey)
choco install kubernetes-helm

Verificando a Instalação

terragrunt --version
terraform --version
kubectl version --client
helm version

Configuração da AWS CLI

# Instalar AWS CLI
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

# Configurar credenciais AWS
aws configure

# Verificar configuração
aws sts get-caller-identity

Criando um Novo Ambiente

Passo 1: Copie o Template do Ambiente

A pasta env-template-folder contém arquivos pré-estruturados com placeholders <YOUR_*> prontos para serem preenchidos. Copie-a inteiramente para criar sua nova pasta de ambiente.
# Navegue até o diretório de ambientes do terragrunt
cd terragrunt/environments

# Copie a pasta template completa para um novo ambiente (substitua 'nome-do-seu-ambiente')
cp -r env-template-folder nome-do-seu-ambiente

# A estrutura de pastas está pronta:
# nome-do-seu-ambiente/
# ├── terragrunt.hcl               # Configuração principal do cluster
# ├── state/
# │   └── terragrunt.hcl           # Configuração do bucket de estado S3
# └── values/
#     ├── infrastructure.yaml      # AWS Load Balancer Controller
#     ├── karpenter-values.yaml    # Configurações do controlador Karpenter
#     ├── karpenter-nodeclasses.yaml  # Definições EC2NodeClass
#     ├── karpenter.yaml           # Definições Karpenter NodePool
#     ├── keda.yaml                # Escalonador KEDA
#     ├── aws-ebs-csi-driver.yaml  # EBS CSI driver
#     ├── odin-services.yaml       # Serviços de aplicação Odin
#     ├── supabase.yaml            # Supabase (se auto-hospedado)
#     ├── ha-supabase-db.yaml      # Supabase HA DB (se auto-hospedado)
#     ├── cloudnative-pg.yaml      # Operador CloudNativePG (se auto-hospedado)
#     ├── signoz.yaml              # Observabilidade SigNoz (opcional)
#     └── signoz-k8s-infra.yaml    # Métricas SigNoz k8s (opcional)

Passo 2: Verifique se Todos os Placeholders Estão Presentes

cd nome-do-seu-ambiente

# Listar todos os placeholders que precisam ser preenchidos
grep -r "<YOUR_" . --include="*.hcl" --include="*.yaml" | sort
Todos os placeholders seguem a convenção <YOUR_*>. Os passos abaixo orientam sobre como preenchê-los arquivo por arquivo.

Passo 3: Provisionar Certificados SSL (AWS ACM)

Antes de definir variáveis de ambiente, você precisa dos ARNs dos certificados. Use o Console AWS para solicitar certificados SSL no AWS Certificate Manager (ACM) para todos os domínios que seu ambiente servirá. Opção A: Certificado wildcard único (recomendado) Um único certificado wildcard cobre todos os subdomínios com um único ARN. Por exemplo, se seu domínio base for app.example.com, um único certificado *.app.example.com cobre:
ServiçoDomínio
Webapp.example.com
FastAPIapi-app.example.com
Automatorautomations-app.example.com
Supabasesupabase-app.example.com
SigNozsignoz-app.example.com
Opção B: Certificados por serviço Solicite um certificado por domínio se não puder usar um wildcard. Repita os passos abaixo para cada domínio: <YOUR_WEB_DOMAIN>, <YOUR_API_DOMAIN>, <YOUR_AUTOMATOR_DOMAIN>, <YOUR_SUPABASE_DOMAIN> (apenas se ENABLE_SUPABASE=true), <YOUR_SIGNOZ_DOMAIN> (apenas se ENABLE_SIGNOZ=true). Solicitando um certificado no Console AWS
  1. Abra o console do AWS Certificate Manager
  2. Mude para a região correta (canto superior direito) — deve corresponder a <YOUR_AWS_REGION>
  3. Clique em Request a certificateRequest a public certificateNext
  4. Em Fully qualified domain name, insira o wildcard (por exemplo, *.app.example.com) ou um domínio específico
  5. Defina Validation method como DNS validation
  6. Clique em Request — o certificado é criado no estado Pending validation
Adicionando o registro de validação DNS CNAME O ACM gera um registro CNAME que você deve adicionar ao seu provedor DNS para provar a titularidade do domínio. Obtenha os valores no Console ACM abrindo o certificado e expandindo o domínio em Domains.
Campo DNSValor
Tipo de registroCNAME
Nome / Hostpor exemplo, _fa187f22ac17bce6f508bf3c56439c61.signoz-app.example.com.
Valor / Aponta parapor exemplo, _c7c97325fe38061e168e232d122c7ff3.jkddzztszm.acm-validations.aws.
Inclua o ponto final (.) no final dos valores CNAME se seu provedor DNS exigir.
Cloudflare
  1. Faça login no Cloudflare → selecione seu domínio → vá para DNSRecordsAdd record
  2. Defina Type como CNAME
  3. Cole o nome CNAME do ACM em Name e o valor CNAME do ACM em Target
  4. Defina Proxy status como DNS only (ícone de nuvem cinza) — o certificado não será validado através do proxy Cloudflare
  5. Clique em Save
Route 53
  1. Abra o console Route 53 → Hosted zones → selecione sua zona → Create record
  2. Defina Record type como CNAME
  3. Cole o nome CNAME do ACM em Record name (apenas a parte do subdomínio) e o valor em Value
  4. Defina TTL como 300 e clique em Create records
No ACM, você também pode clicar em Create records in Route 53 para que o ACM adicione o registro automaticamente se a hosted zone estiver na mesma conta.
Uma vez que o DNS propagar (tipicamente 1–5 minutos), o status do certificado muda para Issued. Copie o ARN do topo do certificado — ele se parece com arn:aws:acm:<regiao>:<account-id>:certificate/<uuid>. Mantenha o(s) ARN(s) à mão para o próximo passo.

Passo 4: Defina as Variáveis de Ambiente

Defina estas variáveis de ambiente do shell antes de executar quaisquer comandos Terragrunt. Elas são lidas diretamente por terragrunt.hcl via get_env().
export AWS_REGION="<YOUR_AWS_REGION>"          # por exemplo, "eu-west-2", "us-east-2"
export CLUSTER_NAME="<env_folder_name>"          # por exemplo, "env-template-folder"

# Configuração de domínio
export WEB_DOMAIN="<YOUR_WEB_DOMAIN>"                    # por exemplo, "app.example.com"
export FASTAPI_DOMAIN="<YOUR_API_DOMAIN>"                # por exemplo, "api-app.example.com"
export AUTOMATOR_DOMAIN="<YOUR_AUTOMATOR_DOMAIN>"        # por exemplo, "automations-app.example.com"
export SUPABASE_DOMAIN="<YOUR_SUPABASE_DOMAIN>"          # por exemplo, "supabase-app.example.com"
export SIGNOZ_DOMAIN="<YOUR_SIGNOZ_DOMAIN>"              # por exemplo, "signoz-app.example.com"

# ARNs de Certificados SSL — Opção A: Certificado wildcard único (recomendado)
export WILDCARD_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_WILDCARD_CERT_ID>"

# ARNs de Certificados SSL — Opção B: Certificados por serviço
export WEB_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_WEB_CERT_ID>"
export FASTAPI_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_API_CERT_ID>"
export AUTOMATOR_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_AUTOMATOR_CERT_ID>"
export SUPABASE_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_SUPABASE_CERT_ID>"
export SIGNOZ_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_SIGNOZ_CERT_ID>"

# Flags de habilitação de serviços
export ENABLE_ALB_CONTROLLER="true"
export ENABLE_AWS_SERVICES="true"      # Defina como "true" para habilitar ElastiCache e AmazonMQ

# Pilha Supabase (auto-hospedado) — habilite os três juntos se auto-hospedando o Supabase
export ENABLE_CNPG="true"             # Operador CloudNativePG  (namespace: cnpg-system)
export ENABLE_HA_SUPABASE_DB="true"   # Supabase HA database    (namespace: ha-supabase-db)
export ENABLE_SUPABASE="true"         # Aplicação Supabase      (namespace: supabase)

export ENABLE_SIGNOZ="true"           # Defina como "true" para habilitar observabilidade SigNoz
export SSL_TERMINATION="alb"

Instâncias Spot e Cargas de Trabalho Estatais

As instâncias Spot são configuradas por NodePool em values/karpender.yaml, não via variáveis de ambiente. Cada NodePool declara sua própria estratégia de capacidade:
NodePoolRótulo workload-typeTipo de CapacidadeJustificativa
generalgeneralSpot → fallback On-DemandOtimizado em custo para cargas de trabalho em lote/segundo plano sem estado
compute-intensivecompute-intensiveSpot → fallback On-DemandOtimizado em custo para cargas de trabalho limitadas por CPU
memory-intensivememory-intensiveOn-Demand → fallback SpotEstabilidade priorizada para pods de alta memória
gpugpuSpot → fallback On-DemandOtimizado em custo para cargas de trabalho em lote de IA/ML
applicationapplicationApenas On-DemandServiços estáveis面向 ao usuário (Supabase, Kong, etc.) — sem interrupções Spot
databasedatabase / node-type: database-dedicatedApenas On-DemandEstatal — interrupção Spot é insegura para bancos de dados
O NodePool application usa famílias de instâncias m/c (geração 5+) com apenas On-Demand. Os pods do serviço Supabase são fixados aqui via nodeSelector: workload-type: "application" para garantir que nunca sejam interrompidos por um evento de reivindicação Spot. O NodePool database-dedicated nunca usa Spot. Ele usa consolidationPolicy: WhenEmpty para que o Karpenter não evicta um nó que ainda tem um pod em execução, tornando-o seguro para cargas de trabalho estatais como réplicas PostgreSQL e CloudNativePG. Diretrizes para aplicações estatais no Spot:
  • Não agende bancos de dados, filas persistentes ou qualquer pod com PersistentVolumeClaim em NodePools Spot.
  • Use um nodeSelector direcionando node-type: database-dedicated com a toleração correspondente database-workload: "true" para pods de banco de dados.
  • Use nodeSelector: workload-type: "application" para serviços sem estado面向 ao usuário que devem permanecer disponíveis sem interrupção.
  • Para cargas de trabalho em segundo plano (Web, API, Celery, Automator), o NodePool Spot general é apropriado — o tratador de interrupção SQS do Karpenter drena nós Spot graciosamente antes que a AWS os reivindique, e a contagem mínima de réplicas do KEDA (≥ 2) garante disponibilidade durante a substituição de nós.
  • Para desabilitar Spot globalmente, remova "spot" da lista de valores em cada NodePool dentro de values/karpenter.yaml.
Como o Karpenter lida com avisos de interrupção Spot: A AWS fornece um aviso de interrupção de 2 minutos antes de terminar uma instância Spot. O Karpenter usa EventBridge e SQS para agir automaticamente:
Evento de Interrupção Spot da AWS


Amazon EventBridge (CloudWatch Events)
  Rule: EC2 Spot Instance Interruption Warning


   Fila SQS (Fila de interrupção do Karpenter)


  Controlador Karpenter (verifica a SQS continuamente)

        ├── Marca o nó como cordoned (nenhum novo pod agendado)
        ├── Drena pods existentes (respeita PodDisruptionBudgets)
        ├── Provisiona um nó de substituição em paralelo
        └── Pods reagendam para o novo nó antes que a janela de 2 minutos feche
Isto é configurado no bloco karpenter em terragrunt.hcl:
karpenter = {
  spot_interruption_handling = true   # cria a fila SQS e a regra EventBridge
  enable_spot_instances       = true   # permite Spot nos requisitos de capacidade do NodePool
}

Passo 5: Atualize os Valores Específicos do Ambiente

Faça uma busca e substituição em todos os arquivos na sua nova pasta de ambiente para os seguintes placeholders:
PlaceholderDescriçãoExemplo
<YOUR_ENV_NAME>Identificador único do ambienteapp-eks-prod
<YOUR_AWS_REGION>Região AWS do clustereu-west-2, us-east-2
<YOUR_AWS_ACCOUNT_ID>ID da conta AWS de 12 dígitos123456789012
<YOUR_ENVIRONMENT>Valor da tag de ambienteprod, staging, dev
<YOUR_PROJECT>Valor da tag de projetoodin, ekb
# Execute a partir da sua nova pasta de ambiente para encontrar todos os placeholders restantes
grep -r "<YOUR_" .

5.1 terragrunt.hcl — Configuração principal do cluster

nano terragrunt.hcl
CampoPlaceholderNotas
cluster_name<YOUR_ENV_NAME>Deve corresponder ao nome do cluster EKS
cluster_region<YOUR_AWS_REGION>Região AWS
aws_account_id<YOUR_AWS_ACCOUNT_ID>ID da conta de 12 dígitos
vpc_cidr<YOUR_VPC_CIDR>por exemplo, 192.168.0.0/16
availability_zones<YOUR_REGION>a/b/c3 AZs na sua região
tags.Environment<YOUR_ENVIRONMENT>por exemplo, prod
tags.Project<YOUR_PROJECT>por exemplo, odin
aws_services.amazon_mq.rabbitmq.username<YOUR_RABBITMQ_USERNAME>Nome de usuário admin do RabbitMQ (apenas quando ENABLE_AWS_SERVICES=true)
aws_services.amazon_mq.rabbitmq.password<YOUR_RABBITMQ_PASSWORD>Mín. 12 caracteres; deve incluir maiúsculas, minúsculas, dígitos e caracteres especiais

5.2 state/terragrunt.hcl — Bucket de estado S3

nano state/terragrunt.hcl
CampoPlaceholderNotas
bucket_nameodin-terraform-state-<YOUR_ENV_NAME>Deve ser globalmente único
region<YOUR_AWS_REGION>Mesma região do cluster

5.3 values/infrastructure.yaml — AWS Load Balancer Controller

Obtenha o ID da VPC após a criação do cluster EKS antes de implantar o AWS Load Balancer Controller.
# Obter o ID da VPC após a criação do cluster EKS
aws eks describe-cluster --name <YOUR_ENV_NAME> \
  --query "cluster.resourcesVpcConfig.vpcId" --output text
nano values/infrastructure.yaml
CampoPlaceholderNotas
clusterName<YOUR_ENV_NAME>Nome do cluster EKS
region<YOUR_AWS_REGION>Região AWS
vpcId<YOUR_VPC_ID>Necessário antes da implantação do ALB
serviceAccount.annotations.eks.amazonaws.com/role-arn<YOUR_AWS_ACCOUNT_ID>, <YOUR_ENV_NAME>Função IAM para o controlador ALB

5.4 values/karpenter-values.yaml — Controlador Karpenter

Obtenha o endpoint do cluster EKS após a criação do cluster EKS e antes de implantar o Karpenter.
# Obter o endpoint do cluster após a criação do cluster EKS
aws eks describe-cluster --name <YOUR_ENV_NAME> \
  --query "cluster.endpoint" --output text
nano values/karpenter-values.yaml
CampoPlaceholderNotas
serviceAccount.annotations.eks.amazonaws.com/role-arn<YOUR_AWS_ACCOUNT_ID>, <YOUR_ENV_NAME>Função IAM para o Karpenter
env.CLUSTER_NAME<YOUR_ENV_NAME>Nome do cluster EKS
env.CLUSTER_ENDPOINT<YOUR_EKS_CLUSTER_ENDPOINT>Necessário antes da implantação do Karpenter
settings.aws.defaultInstanceProfile<YOUR_ENV_NAME>Perfil de instância do nó do Karpenter

5.5 values/karpenter-nodeclasses.yaml — Classes de nós Karpenter

nano values/karpenter-nodeclasses.yaml
CampoPlaceholderNotas
Todas as tags kubernetes.io/cluster/<YOUR_ENV_NAME><YOUR_ENV_NAME>Tag de cluster para seletores de sub-rede/SG
Nome do cluster bootstrap user_data<YOUR_ENV_NAME>Script de bootstrap do nó
tags.Environment<YOUR_ENVIRONMENT>por exemplo, prod
tags.Project<YOUR_PROJECT>por exemplo, odin

5.6 values/aws-ebs-csi-driver.yaml — EBS CSI Driver

nano values/aws-ebs-csi-driver.yaml
CampoPlaceholderNotas
controller.serviceAccount.annotations.eks.amazonaws.com/role-arn<YOUR_AWS_ACCOUNT_ID>, <YOUR_ENV_NAME>Função IAM para o controlador EBS CSI
node.serviceAccount.annotations.eks.amazonaws.com/role-arn<YOUR_AWS_ACCOUNT_ID>, <YOUR_ENV_NAME>Função IAM para o nó EBS CSI
controller.env.AWS_DEFAULT_REGION<YOUR_AWS_REGION>Região AWS
controller.env.AWS_REGION<YOUR_AWS_REGION>Região AWS
node.env.AWS_DEFAULT_REGION<YOUR_AWS_REGION>Região AWS
node.env.AWS_REGION<YOUR_AWS_REGION>Região AWS

5.7 values/karpenter.yaml — Karpenter NodePools

nano values/karpenter.yaml
CampoPlaceholderNotas
*.labels.Environment<YOUR_ENVIRONMENT>Aplicado a todos os rótulos de NodePool
*.requirements topology.kubernetes.io/zone["<YOUR_REGION>a", "<YOUR_REGION>b", "<YOUR_REGION>c"]AZs para todos os NodePools
Os nomes das classes de nós (general, compute-intensive, memory-intensive, gpu, database) devem corresponder às entradas em karpenter-nodeclasses.yaml.

5.8 values/keda.yaml — Escalonador KEDA

Nenhum placeholder específico do ambiente é necessário. Limites de recursos e contagens de réplicas são pré-configurados com padrões sensatos. Revise e ajuste se necessário.

5.9 values/supabase.yaml — Aplicação Supabase (apenas se ENABLE_SUPABASE=true)

Todas as chaves abaixo devem ser geradas consistentemente e compartilhadas com ha-supabase-db.yaml. Gere-as uma vez e use os mesmos valores em ambos os arquivos.
# Gerar segredo JWT
openssl rand -hex 32

# Gerar JWTs de anon/service (requer Supabase CLI)
brew install supabase/tap/supabase
supabase gen-keys

# Gerar senhas e tokens
openssl rand -hex 24       # para senhas
openssl rand -base64 64    # para secretKeyBase
nano values/supabase.yaml
CampoPlaceholderNotas
secret.jwt.anonKey<YOUR_SUPABASE_ANON_KEY>Deve corresponder ao anonKey em ha-supabase-db.yaml
secret.jwt.serviceKey<YOUR_SUPABASE_SERVICE_ROLE_KEY>Deve corresponder ao serviceRoleKey em ha-supabase-db.yaml
secret.jwt.secret<YOUR_SUPABASE_JWT_SECRET>Deve corresponder ao jwtSecret em ha-supabase-db.yaml
secret.db.password<YOUR_SUPABASE_DB_PASSWORD>Deve corresponder ao postgresPassword em ha-supabase-db.yaml
secret.analytics.publicAccessToken<YOUR_SUPABASE_ANALYTICS_PUBLIC_TOKEN>Token interno Logflare
secret.analytics.privateAccessToken<YOUR_SUPABASE_ANALYTICS_PRIVATE_TOKEN>Token interno Logflare
secret.dashboard.username<YOUR_SUPABASE_DASHBOARD_USERNAME>Login da UI Studio
secret.dashboard.password<YOUR_SUPABASE_DASHBOARD_PASSWORD>Login da UI Studio
secret.realtime.secretKeyBase<YOUR_SUPABASE_REALTIME_SECRET_KEY_BASE>Chave secreta Phoenix
secret.meta.cryptoKey<YOUR_SUPABASE_META_CRYPTO_KEY>openssl rand -hex 32
secret.s3.keyId<YOUR_MINIO_KEY_ID>Deve corresponder ao secret.minio.user (openssl rand -hex 16)
secret.s3.accessKey<YOUR_MINIO_ACCESS_KEY>Deve corresponder ao secret.minio.password (openssl rand -hex 32)
secret.minio.user<YOUR_MINIO_KEY_ID>Mesmo valor que secret.s3.keyId
secret.minio.password<YOUR_MINIO_ACCESS_KEY>Mesmo valor que secret.s3.accessKey

5.10 values/ha-supabase-db.yaml — Supabase HA Database (apenas se ENABLE_HA_SUPABASE_DB=true)

Os segredos aqui devem corresponder a supabase.yaml. Use os mesmos valores gerados para postgresPassword, jwtSecret, anonKey e serviceRoleKey.
nano values/ha-supabase-db.yaml
CampoPlaceholderNotas
secrets.inline.postgresPassword<YOUR_SUPABASE_DB_PASSWORD>Deve corresponder ao secret.db.password em supabase.yaml
secrets.inline.authenticatorPassword<YOUR_SUPABASE_DB_PASSWORD>Deve ser idêntico ao postgresPassword
secrets.inline.pgbouncerPassword<YOUR_SUPABASE_DB_PASSWORD>Deve ser idêntico ao postgresPassword
secrets.inline.jwtSecret<YOUR_SUPABASE_JWT_SECRET>Deve corresponder ao secret.jwt.secret em supabase.yaml
secrets.inline.anonKey<YOUR_SUPABASE_ANON_KEY>Deve corresponder ao secret.jwt.anonKey em supabase.yaml
secrets.inline.serviceRoleKey<YOUR_SUPABASE_SERVICE_ROLE_KEY>Deve corresponder ao secret.jwt.serviceKey em supabase.yaml
A classe de armazenamento (ebs-csi-gp2), contagens de instâncias e limites de recursos são pré-configurados. Ajuste postgres.storage.size e postgres.walStorage.size para o volume de dados esperado.

5.11 values/cloudnative-pg.yaml — Operador CloudNativePG (apenas se ENABLE_CNPG=true)

Nenhum placeholder específico do ambiente é necessário. Isto implanta apenas o controlador do operador CNPG. As configurações padrão (3 réplicas, limites de recursos) são adequadas para a maioria dos ambientes.

5.12 values/odin-services.yaml — Serviços de aplicação Odin

Os endpoints Redis e RabbitMQ só estão disponíveis após o Terraform criar esses recursos AWS. Os ARNs de certificado devem ser provisionados no ACM antes da implantação.
nano values/odin-services.yaml
Configurações gerais:
CampoPlaceholderNotas
server<YOUR_WEB_DOMAIN>Domínio web principal
toolkitEncryptionKey<YOUR_TOOLKIT_ENCRYPTION_KEY>Gerar: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
Supabase (dataServiceConfig) — auto-hospedado (ENABLE_SUPABASE=true):
CampoPlaceholderFonte
supabase.projectUrlhttp://supabase-kong:8000Fixo — Supabase Kong interno
supabase.key<YOUR_SUPABASE_SERVICE_ROLE_KEY>Mesmo que secret.jwt.serviceKey em supabase.yaml
supabase.postgres.userpostgresFixo para auto-hospedado
supabase.postgres.hostha-supabase-db-postgres-pooler-rw.ha-supabase-db.svc.cluster.localFixo — Serviço DB Pool dentro do cluster
supabase.postgres.password<YOUR_SUPABASE_DB_PASSWORD>Mesmo que secret.db.password em supabase.yaml
supabase.projectId(deixe vazio)Não usado no modo auto-hospedado
Supabase (dataServiceConfig) — Supabase Cloud (ENABLE_SUPABASE=false):
CampoPlaceholderFonte
supabase.projectUrl<YOUR_SUPABASE_PROJECT_URL>Supabase dashboard → Project Settings → API
supabase.key<YOUR_SUPABASE_SERVICE_ROLE_KEY>Supabase dashboard → API → chave service_role
supabase.postgres.user<YOUR_SUPABASE_DB_USER>Supabase dashboard → Project Settings → Database
supabase.postgres.host<YOUR_SUPABASE_DB_HOST>Supabase dashboard → Database (por exemplo, aws-0-eu-west-2.pooler.supabase.com)
supabase.postgres.password<YOUR_SUPABASE_DB_PASSWORD>Supabase dashboard → Project Settings → Database
supabase.projectId<YOUR_SUPABASE_PROJECT_ID>Da URL do seu projeto Supabase
Redis:
CampoPlaceholderNotas
redis.urlrediss://<YOUR_REDIS_HOST>:6379?ssl_cert_reqs=noneApós o Terraform criar o ElastiCache
redis.host<YOUR_REDIS_HOST>Endpoint primário do ElastiCache
# Obter endpoint do Redis após terraform apply
aws elasticache describe-cache-clusters \
  --show-cache-node-info \
  --query "CacheClusters[?starts_with(CacheClusterId,'<YOUR_ENV_NAME>')].CacheNodes[0].Endpoint.Address" \
  --output text
RabbitMQ:
CampoPlaceholderNotas
rabbitmq.urlamqps://<YOUR_RABBITMQ_USERNAME>:<YOUR_RABBITMQ_PASSWORD>@<YOUR_RABBITMQ_HOST>:5671Após o Terraform criar o AmazonMQ
rabbitmq.host<YOUR_RABBITMQ_HOST>Endpoint do broker AmazonMQ
rabbitmq.username<YOUR_RABBITMQ_USERNAME>Definido em terragrunt.hcl
rabbitmq.password<YOUR_RABBITMQ_PASSWORD>Definido em terragrunt.hcl
# Obter endpoint do RabbitMQ após terraform apply
aws mq list-brokers \
  --query "BrokerSummaries[?BrokerName=='odin-rabbitmq'].BrokerId" --output text | \
  xargs -I{} aws mq describe-broker --broker-id {} \
  --query "BrokerInstances[0].Endpoints[0]" --output text
ARNs de SSL / Certificado:
CampoPlaceholderNotas
ssl.services.web.domain<YOUR_WEB_DOMAIN>por exemplo, app.example.com
ssl.services.web.certificateArn<YOUR_WEB_CERTIFICATE_ARN>ARN do certificado ACM
ssl.services.fastapiBackend.domain<YOUR_API_DOMAIN>por exemplo, api-app.example.com
ssl.services.fastapiBackend.certificateArn<YOUR_API_CERTIFICATE_ARN>ARN do certificado ACM
ssl.services.automator.domain<YOUR_AUTOMATOR_DOMAIN>por exemplo, automations-app.example.com
ssl.services.automator.certificateArn<YOUR_AUTOMATOR_CERTIFICATE_ARN>ARN do certificado ACM
ssl.services.supabase.domain<YOUR_SUPABASE_DOMAIN>por exemplo, supabase-app.example.com
ssl.services.supabase.certificateArn<YOUR_SUPABASE_CERTIFICATE_ARN>ARN do certificado ACM
# Listar certificados ACM na sua região
aws acm list-certificates --region <YOUR_AWS_REGION> \
  --query "CertificateSummaryList[*].[DomainName,CertificateArn]" --output table
Chaves Supabase do frontend web — auto-hospedado (ENABLE_SUPABASE=true):
CampoPlaceholderFonte
web.supabase.urlhttps://<YOUR_SUPABASE_DOMAIN>URL externa roteada via ingress ALB
web.supabase.anonKey<YOUR_SUPABASE_ANON_KEY>Mesmo que secret.jwt.anonKey em supabase.yaml
web.supabase.serviceRoleKey<YOUR_SUPABASE_SERVICE_ROLE_KEY>Mesmo que secret.jwt.serviceKey em supabase.yaml
web.supabase.clientanonKey<YOUR_SUPABASE_SERVICE_ROLE_KEY>Mesmo que secret.jwt.serviceKey em supabase.yaml
Chaves Supabase do frontend web — Supabase Cloud (ENABLE_SUPABASE=false):
CampoPlaceholderFonte
web.supabase.url<YOUR_SUPABASE_PROJECT_URL>Supabase dashboard → Project Settings → API
web.supabase.anonKey<YOUR_SUPABASE_ANON_KEY>Supabase dashboard → API → chave anon
web.supabase.serviceRoleKey<YOUR_SUPABASE_SERVICE_ROLE_KEY>Supabase dashboard → API → chave service_role
web.supabase.clientanonKey<YOUR_SUPABASE_CLIENT_ANON_KEY>Mesmo que a chave service_role

5.13 values/signoz.yaml — Observabilidade SigNoz (apenas se ENABLE_SIGNOZ=true)

nano values/signoz.yaml
CampoPlaceholderNotas
global.clusterName<YOUR_ENV_NAME>Nome do cluster EKS
signoz.ingress.annotations.alb.ingress.kubernetes.io/certificate-arn<YOUR_AWS_REGION>, <YOUR_AWS_ACCOUNT_ID>, <YOUR_SIGNOZ_CERTIFICATE_ID>Certificado ACM para SigNoz
signoz.ingress.hosts[0].host<YOUR_SIGNOZ_DOMAIN>por exemplo, signoz-app.example.com

5.14 values/signoz-k8s-infra.yaml — Métricas SigNoz K8s (apenas se ENABLE_SIGNOZ=true)

nano values/signoz-k8s-infra.yaml
CampoPlaceholderNotas
global.clusterName<YOUR_ENV_NAME>Nome do cluster EKS para rotulagem de métricas
O endpoint do coletor OTel (signoz-otel-collector.monitoring.svc.cluster.local:4317) é pré-configurado assumindo que tanto SigNoz quanto k8s-infra são implantados no namespace monitoring. Nenhuma alteração é necessária, a menos que você use um nome de release personalizado.

Lembrete da Ordem de Implantação

Alguns valores só estão disponíveis após a implantação de certa infraestrutura. Siga esta ordem:
  1. Antes de qualquer implantação — Defina: <YOUR_ENV_NAME>, <YOUR_AWS_REGION>, <YOUR_AWS_ACCOUNT_ID>, <YOUR_ENVIRONMENT>, <YOUR_PROJECT>, <YOUR_VPC_CIDR>, todos os nomes de domínio, todos os ARNs de certificado, todos os valores do Supabase, <YOUR_TOOLKIT_ENCRYPTION_KEY>, nome de usuário/senha do RabbitMQ
  2. Após criação do cluster EKS — Defina: <YOUR_VPC_ID> (infrastructure.yaml), <YOUR_EKS_CLUSTER_ENDPOINT> (karpenter-values.yaml)
  3. Após terraform apply para serviços AWS — Defina: <YOUR_REDIS_HOST>, <YOUR_RABBITMQ_HOST> (odin-services.yaml)

Passo 6: Verifique se Não Há Placeholders Restantes

grep -r "<YOUR_" . --include="*.hcl" --include="*.yaml"
A saída esperada deve estar vazia ou conter apenas referências a recursos prestes a serem criados (VPC, Redis, MQ, EKS). Se houver placeholders restantes, consulte as subseções do Passo 5 acima. Lista de verificação de arquivos:
ArquivoPassoObrigatório
terragrunt.hcl5.1Sempre
state/terragrunt.hcl5.2Sempre
values/infrastructure.yaml5.3Sempre
values/karpenter-values.yaml5.4Sempre
values/karpenter-nodeclasses.yaml5.5Sempre
values/karpenter.yaml5.7Sempre
values/keda.yaml5.8Sempre
values/aws-ebs-csi-driver.yaml5.6Sempre
values/odin-services.yaml5.12Sempre
values/cloudnative-pg.yaml5.11Apenas se ENABLE_CNPG=true
values/ha-supabase-db.yaml5.10Apenas se ENABLE_HA_SUPABASE_DB=true
values/supabase.yaml5.9Apenas se ENABLE_SUPABASE=true
values/signoz.yaml5.13Apenas se ENABLE_SIGNOZ=true
values/signoz-k8s-infra.yaml5.14Apenas se ENABLE_SIGNOZ=true

Fase 1: Configuração do Gerenciamento de Estado

Finalidade: Criação do bucket S3 para o estado do Terraform. O módulo de gerenciamento de estado de cada ambiente cria um bucket S3 com o padrão odin-terraform-state-{nome-do-ambiente}, configura criptografia, versionamento e bloqueio de acesso público, e usa estado local para o próprio módulo de estado (padrão de inicialização).
cd terragrunt/environments/{nome-do-seu-ambiente}/state
terragrunt init
terragrunt plan
terragrunt apply

Fase 2: Implantação da Infraestrutura EKS

Finalidade: Rede principal (VPC, sub-redes, NAT gateway), funções e políticas IAM, cluster EKS e node groups gerenciados.

2.1 Execução Seca — Infraestrutura EKS

Infraestrutura Principal
cd terragrunt/environments/nome-do-seu-ambiente
terragrunt plan -target="aws_vpc.main" \
  -target="aws_internet_gateway.main" \
  -target="aws_subnet.public" \
  -target="aws_subnet.private" \
  -target="aws_eip.nat" \
  -target="aws_nat_gateway.main" \
  -target="aws_route_table.public" \
  -target="aws_route_table.private" \
  -target="aws_route_table_association.public" \
  -target="aws_route_table_association.private"
Funções e Políticas IAM
terragrunt plan -target="aws_iam_role.cluster" \
  -target="aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy" \
  -target="aws_iam_openid_connect_provider.eks" \
  -target="aws_iam_role.node" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEC2ContainerRegistryReadOnly"
Cluster EKS e Node Groups
terragrunt plan -target="aws_eks_cluster.main" \
  -target="aws_eks_node_group.main" \
  -target="kubernetes_secret.regcred"

Usando um Registro Docker Personalizado / Privado

Por padrão, as imagens EKB são puxadas do Docker Hub usando um segredo chamado regcred. Se o cliente hospeda imagens em um registro diferente, siga estes passos antes de implantar odin-services. Passo 1 — Criar o imagePullSecret no namespace alvo
# Registro privado genérico (Docker Hub, Quay, auto-hospedado, etc.)
kubectl create secret docker-registry regcred \
  --namespace default \
  --docker-server=<YOUR_REGISTRY_HOST> \
  --docker-username=<YOUR_REGISTRY_USERNAME> \
  --docker-password=<YOUR_REGISTRY_PASSWORD> \
  --docker-email=<YOUR_EMAIL>

# AWS ECR — o token expira a cada 12h; atualize via CronJob ou use cache pull-through do ECR
aws ecr get-login-password --region <YOUR_AWS_REGION> | \
  kubectl create secret docker-registry regcred \
    --namespace default \
    --docker-server=<YOUR_AWS_ACCOUNT_ID>.dkr.ecr.<YOUR_AWS_REGION>.amazonaws.com \
    --docker-username=AWS \
    --docker-password-stdin
Passo 2 — Definir o nome do segredo em values/odin-services.yaml
# values/odin-services.yaml
imagePullSecrets:
  - name: regcred          # deve corresponder ao nome do segredo criado acima
  # - name: customer-registry-secret  # adicionar registros adicionais se necessário
Passo 3 — Atualizar referências de imagem
web:
  image: <YOUR_REGISTRY_HOST>/<YOUR_ORG>/web:<TAG>

fastapiBackend:
  image: <YOUR_REGISTRY_HOST>/<YOUR_ORG>/server:<TAG>
Passo 4 — Verificar acesso de pull antes da implantação completa
kubectl run registry-test \
  --image=<YOUR_REGISTRY_HOST>/<YOUR_ORG>/web:<TAG> \
  --overrides='{"spec":{"imagePullSecrets":[{"name":"regcred"}]}}' \
  --restart=Never --rm -it -- echo "Pull successful"

2.2 Implantar Infraestrutura EKS

Passo 1: Infraestrutura Principal
cd terragrunt/environments/nome-do-seu-ambiente
terragrunt apply -target="aws_vpc.main" \
  -target="aws_internet_gateway.main" \
  -target="aws_subnet.public" \
  -target="aws_subnet.private" \
  -target="aws_eip.nat" \
  -target="aws_nat_gateway.main" \
  -target="aws_route_table.public" \
  -target="aws_route_table.private" \
  -target="aws_route_table_association.public" \
  -target="aws_route_table_association.private"
Após este passo, atualize o vpcId em values/infrastructure.yaml antes de implantar o AWS Load Balancer Controller.
Passo 2: Cluster EKS e Funções e Políticas IAM
terragrunt apply -target="aws_iam_role.cluster" \
  -target="aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy" \
  -target="aws_iam_openid_connect_provider.eks" \
  -target="aws_iam_role.node" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEC2ContainerRegistryReadOnly"
Passo 3: Node Groups e Add-ons
terragrunt apply -target="aws_eks_cluster.main" \
  -target="aws_eks_node_group.main" \
  -target="kubernetes_secret.regcred"
Após este passo, atualize CLUSTER_ENDPOINT em values/karpenter-values.yaml antes de implantar o Karpenter.
Verificar Conectividade do Cluster EKS
aws eks update-kubeconfig --region $AWS_REGION --name $CLUSTER_NAME

kubectl cluster-info
kubectl get nodes
kubectl get secret regcred -n default

Fase 3: Armazenamento e Balanceamento de Carga

Finalidade: EBS CSI driver para volumes persistentes, AWS Load Balancer Controller rodando no node group gerenciado.

3.1 Execução Seca — Armazenamento e Balanceamento de Carga

EBS CSI Driver
cd terragrunt/environments/nome-do-seu-ambiente
terragrunt plan -target="aws_iam_role.ebs_csi_driver" \
  -target="aws_iam_role_policy_attachment.ebs_csi_driver" \
  -target="helm_release.ebs_csi_driver"
AWS Load Balancer Controller
terragrunt plan -target="aws_iam_role.aws_load_balancer_controller" \
  -target="aws_iam_role_policy_attachment.aws_load_balancer_controller" \
  -target="aws_iam_policy.aws_load_balancer_controller" \
  -target="helm_release.infrastructure"

3.2 Implantar Armazenamento e Balanceamento de Carga

Passo 1: EBS CSI Driver
cd terragrunt/environments/nome-do-seu-ambiente
terragrunt apply -target="aws_iam_role.ebs_csi_driver" \
  -target="aws_iam_role_policy_attachment.ebs_csi_driver" \
  -target="helm_release.ebs_csi_driver"
Verificação
helm list -n kube-system | grep ebs
kubectl get pods -n kube-system | grep ebs-csi
kubectl get storageclass
aws iam get-role --role-name $CLUSTER_NAME-ebs-csi-driver-role --region $AWS_REGION
kubectl get sa -n kube-system | grep ebs-csi
kubectl describe sa ebs-csi-controller-sa -n kube-system
Passo 2: AWS Load Balancer Controller
terragrunt apply -target="aws_iam_role.aws_load_balancer_controller" \
  -target="aws_iam_role_policy_attachment.aws_load_balancer_controller" \
  -target="aws_iam_policy.aws_load_balancer_controller" \
  -target="helm_release.infrastructure"
Verificação
helm list -n infrastructure
kubectl get pods -n infrastructure | grep aws-load-balancer-controller
kubectl get sa -n infrastructure
kubectl describe sa aws-load-balancer-controller -n infrastructure
aws iam get-role --role-name $CLUSTER_NAME-aws-load-balancer-controller --region $AWS_REGION
kubectl logs -n infrastructure -l app.kubernetes.io/name=aws-load-balancer-controller
kubectl get ingressclass

Fase 4: Escalação Automática Karpenter

Finalidade: Funções IAM para Karpenter, tratamento de interrupção Spot, controlador Karpenter e node pools.

4.1 Execução Seca — Karpenter

Recursos IAM do Karpenter
cd terragrunt/environments/nome-do-seu-ambiente
terragrunt plan -target="aws_iam_role.karpenter_controller" \
  -target="aws_iam_policy.karpenter_controller" \
  -target="aws_iam_role_policy_attachment.karpenter_controller" \
  -target="aws_iam_role.karpenter_node" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEC2ContainerRegistryReadOnly" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEBSCSIDriverPolicy" \
  -target="aws_iam_instance_profile.karpenter_node"
Função Vinculada ao Serviço EC2 Spot (se instâncias Spot estiverem habilitadas)
terragrunt plan -target="aws_iam_service_linked_role.ec2_spot[0]"
Interrupção Spot do Karpenter (se habilitada em terragrunt.hcl)
terragrunt plan -target="aws_sqs_queue.karpenter_interruption_queue" \
  -target="aws_sqs_queue_policy.karpenter_interruption_queue" \
  -target="aws_cloudwatch_event_rule.karpenter_interruption" \
  -target="aws_cloudwatch_event_target.karpenter_interruption"
Charts Helm do Karpenter
terragrunt plan -target="helm_release.karpenter"
Karpenter NodePools e EC2NodeClasses
terragrunt plan -target="kubernetes_manifest.karpenter_nodepool" \
  -target="kubernetes_manifest.karpenter_nodeclass" \
  -target="kubernetes_config_map.aws_auth"
Um erro esperado pode aparecer durante o plan: API did not recognize GroupVersionKind from manifest (CRD may not be installed). Isto pode ser ignorado com segurança — o Kubernetes valida recursos contra a API ao vivo durante o plan, antes que os CRDs sejam instalados.

4.2 Implantar Karpenter

Passo 1: Recursos IAM do Karpenter
cd terragrunt/environments/nome-do-seu-ambiente
terragrunt apply -target="aws_iam_role.karpenter_controller" \
  -target="aws_iam_policy.karpenter_controller" \
  -target="aws_iam_role_policy_attachment.karpenter_controller" \
  -target="aws_iam_role.karpenter_node" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEC2ContainerRegistryReadOnly" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEBSCSIDriverPolicy" \
  -target="aws_iam_instance_profile.karpenter_node"
Verificação
aws iam get-role --role-name $CLUSTER_NAME-karpenter-controller --region $AWS_REGION
aws iam get-role --role-name $CLUSTER_NAME-karpenter-node --region $AWS_REGION
aws iam get-instance-profile --instance-profile-name $CLUSTER_NAME-karpenter-node --region $AWS_REGION
aws iam list-attached-role-policies --role-name $CLUSTER_NAME-karpenter-node --region $AWS_REGION
Passo 2: Função Vinculada ao Serviço EC2 Spot (se instâncias Spot estiverem habilitadas)
A função vinculada ao serviço EC2 Spot é por conta (apenas uma por conta AWS) e deve existir antes que o Karpenter possa iniciar instâncias Spot.
Opção A: Deixe o Terraform criá-la (recomendado para novas implantações)
terragrunt apply -target="aws_iam_service_linked_role.ec2_spot[0]"
Opção B: Importar se a função já existir
# Verificar se a função existe
aws iam get-role --role-name AWSServiceRoleForEC2Spot --region $AWS_REGION

# Se não existir, criá-la manualmente
aws iam create-service-linked-role --aws-service-name spot.amazonaws.com --region $AWS_REGION

# Importar para o Terraform (substitua ACCOUNT_ID pelo seu ID de conta AWS de 12 dígitos)
terragrunt import 'aws_iam_service_linked_role.ec2_spot[0]' \
  arn:aws:iam::ACCOUNT_ID:role/aws-service-role/spot.amazonaws.com/AWSServiceRoleForEC2Spot
Passo 3: Interrupção Spot do Karpenter (se habilitada em terragrunt.hcl)
terragrunt apply -target="aws_sqs_queue.karpenter_interruption_queue" \
  -target="aws_sqs_queue_policy.karpenter_interruption_queue" \
  -target="aws_cloudwatch_event_rule.karpenter_interruption" \
  -target="aws_cloudwatch_event_target.karpenter_interruption"
Verificação
aws events describe-rule --name $CLUSTER_NAME-karpenter-interruption --region $AWS_REGION
aws events list-targets-by-rule --rule $CLUSTER_NAME-karpenter-interruption --region $AWS_REGION
aws sqs get-queue-url --queue-name $CLUSTER_NAME-karpenter-interruption-queue --region $AWS_REGION
Passo 4: Chart Helm do Karpenter
terragrunt apply -target="helm_release.karpenter"
Verificação
helm list -n kube-system | grep karpenter
kubectl get pods -n kube-system | grep karpenter
kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter
kubectl describe sa karpenter -n kube-system
Passo 5: Manifestos Kubernetes do Karpenter
terragrunt apply -target="kubernetes_manifest.karpenter_nodepool" \
  -target="kubernetes_manifest.karpenter_nodeclass"

# Importar o ConfigMap aws-auth existente
# Nota: Use aspas para evitar que o zsh interprete colchetes como padrões glob
terragrunt import 'kubernetes_config_map.aws_auth[0]' kube-system/aws-auth

# Em seguida, aplique
terragrunt apply -target='kubernetes_config_map.aws_auth[0]'
Verificação
kubectl get nodepools -o wide
kubectl describe nodepool general
kubectl describe nodepool application
kubectl describe nodepool database
kubectl get ec2nodeclasses -o wide
kubectl get configmap aws-auth -n kube-system -o jsonpath='{.data.mapRoles}' | grep karpenter-node
kubectl get nodepools -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}'
kubectl get nodes -l karpenter.sh/nodepool --show-labels
kubectl get events -n kube-system --field-selector involvedObject.name=karpenter --sort-by='.lastTimestamp'

Fase 5: Escalação Automática KEDA

Finalidade: KEDA para escalação automática em nível de aplicação.

5.1 Execução Seca — KEDA

cd terragrunt/environments/nome-do-seu-ambiente
terragrunt plan -target="helm_release.keda"

5.2 Implantar KEDA

cd terragrunt/environments/nome-do-seu-ambiente
terragrunt apply -target="helm_release.keda"
Verificação
helm list -n keda
kubectl get pods -n keda
kubectl get deployment -n keda
kubectl get crd | grep keda
kubectl get validatingwebhookconfigurations | grep keda
kubectl get svc -n keda

Fase 6: Serviços de Dados

Finalidade: Supabase (banco de dados), ElastiCache (Redis), RabbitMQ (fila de mensagens).
Implante primeiro o operador CloudNativePG, depois o cluster HA Supabase DB, e então a aplicação Supabase. O cluster DB deve estar pronto antes que o Supabase inicie.

6.1 Execução Seca — Serviços de Dados

Passo 1: Operador CloudNativePG (se habilitado)
cd terragrunt/environments/nome-do-seu-ambiente
ENABLE_CNPG=true terragrunt plan \
  --target='helm_release.additional_charts["cloudnative-pg"]'
Passo 2: HA Supabase DB (se habilitado)
ENABLE_HA_SUPABASE_DB=true terragrunt plan \
  --target='helm_release.additional_charts["ha-supabase-db"]'
Passo 3: Aplicação Supabase (se habilitada)
if [ "${ENABLE_SUPABASE:-false}" = "true" ]; then
  ENABLE_SUPABASE=true terragrunt plan \
    --target='helm_release.supabase[0]'
fi
Passo 4: Serviços AWS — ElastiCache e RabbitMQ (se habilitados)
if [ "${ENABLE_AWS_SERVICES:-false}" = "true" ]; then
  terragrunt plan -target="aws_elasticache_subnet_group.redis" \
    -target="aws_security_group.redis" \
    -target="aws_elasticache_replication_group.redis" \
    -target="aws_security_group.rabbitmq" \
    -target="aws_mq_broker.rabbitmq"
fi

6.2 Implantar Serviços de Dados

Passo 1: Operador CloudNativePG (se habilitado)
cd terragrunt/environments/nome-do-seu-ambiente
ENABLE_CNPG=true terragrunt apply --auto-approve \
  --target='helm_release.additional_charts["cloudnative-pg"]'
Passo 2: HA Supabase DB (se habilitado)
ENABLE_HA_SUPABASE_DB=true terragrunt apply --auto-approve \
  --target='helm_release.additional_charts["ha-supabase-db"]'
Verificar o pooler PgBouncer e credenciais após a implantação:
kubectl get svc -n ha-supabase-db | grep pooler
kubectl get secrets -n ha-supabase-db
kubectl get secret ha-supabase-db-authenticator-credentials -n ha-supabase-db \
  -o jsonpath='{.data.username}' | base64 -d && echo ""
Use o ClusterIP do pooler (ou EXTERNAL-IP se LoadBalancer) como valor de SUPABASE_POSTGRES_HOST em values/odin-services.yaml e como secret.db.postgresHost em values/supabase.yaml. Passo 3: Aplicação Supabase (se habilitada) Todos os pods do serviço Supabase rodam exclusivamente no NodePool application do Karpenter (apenas On-Demand) para prevenir interrupções Spot.
if [ "${ENABLE_SUPABASE:-false}" = "true" ]; then
  ENABLE_SUPABASE=true terragrunt apply --auto-approve \
    --target='helm_release.supabase[0]'
fi
Passo 4: Serviços AWS — ElastiCache e RabbitMQ (se habilitados)
if [ "${ENABLE_AWS_SERVICES:-false}" = "true" ]; then
  terragrunt apply \
    -target="aws_elasticache_subnet_group.redis" \
    -target="aws_security_group.redis" \
    -target="aws_elasticache_replication_group.redis" \
    -target="aws_security_group.rabbitmq" \
    -target="aws_mq_broker.rabbitmq"
fi
Verificação
# Obter detalhes de conexão das saídas do Terraform
terragrunt output elasticache_endpoint
terragrunt output elasticache_port
terragrunt output rabbitmq_endpoint
terragrunt output rabbitmq_port

# Testar conectividade Redis a partir do cluster EKS
kubectl run redis-test --image=redis:7-alpine --restart=Never -- \
  sh -c "redis-cli -h <redis-endpoint> -p 6379 --tls --insecure ping && echo 'Redis connection successful'"
kubectl logs redis-test
kubectl delete pod redis-test

# Verificar status de criptografia do Redis
aws elasticache describe-replication-groups \
  --replication-group-id $CLUSTER_NAME-redis \
  --region $AWS_REGION \
  --query 'ReplicationGroups[0].{AtRestEncryption:AtRestEncryptionEnabled,TransitEncryption:TransitEncryptionEnabled}'
Antes de implantar os Serviços Odin, atualize values/odin-services.yaml com o endpoint Redis, endpoint RabbitMQ e todos os ARNs de certificado obtidos nesta fase.

Fase 7: Serviços Odin

Finalidade: Implantação de aplicação via Helm.
Antes de implantar, reduza temporariamente o fastapiBackend para uma única réplica para a execução inicial de migração do banco de dados — defina replicaCount: 1, workers: 1 e keda.minReplicas: 1. Uma vez que a migração seja concluída com sucesso, reverta esses valores para seus padrões de produção antes de reimplementar.

7.1 Execução Seca — Serviços Odin

cd terragrunt/environments/nome-do-seu-ambiente
terragrunt plan -target="helm_release.odin_services"

7.2 Implantar Serviços Odin

cd terragrunt/environments/nome-do-seu-ambiente
terragrunt apply -target="helm_release.odin_services"
Verificação
kubectl get pods
kubectl get ingress  # Adicione os endpoints ALB ao seu provedor DNS

Fase 8: Observabilidade SigNoz

Finalidade: Monitoramento de logs e métricas.

8.1 Execução Seca — Charts SigNoz

cd terragrunt/environments/nome-do-seu-ambiente
terragrunt plan -target='helm_release.additional_charts["signoz"]'
terragrunt plan -target='helm_release.additional_charts["k8s-infra"]'

8.2 Implantar Charts SigNoz

cd terragrunt/environments/nome-do-seu-ambiente
terragrunt apply -target='helm_release.additional_charts["signoz"]'
terragrunt apply -target='helm_release.additional_charts["k8s-infra"]'
Verificação
kubectl get pods -n monitoring
kubectl get ingress -n monitoring  # Adicione os endpoints ALB ao seu provedor DNS

Fase 9: Implantação Final

9.1 Implantação Completa

cd terragrunt/environments/nome-do-seu-ambiente
terragrunt apply
Este apply final lida com quaisquer recursos restantes não direcionados explicitamente nas fases anteriores.

9.2 Verificar Implantação

# Atualizar kubeconfig
aws eks update-kubeconfig --region us-east-2 --name nome-do-seu-ambiente

# Verificar status do cluster
kubectl get nodes
kubectl get pods --all-namespaces

# Verificar Karpenter
kubectl get pods -n kube-system -l app.kubernetes.io/name=karpenter
kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter

# Verificar AWS Load Balancer Controller
kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller

# Verificar KEDA
kubectl get pods -n keda

# Verificar Serviços Odin
kubectl get pods -n default
kubectl get services -n default
kubectl get ingress -n default

# Verificar todas as releases Helm
helm list --all-namespaces

Solução de Problemas

Problemas de lock de estado
terragrunt force-unlock <lock-id>
Karpenter não funciona
kubectl describe nodes
kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter
Problemas com balanceador de carga
kubectl describe ingress -n default
kubectl logs -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller
Problemas com charts Helm
helm status <release-name> -n <namespace>
helm rollback <release-name> <revision> -n <namespace>

Limpeza

# Destruir infraestrutura
cd terragrunt/environments/nome-do-seu-ambiente
terragrunt destroy -auto-approve

# Destruir bucket de estado (use com cuidado)
cd terragrunt/environments/nome-do-seu-ambiente/state
terragrunt destroy -auto-approve

Monitoramento e Logging

# Recursos AWS
aws eks describe-cluster --name nome-do-seu-ambiente --region us-east-2
aws ec2 describe-instances --filters "Name=tag:kubernetes.io/cluster/nome-do-seu-ambiente,Values=owned"

# Recursos Kubernetes
kubectl top nodes
kubectl top pods --all-namespaces
kubectl get events --sort-by=.metadata.creationTimestamp

Referência Rápida — Todos os Comandos de Implantação

# Fase 1: Gerenciamento de Estado
cd terragrunt/environments/nome-do-seu-ambiente/state
terragrunt apply

# Fase 2: Infraestrutura EKS
cd terragrunt/environments/nome-do-seu-ambiente

terragrunt apply -target="aws_vpc.main" -target="aws_internet_gateway.main" \
  -target="aws_subnet.public" -target="aws_subnet.private" -target="aws_eip.nat" \
  -target="aws_nat_gateway.main" -target="aws_route_table.public" \
  -target="aws_route_table.private" -target="aws_route_table_association.public" \
  -target="aws_route_table_association.private" -auto-approve

terragrunt apply -target="aws_iam_role.cluster" \
  -target="aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy" \
  -target="aws_iam_openid_connect_provider.eks" -target="aws_iam_role.node" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEC2ContainerRegistryReadOnly" \
  -auto-approve

terragrunt apply -target="aws_eks_cluster.main" \
  -target="aws_eks_node_group.main" -target="kubernetes_secret.regcred" -auto-approve

# Fase 3: Armazenamento e Balanceamento de Carga
terragrunt apply -target="aws_iam_role.ebs_csi_driver" \
  -target="aws_iam_role_policy_attachment.ebs_csi_driver" \
  -target="helm_release.ebs_csi_driver" -auto-approve

terragrunt apply -target="aws_iam_role.aws_load_balancer_controller" \
  -target="aws_iam_role_policy_attachment.aws_load_balancer_controller" \
  -target="aws_iam_policy.aws_load_balancer_controller" \
  -target="helm_release.infrastructure" -auto-approve

# Fase 4: Escalação Automática Karpenter
terragrunt apply -target="aws_iam_role.karpenter_controller" \
  -target="aws_iam_policy.karpenter_controller" \
  -target="aws_iam_role_policy_attachment.karpenter_controller" \
  -target="aws_iam_role.karpenter_node" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEC2ContainerRegistryReadOnly" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEBSCSIDriverPolicy" \
  -target="aws_iam_instance_profile.karpenter_node" -auto-approve

# Tratamento de interrupção Spot (se spot_interruption_handling = true)
terragrunt apply -target="aws_sqs_queue.karpenter_interruption_queue" \
  -target="aws_sqs_queue_policy.karpenter_interruption_queue" \
  -target="aws_cloudwatch_event_rule.karpenter_interruption" \
  -target="aws_cloudwatch_event_target.karpenter_interruption" -auto-approve

terragrunt apply -target="helm_release.karpenter" -auto-approve

terragrunt apply -target="kubernetes_manifest.karpenter_nodepool" \
  -target="kubernetes_manifest.karpenter_nodeclass" \
  -target='kubernetes_config_map.aws_auth[0]' -auto-approve

# Fase 5: Escalação Automática KEDA
terragrunt apply -target="helm_release.keda" -auto-approve

# Fase 6: Serviços de Dados
ENABLE_CNPG=true terragrunt apply --target='helm_release.additional_charts["cloudnative-pg"]' -auto-approve
ENABLE_HA_SUPABASE_DB=true terragrunt apply --target='helm_release.additional_charts["ha-supabase-db"]' -auto-approve

if [ "${ENABLE_SUPABASE:-false}" = "true" ]; then
  ENABLE_SUPABASE=true terragrunt apply --target='helm_release.supabase[0]' -auto-approve
fi

if [ "${ENABLE_AWS_SERVICES:-false}" = "true" ]; then
  terragrunt apply -target="aws_elasticache_subnet_group.redis" \
    -target="aws_security_group.redis" \
    -target="aws_elasticache_replication_group.redis" \
    -target="aws_security_group.rabbitmq" \
    -target="aws_mq_broker.rabbitmq" -auto-approve
fi

# Fase 7: Serviços Odin
terragrunt apply -target="helm_release.odin_services" -auto-approve

# Fase 8: SigNoz (se habilitado)
terragrunt apply -target='helm_release.additional_charts["signoz"]' -auto-approve
terragrunt apply -target='helm_release.additional_charts["k8s-infra"]' -auto-approve

# Fase 9: Implantação Final
terragrunt apply -auto-approve
Substitua nome-do-seu-ambiente pelo nome do seu ambiente real ao longo de todo o processo. Sempre execute execuções secas (terragrunt plan) primeiro para validar sua configuração antes de aplicar alterações.