Pular para o conteúdo principal

RDS Instance - Banco de Dados Relacional

Crie e gerencie bancos de dados relacionais totalmente gerenciados e escaláveis na AWS com PostgreSQL, MySQL, MariaDB, SQL Server ou Oracle.

Pré-requisito: Configuração do AWSProvider

Antes de criar qualquer recurso AWS, você precisa configurar um AWSProvider que gerencia credenciais e autenticação com a AWS.

IRSA:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: AWSProvider
metadata:
name: production-aws
namespace: default
spec:
region: us-east-1
roleARN: arn:aws:iam::123456789012:role/infra-operator-role
defaultTags:
managed-by: infra-operator
environment: production

Credenciais Estáticas:

apiVersion: v1
kind: Secret
metadata:
name: aws-credentials
namespace: default
type: Opaque
stringData:
access-key-id: test
secret-access-key: test
---
apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: AWSProvider
metadata:
name: localstack
namespace: default
spec:
region: us-east-1
accessKeyIDRef:
name: aws-credentials
key: access-key-id
secretAccessKeyRef:
name: aws-credentials
key: secret-access-key
defaultTags:
managed-by: infra-operator
environment: test

Verificar Status:

kubectl get awsprovider
kubectl describe awsprovider production-aws
aviso

Para produção, sempre use IRSA (IAM Roles for Service Accounts) ao invés de credenciais estáticas.

Criar Role IAM para IRSA

Para usar IRSA em produção, você precisa criar uma Role IAM com as permissões necessárias:

Trust Policy (trust-policy.json):

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:infra-operator-system:infra-operator-controller-manager",
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com"
}
}
}
]
}

IAM Policy - RDS (rds-policy.json):

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"rds:CreateDBInstance",
"rds:DeleteDBInstance",
"rds:DescribeDBInstances",
"rds:ModifyDBInstance",
"rds:StartDBInstance",
"rds:StopDBInstance",
"rds:CreateDBSnapshot",
"rds:DeleteDBSnapshot",
"rds:AddTagsToResource",
"rds:RemoveTagsFromResource",
"rds:ListTagsForResource",
"rds:CreateDBParameterGroup",
"rds:ModifyDBParameterGroup"
],
"Resource": "*"
}
]
}

Criar Role com AWS CLI:

# 1. Obter OIDC Provider do cluster EKS
export CLUSTER_NAME=my-cluster
export AWS_REGION=us-east-1
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

OIDC_PROVIDER=$(aws eks describe-cluster \
--name $CLUSTER_NAME \
--region $AWS_REGION \
--query "cluster.identity.oidc.issuer" \
--output text | sed -e "s/^https:\/\///")

# 2. Atualizar trust-policy.json com valores corretos
cat > trust-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OIDC_PROVIDER}:sub": "system:serviceaccount:infra-operator-system:infra-operator-controller-manager",
"${OIDC_PROVIDER}:aud": "sts.amazonaws.com"
}
}
}
]
}
EOF

# 3. Criar IAM Role
aws iam create-role \
--role-name infra-operator-rds-role \
--assume-role-policy-document file://trust-policy.json \
--description "Role for Infra Operator RDS management"

# 4. Criar e anexar policy
aws iam put-role-policy \
--role-name infra-operator-rds-role \
--policy-name RDSManagement \
--policy-document file://rds-policy.json

# 5. Obter Role ARN
aws iam get-role \
--role-name infra-operator-rds-role \
--query 'Role.Arn' \
--output text

Anotar ServiceAccount do Operator:

# Adicionar annotation ao ServiceAccount do operator
kubectl annotate serviceaccount infra-operator-controller-manager \
-n infra-operator-system \
eks.amazonaws.com/role-arn=arn:aws:iam::123456789012:role/infra-operator-rds-role
observação

Substitua 123456789012 pelo seu AWS Account ID e EXAMPLED539D4633E53DE1B71EXAMPLE pelo seu OIDC provider ID.

Visão Geral

Amazon RDS (Relational Database Service) é um serviço de banco de dados relacional totalmente gerenciado que oferece:

Recursos:

  • Totalmente Gerenciado: A AWS gerencia backups, patches, replicação e failover
  • Alta Disponibilidade: Multi-AZ automático com failover em minutos
  • Múltiplos Engines: PostgreSQL, MySQL, MariaDB, SQL Server, Oracle
  • Escalabilidade: Aumente ou diminua a capacidade conforme necessário
  • Backups Automatizados: Retenção configurável (até 35 dias)
  • Point-in-Time Recovery (PITR): Restaure para qualquer ponto nos últimos 35 dias
  • Criptografia em Repouso: AES-256 com AWS KMS
  • Criptografia em Trânsito: SSL/TLS automático
  • Performance Insights: Monitore e otimize performance
  • Enhanced Monitoring: Métricas detalhadas de OS, IO, CPU
  • Read Replicas: Replicação de leitura entre regiões (síncrona ou assíncrona)
  • Patching Automatizado: Janelas de manutenção configuráveis
  • Parameter Groups: Configuração customizada do banco de dados
  • Security Groups: Controle de acesso em nível de rede

Status: ⚠️ Requer LocalStack Pro ou AWS Real

Início Rápido

RDS PostgreSQL:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: RDSInstance
metadata:
name: e2e-postgres-db
namespace: default
spec:
providerRef:
name: localstack

# Identificador único do banco de dados
dbInstanceIdentifier: e2e-test-postgres

# Database engine
engine: postgres
engineVersion: "14.7"

# Instance class
dbInstanceClass: db.t3.micro

# Storage
allocatedStorage: 20

# Credenciais do administrador
masterUsername: dbadmin
masterUserPassword: Test123456!

# Nome do banco de dados inicial
dbName: testdb
port: 5432

# Configuração
multiAZ: false
publiclyAccessible: true
storageEncrypted: true

# Backups
backupRetentionPeriod: 7
preferredBackupWindow: "03:00-04:00"

# Tags
tags:
Environment: test
ManagedBy: infra-operator
Database: postgres

deletionPolicy: Delete

RDS MySQL:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: RDSInstance
metadata:
name: e2e-mysql-db
namespace: default
spec:
providerRef:
name: localstack

# Identificador único
dbInstanceIdentifier: e2e-test-mysql

# MySQL engine
engine: mysql
engineVersion: "8.0.33"

# Instance class
dbInstanceClass: db.t3.small

# Storage
allocatedStorage: 30

# Credenciais
masterUsername: admin
masterUserPassword: MyPassword123!

# Banco de dados inicial
dbName: mydb
port: 3306

# Multi-AZ habilitado
multiAZ: true
publiclyAccessible: false
storageEncrypted: true

# Backups
backupRetentionPeriod: 14

# Tags
tags:
Environment: test
ManagedBy: infra-operator
Database: mysql

deletionPolicy: Delete

RDS PostgreSQL Produção:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: RDSInstance
metadata:
name: app-database
namespace: default
spec:
providerRef:
name: production-aws

# Identificador único do banco de dados (2-63 caracteres)
dbInstanceIdentifier: app-db-prod

# Database engine
engine: postgres
engineVersion: "15.4"

# Instance class (capacidade)
dbInstanceClass: db.t3.micro

# Storage
allocatedStorage: 20
storageType: gp3
iops: 3000

# Credenciais do administrador
masterUsername: postgres
masterUserPasswordSecretRef:
name: db-password
key: password

# Multi-AZ para alta disponibilidade
multiAZ: true

# VPC e segurança
dbSubnetGroupName: private-subnet-group
vpcSecurityGroupRefs:
- name: db-sg

# Backups
backupRetentionPeriod: 7
preferredBackupWindow: "03:00-04:00"
preferredMaintenanceWindow: "sun:04:00-sun:05:00"

# Proteção contra deleção
deletionProtection: true

# Tagging
tags:
Environment: production
Application: web-app

deletionPolicy: Retain

Aplicar:

kubectl apply -f rds.yaml

Verificar Status:

kubectl get rdsinstances
kubectl describe rdsinstance e2e-postgres-db
kubectl get rdsinstance e2e-postgres-db -o yaml

Referência de Configuração

Campos Obrigatórios

Referência ao recurso AWSProvider para autenticação

Nome do recurso AWSProvider

Identificador único para a instância RDS (2 a 63 caracteres)

Regras:

  • Apenas caracteres alfanuméricos e hífens
  • Não pode começar ou terminar com hífen
  • Deve ser único por região
  • Não pode ser modificado após criação

Exemplo:

dbInstanceIdentifier: myapp-db-prod

Database engine

Opções:

  • postgres - PostgreSQL
  • mysql - MySQL
  • mariadb - MariaDB
  • sqlserver-ex - SQL Server Express
  • sqlserver-se - SQL Server Standard
  • sqlserver-ee - SQL Server Enterprise
  • oracle-se2 - Oracle Standard Edition 2
  • oracle-ee - Oracle Enterprise Edition

Exemplo:

engine: postgres

Versão do database engine

Exemplos:

  • PostgreSQL: 15.4, 14.9, 13.13
  • MySQL: 8.0.35, 8.0.34, 5.7.44
  • MariaDB: 10.6.14, 10.5.21, 10.4.32

Exemplo:

engineVersion: "15.4"

Nota: Sempre especifique versões com patch (ex: 15.4, não 15)

Instance class (CPU, RAM, performance)

Família db.t3 (Burstable - Dev/Test):

  • db.t3.micro - 1 vCPU, 1 GB RAM (~$0.017/hora)
  • db.t3.small - 1 vCPU, 2 GB RAM (~$0.034/hora)
  • db.t3.medium - 1 vCPU, 4 GB RAM (~$0.068/hora)

Família db.t4g (Graviton - mais barato):

  • db.t4g.micro - 1 vCPU, 1 GB RAM
  • db.t4g.small - 1 vCPU, 2 GB RAM

Família db.m5 (General Purpose):

  • db.m5.large - 2 vCPU, 8 GB RAM (~$0.175/hora)
  • db.m5.xlarge - 4 vCPU, 16 GB RAM (~$0.350/hora)
  • db.m5.2xlarge - 8 vCPU, 32 GB RAM (~$0.700/hora)

Família db.r5 (Memory Optimized - Cache/Analytics):

  • db.r5.large - 2 vCPU, 16 GB RAM (~$0.280/hora)
  • db.r5.xlarge - 4 vCPU, 32 GB RAM (~$0.560/hora)

Exemplo:

dbInstanceClass: db.t3.micro

Espaço de armazenamento alocado em GB

Range: 20 - 65,536 GB (depende do engine)

Tipos de armazenamento:

  • gp2 (General Purpose): 20-65,536 GB (padrão)
  • gp3 (General Purpose v3): 20-65,536 GB (recomendado, melhor performance)
  • io1 (Provisioned IOPS): 100-65,536 GB (alta performance)
  • io2 (Provisioned IOPS v2): 100-65,536 GB (máxima performance)

Exemplo:

allocatedStorage: 20
storageType: gp3

Nota: Você pode aumentar o tamanho depois, mas não pode diminuir

Nome de usuário do administrador do banco de dados

Regras:

  • 1 a 16 caracteres (depende do engine)
  • Apenas alfanuméricos
  • Não pode ser admin, root, postgres (alguns engines)
  • Não pode começar com número

Exemplo:

masterUsername: dbadmin

Referência ao Secret do Kubernetes contendo a senha

Nome do Secret do Kubernetes

Chave dentro do Secret

Exemplo de Secret:

apiVersion: v1
kind: Secret
metadata:
name: db-password
namespace: default
type: Opaque
stringData:
password: SuperSecurePassword123!

Regras de Senha:

  • Mínimo 8 caracteres
  • Contém: letras, números, símbolos especiais
  • Não pode conter @, /, ", ou \

Campos Opcionais - Storage

Tipo de armazenamento EBS

Opções:

  • gp2: General Purpose SSD (padrão, bom para a maioria)
  • gp3: General Purpose SSD v3 (recomendado, melhor performance)
  • io1: Provisioned IOPS SSD (performance previsível)
  • io2: Provisioned IOPS SSD v2 (máxima performance)

Exemplo:

storageType: gp3

IOPS provisionados (apenas io1/io2)

Range: 1,000 - 64,000 IOPS

Nota: Para gp3, IOPS é configurado separadamente do tamanho:

storageType: io1
allocatedStorage: 100
iops: 5000

Throughput de armazenamento para gp3 (MB/s)

Range: 125 - 1,000 MB/s:

storageType: gp3
storageThroughput: 500

Campos Opcionais - Rede e Segurança

Nome do DB Subnet Group (subnets privadas)

Importante: DEVE existir previamente na AWS:

dbSubnetGroupName: private-subnet-group

Criar subnet group via AWS CLI:

aws rds create-db-subnet-group \
--db-subnet-group-name private-subnet-group \
--db-subnet-group-description "Private subnets for RDS" \
--subnet-ids subnet-xxx subnet-yyy

Referências aos Security Groups do Kubernetes para controle de acesso

Nome do recurso SecurityGroup no Kubernetes

Exemplo:

  vpcSecurityGroupRefs:
- name: rds-security-group

Alternativa - usar IDs diretos:

vpcSecurityGroupIds:
- sg-0123456789abcdef0
- sg-0123456789abcdef1

Se o banco de dados é acessível via internet pública

⚠️ Segurança: Nunca habilite em produção!:

publiclyAccessible: false  # Manter privado

Protege contra deleção acidental

Recomendado: true em produção:

deletionProtection: true

Campos Opcionais - Backups e Recuperação

Dias de retenção de backup automatizado

Range: 1 - 35 dias

Recomendações:

  • Desenvolvimento: 1-7 dias
  • Staging: 7-14 dias
  • Produção: 14-35 dias

Exemplo:

backupRetentionPeriod: 30

Custo: Aumenta com a retenção

Janela diária de backup (UTC, formato HH:MM-HH:MM)

Padrão: Selecionado automaticamente:

preferredBackupWindow: "03:00-04:00"  # 3AM-4AM UTC

Dica: Escolha horário de baixo uso

Janela semanal de manutenção para patches (formato: ddd:HH:MM-ddd:HH:MM)

Padrão: Selecionado automaticamente:

preferredMaintenanceWindow: "sun:04:00-sun:05:00"
# Domingo, 4AM-5AM UTC

Dias válidos: mon, tue, wed, thu, fri, sat, sun

Pular criação de snapshot final ao deletar banco de dados

Cuidado: true pode perder dados!:

skipFinalSnapshot: false  # Sempre criar snapshot final

Identificador do snapshot final ao deletar

Exemplo:

finalDBSnapshotIdentifier: app-db-final-snapshot-2025-11-22

Campos Opcionais - Alta Disponibilidade e Replicação

Habilitar Multi-AZ (alta disponibilidade)

Benefícios:

  • Failover automático em caso de falha (minutos)
  • Replicação síncrona para integridade de dados
  • ~50% de aumento de custo

Recomendado: true em produção:

multiAZ: true

Usar IAM para autenticação (ao invés de senha)

Exemplo:

enableIAMDatabaseAuthentication: true

Benefícios:

  • Sem senha hardcoded
  • Tokens temporários
  • Auditoria automática

Campos Opcionais - Criptografia

Habilitar criptografia em repouso

Padrão: true (recomendado):

storageEncrypted: true

ARN da chave KMS da AWS para criptografia

Padrão: Chave gerenciada pela AWS (sem custo):

storageEncrypted: true
kmsKeyId: arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012

Campos Opcionais - Monitoramento e Otimização

Habilitar Performance Insights (análise detalhada)

Exemplo:

enablePerformanceInsights: true

Custo: ~$0.02/hora adicional

Habilitar Enhanced Monitoring (métricas do OS)

Exemplo:

enableEnhancedMonitoring: true
monitoringInterval: 60 # A cada 60 segundos

Custo: Baseado no intervalo

Intervalo do Enhanced Monitoring (segundos)

Opções: 0 (desabilitado), 1, 5, 10, 15, 30, 60:

monitoringInterval: 60

Campos Opcionais - Outros

Pares chave-valor para organização e billing

Exemplo:

tags:
Environment: production
Application: web-app
Team: backend
CostCenter: engineering
ManagedBy: infra-operator

O que acontece com a instância quando o CR é deletado

Opções:

  • Delete: Instância é deletada da AWS
  • Retain: Instância permanece na AWS mas não gerenciada
  • Orphan: Remove apenas gerenciamento

Exemplo:

deletionPolicy: Retain  # Para produção

Campos de Status

Após a instância ser criada, os seguintes campos de status são populados:

ARN completo da instância RDS

arn:aws:rds:us-east-1:123456789012:db:app-db-prod

Informações de conexão do banco de dados

Hostname do banco de dados para conexão

  ```
app-db-prod.c9akciq32.us-east-1.rds.amazonaws.com
```

Porta de conexão (padrão: 5432 PostgreSQL, 3306 MySQL)

Estado atual da instância

Valores possíveis:

  • creating - Criando
  • available - Disponível e pronto
  • deleting - Sendo deletado
  • modifying - Configuração sendo alterada
  • backing-up - Backup em andamento
  • maintenance - Manutenção programada
  • failed - Erro na criação

Espaço alocado em GB

Versão do engine em execução

Se Multi-AZ está habilitado

true quando a instância está available e pronta

Timestamp da última sincronização com AWS

Exemplos

PostgreSQL RDS de Produção com Multi-AZ

Banco de dados para aplicação web com alta disponibilidade:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: RDSInstance
metadata:
name: production-postgres
namespace: default
spec:
providerRef:
name: production-aws

# Identificação
dbInstanceIdentifier: myapp-db-prod
engine: postgres
engineVersion: "15.4"

# Classe e storage
dbInstanceClass: db.t3.small
allocatedStorage: 50
storageType: gp3
iops: 3000
storageThroughput: 250

# Credenciais
masterUsername: postgres
masterUserPasswordSecretRef:
name: db-password
key: password

# Rede
dbSubnetGroupName: private-subnet-group
vpcSecurityGroupRefs:
- name: rds-security-group
publiclyAccessible: false

# Alta Disponibilidade
multiAZ: true
deletionProtection: true

# Backups
backupRetentionPeriod: 30
preferredBackupWindow: "03:00-04:00"
preferredMaintenanceWindow: "sun:04:00-sun:05:00"

# Monitoramento
enablePerformanceInsights: true

# Segurança
storageEncrypted: true

# Tags
tags:
Environment: production
Application: myapp
Team: backend
CostCenter: engineering

deletionPolicy: Retain

RDS MySQL para Desenvolvimento

Banco de dados simples para desenvolvimento local:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: RDSInstance
metadata:
name: dev-mysql
namespace: default
spec:
providerRef:
name: dev-aws

dbInstanceIdentifier: myapp-db-dev

engine: mysql
engineVersion: "8.0.35"

# Instância pequena para dev
dbInstanceClass: db.t3.micro
allocatedStorage: 20
storageType: gp3

masterUsername: admin
masterUserPasswordSecretRef:
name: dev-db-password
key: password

# Dev não precisa de Multi-AZ
multiAZ: false
deletionProtection: false

# Backups menos frequentes
backupRetentionPeriod: 7

tags:
Environment: development
Application: myapp

deletionPolicy: Delete

RDS com Read Replica

Banco de dados primário com replicação de leitura para analytics:

# Banco de dados primário
apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: RDSInstance
metadata:
name: primary-db
namespace: default
spec:
providerRef:
name: production-aws

dbInstanceIdentifier: myapp-db-primary
engine: postgres
engineVersion: "15.4"

dbInstanceClass: db.m5.large
allocatedStorage: 100
storageType: gp3

masterUsername: postgres
masterUserPasswordSecretRef:
name: db-password
key: password

multiAZ: true
backupRetentionPeriod: 35

# Habilitar backups (necessário para réplicas)
backupRetentionPeriod: 7

tags:
Environment: production
Role: primary

deletionPolicy: Retain

---
# Read Replica (para analytics/reporting)
apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: RDSInstance
metadata:
name: read-replica-db
namespace: default
spec:
providerRef:
name: production-aws

dbInstanceIdentifier: myapp-db-read-replica

# Criar a partir do banco de dados primário
replicateSourceDb: myapp-db-primary

# Mesmo engine, pode ser classe menor
dbInstanceClass: db.t3.small

# Não precisa configurar senha (herda do primário)
# Réplica em AZ diferente para HA
availabilityZone: us-east-1b

tags:
Environment: production
Role: read-replica

deletionPolicy: Delete

RDS com Criptografia e PITR Completo

Banco de dados crítico com máxima segurança e recuperação:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: RDSInstance
metadata:
name: critical-database
namespace: default
spec:
providerRef:
name: production-aws

dbInstanceIdentifier: critical-db-prod

engine: postgres
engineVersion: "15.4"

dbInstanceClass: db.r5.xlarge # Memory optimized
allocatedStorage: 500
storageType: io2
iops: 20000

masterUsername: postgres
masterUserPasswordSecretRef:
name: critical-db-password
key: password

# VPC privada com segurança
dbSubnetGroupName: critical-subnet-group
vpcSecurityGroupRefs:
- name: critical-rds-sg
publiclyAccessible: false

# HA e proteção
multiAZ: true
deletionProtection: true

# Backups com PITR completo
backupRetentionPeriod: 35
preferredBackupWindow: "02:00-03:00"
skipFinalSnapshot: false
finalDBSnapshotIdentifier: critical-db-final-backup

# Criptografia com KMS
storageEncrypted: true
kmsKeyId: arn:aws:kms:us-east-1:123456789012:key/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee

# Monitoramento completo
enablePerformanceInsights: true
enableEnhancedMonitoring: true
monitoringInterval: 1

# Autenticação IAM
enableIAMDatabaseAuthentication: true

# Manutenção
preferredMaintenanceWindow: "sun:03:00-sun:04:00"

tags:
Environment: production
CriticalData: "true"
BackupRequired: "true"
Compliance: "required"

deletionPolicy: Retain

RDS MariaDB para WordPress/CMS

Banco de dados para aplicação web tradicional:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: RDSInstance
metadata:
name: wordpress-db
namespace: default
spec:
providerRef:
name: production-aws

dbInstanceIdentifier: wordpress-db

engine: mariadb
engineVersion: "10.6.14"

dbInstanceClass: db.t3.small
allocatedStorage: 50
storageType: gp3

masterUsername: wordpress
masterUserPasswordSecretRef:
name: wordpress-db-password
key: password

dbSubnetGroupName: web-subnet-group
vpcSecurityGroupRefs:
- name: wordpress-rds-sg

multiAZ: true
backupRetentionPeriod: 14

tags:
Environment: production
Application: wordpress

deletionPolicy: Retain

Verificação

Verificar Status via kubectl

Comando:

# Listar todas as instâncias RDS
kubectl get rdsinstances

# Obter informações detalhadas
kubectl get rdsinstance production-postgres -o yaml

# Monitorar criação em tempo real
kubectl get rdsinstance production-postgres -w

# Ver eventos e status
kubectl describe rdsinstance production-postgres

Verificar na AWS

AWS CLI:

# Listar instâncias RDS
aws rds describe-db-instances \
--query 'DBInstances[].{Identifier:DBInstanceIdentifier,Status:DBInstanceStatus,Engine:Engine,Class:DBInstanceClass}' \
--output table

# Obter detalhes completos
aws rds describe-db-instances \
--db-instance-identifier app-db-prod \
--output json | jq '.DBInstances[0]'

# Ver endpoint de conexão
aws rds describe-db-instances \
--db-instance-identifier app-db-prod \
--query 'DBInstances[0].Endpoint'

# Testar conexão (PostgreSQL)
psql -h app-db-prod.c9akciq32.us-east-1.rds.amazonaws.com \
-U postgres \
-d postgres

# Ver backups
aws rds describe-db-snapshots \
--db-instance-identifier app-db-prod

# Ver status multi-AZ
aws rds describe-db-instances \
--db-instance-identifier app-db-prod \
--query 'DBInstances[0].MultiAZ'

LocalStack:

# Para testes com LocalStack
export AWS_ENDPOINT_URL=http://localhost:4566

aws rds describe-db-instances

aws rds describe-db-instances \
--db-instance-identifier app-db-prod

psql (PostgreSQL):

# Conectar ao banco de dados
psql -h <endpoint> -U postgres -d postgres

# Ver usuários
\du

# Ver bancos de dados
\l

# Ver espaço usado
SELECT pg_database.datname,
pg_size_pretty(pg_database_size(pg_database.datname))
FROM pg_database;

# Desconectar
\q

mysql (MySQL/MariaDB):

# Conectar ao banco de dados
mysql -h <endpoint> -u admin -p

# Ver bancos de dados
SHOW DATABASES;

# Ver usuários
SELECT user, host FROM mysql.user;

# Ver espaço usado
SELECT table_schema,
ROUND(SUM(data_length+index_length)/1024/1024,2) AS size_mb
FROM information_schema.tables
GROUP BY table_schema;

# Sair
EXIT;

Output Esperado

Exemplo:

status:
dbInstanceArn: arn:aws:rds:us-east-1:123456789012:db:app-db-prod
dbInstanceStatus: available
endpoint:
address: app-db-prod.c9akciq32.us-east-1.rds.amazonaws.com
port: 5432
engine: postgres
engineVersion: "15.4"
dbInstanceClass: db.t3.small
allocatedStorage: 50
multiAZ: true
storageEncrypted: true
ready: true
lastSyncTime: "2025-11-22T20:45:22Z"

Solução de Problemas

RDS travado em creating por mais de 30 minutos

Sintomas: dbInstanceStatus: creating indefinidamente

Causas comuns:

  1. Subnet group não existe ou é inválido
  2. Security group não encontrado
  3. Cota de instâncias RDS atingida
  4. Problema de conectividade com AWS

Soluções:

# Verificar status detalhado
kubectl describe rdsinstance app-database

# Ver logs do operator
kubectl logs -n infra-operator-system \
deploy/infra-operator-controller-manager \
--tail=100 | grep -i rds

# Verificar se subnet group existe
aws rds describe-db-subnet-groups \
--db-subnet-group-name private-subnet-group

# Verificar se AWSProvider está ready
kubectl get awsprovider
kubectl describe awsprovider production-aws

# Forçar sincronização
kubectl annotate rdsinstance app-database \
force-sync="$(date +%s)" --overwrite

# Último recurso: deletar e recriar (com Retain)
kubectl patch rdsinstance app-database \
--type merge \
-p '{"spec":{"deletionPolicy":"Retain"}}'

Timeout de conexão ao conectar no banco de dados

Sintomas: psql: could not translate host name ou Connection refused

Causas comuns:

  1. Security group não permite conexão (porta bloqueada)
  2. Banco de dados não é publicamente acessível e está conectando de fora da VPC
  3. Hostname/endpoint incorreto
  4. Rede não roteada corretamente

Soluções:

# Obter endpoint correto
aws rds describe-db-instances \
--db-instance-identifier app-db-prod \
--query 'DBInstances[0].Endpoint'

# Verificar se security group permite ingress
aws ec2 describe-security-groups \
--group-ids sg-0123456789abcdef0 \
--query 'SecurityGroups[0].IpPermissions'

# DEVE ter regra como:
# IpProtocol: tcp, FromPort: 5432, ToPort: 5432
# CidrIp: 10.0.0.0/16 (sua VPC)

# Se conectando de fora da VPC:
# 1. Habilitar publiclyAccessible (não recomendado)
# 2. Ou usar bastion/jump host
# 3. Ou usar VPN

# Testar com telnet/nc
nc -zv app-db-prod.c9akciq32.us-east-1.rds.amazonaws.com 5432

# Testar com psql verbose
psql -h app-db-prod.c9akciq32.us-east-1.rds.amazonaws.com \
-U postgres \
-d postgres \
-v

# Se usando Multi-AZ, failover pode estar em andamento
# Tente novamente em 5 minutos

Espaço em disco esgotado (storage full)

Sintomas: Erro Disk full ao executar queries, aplicação lenta

Causas:

  1. Dados cresceram além do esperado
  2. Logs acumulados ou backups
  3. Falta de limpeza de dados antigos

Soluções:

# Ver espaço disponível
aws rds describe-db-instances \
--db-instance-identifier app-db-prod \
--query 'DBInstances[0].AllocatedStorage'

# Aumentar storage (pode levar minutos)
kubectl patch rdsinstance app-database \
--type merge \
-p '{"spec":{"allocatedStorage":100}}'

# Ver progresso
kubectl get rdsinstance app-database -w

# Se PostgreSQL, limpar espaço
# Conectar ao banco de dados:
psql -h <endpoint> -U postgres -d postgres

# Vacuum full (recuperar espaço)
VACUUM FULL;
VACUUM ANALYZE;

# Se MySQL, otimizar tabelas
mysql -h <endpoint> -u admin -p

OPTIMIZE TABLE table_name;

# Ver tamanho do banco de dados
SELECT pg_database.datname,
pg_size_pretty(pg_database_size(pg_database.datname))
FROM pg_database;

Custos altos de RDS

Sintomas: Conta AWS com cobranças inesperadas de RDS

Causas comuns:

  1. Classe de instância muito grande
  2. IOPS provisionados altos
  3. Muitos backups retidos
  4. Replicação cross-region

Soluções:

# Calcular custo atual
# Use AWS Pricing Calculator
# t3.small: ~$0.034/hora * 730 = ~$25/mês
# gp3 storage: ~$0.12/GB/mês

# Reduzir classe (se possível)
kubectl patch rdsinstance app-database \
--type merge \
-p '{"spec":{"dbInstanceClass":"db.t3.micro"}}'

# Reduzir retenção de backup
kubectl patch rdsinstance app-database \
--type merge \
-p '{"spec":{"backupRetentionPeriod":7}}'

# Deletar snapshots antigos desnecessários
aws rds delete-db-snapshot \
--db-snapshot-identifier app-db-snapshot-old

# Para dev, deletar após uso
kubectl delete rdsinstance dev-database

Backup falha ou demora muito

Sintomas: Status de backup travado em backing-up por horas

Causas:

  1. Banco de dados muito grande
  2. IO saturado durante backup
  3. Muitas transações durante backup

Soluções:

# Ver status de backup
aws rds describe-db-instances \
--db-instance-identifier app-db-prod \
--query 'DBInstances[0].LatestRestorableTime'

# Ver snapshots completos
aws rds describe-db-snapshots \
--db-instance-identifier app-db-prod

# Aumentar janela de backup
kubectl patch rdsinstance app-database \
--type merge \
-p '{"spec":{"preferredBackupWindow":"02:00-04:00"}}'

# Aumentar IOPS para performance de backup
kubectl patch rdsinstance app-database \
--type merge \
-p '{"spec":{"iops":5000}}'

# Criar snapshot manual
aws rds create-db-snapshot \
--db-instance-identifier app-db-prod \
--db-snapshot-identifier manual-backup-$(date +%Y%m%d-%H%M%S)

Failover Multi-AZ lento ou falha

Sintomas: Após falha, aplicação offline por 5+ minutos

Causa: Failover automático pode demorar, especialmente se Multi-AZ não configurado corretamente

Soluções:

# Verificar se Multi-AZ está habilitado
aws rds describe-db-instances \
--db-instance-identifier app-db-prod \
--query 'DBInstances[0].MultiAZ'

# Habilitar se não estiver
kubectl patch rdsinstance app-database \
--type merge \
-p '{"spec":{"multiAZ":true}}'

# Testar failover manualmente
# CUIDADO: Causa downtime!
aws rds reboot-db-instance \
--db-instance-identifier app-db-prod \
--force-failover

# Ver progresso de reboot
aws rds describe-db-instances \
--db-instance-identifier app-db-prod \
--query 'DBInstances[0].DBInstanceStatus'

# Implementar retry na aplicação
# Usar connection pooling
# Configurar failover no nível da aplicação

Read Replica não sincronizando ou com lag

Sintomas: Réplica mostra dados desatualizados, não consegue conectar

Causas:

  1. Lag de replicação (atraso de rede)
  2. Banco de dados primário sob pressão de IO
  3. Problemas de rede

Soluções:

# Ver lag de réplica
aws rds describe-db-instances \
--db-instance-identifier myapp-db-read-replica \
--query 'DBInstances[0].StatusInfos'

# Aumentar classe de réplica se estiver subprovisionada
kubectl patch rdsinstance read-replica-db \
--type merge \
-p '{"spec":{"dbInstanceClass":"db.t3.small"}}'

# Aumentar IOPS no primário
kubectl patch rdsinstance primary-db \
--type merge \
-p '{"spec":{"iops":5000}}'

Performance degradada (queries lentas)

Sintomas: Queries normais ficam lentas, CPU/IO alto

Causas:

  1. Falta de índices
  2. Plano de query subótimo
  3. Falta de memória/CPU
  4. Locks de transações

Soluções:

# Habilitar Performance Insights
kubectl patch rdsinstance app-database \
--type merge \
-p '{"spec":{"enablePerformanceInsights":true}}'

# Usar console AWS Performance Insights para análise

# Aumentar memória/CPU se necessário
kubectl patch rdsinstance app-database \
--type merge \
-p '{"spec":{"dbInstanceClass":"db.m5.large"}}'

# Conectar e analisar queries
psql -h <endpoint> -U postgres -d postgres

# Ver queries lentas (PostgreSQL)
SELECT query, calls, mean_exec_time, max_exec_time
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;

# Ver índices faltando
SELECT schemaname, tablename
FROM pg_tables
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
ORDER BY schemaname, tablename;

# Criar índices apropriados
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_date ON orders(created_at);

Erro ao deletar banco de dados (finalizer travado)

Sintomas: kubectl delete rdsinstance pendente indefinidamente

Causa: Finalizer não consegue deletar snapshot final ou banco de dados

Soluções:

# Ver detalhes
kubectl describe rdsinstance app-database

# Ver finalizers
kubectl get rdsinstance app-database -o yaml | grep finalizers

# Opção 1: Mudar deletionPolicy antes de deletar
kubectl patch rdsinstance app-database \
--type merge \
-p '{"spec":{"deletionPolicy":"Retain"}}'

# Então deletar
kubectl delete rdsinstance app-database

# Opção 2: Deletar snapshot final manualmente
aws rds delete-db-snapshot \
--db-snapshot-identifier app-db-final-backup

# Então forçar delete do CR
kubectl patch rdsinstance app-database \
-p '{"metadata":{"finalizers":[]}}' \
--type=merge

# Opção 3: Manter snapshot final, apenas remover CR
kubectl patch rdsinstance app-database \
--type merge \
-p '{"spec":{"skipFinalSnapshot":true}}'

kubectl delete rdsinstance app-database

Boas Práticas

Boas Práticas
  • Habilite Multi-AZ para produção — Failover automático em minutos, ~50% de custo a mais mas essencial para dados críticos, teste failover regularmente
  • Habilite criptografia em todos os lugares — Criptografia de storage (AES-256), AWS KMS para chaves customizadas, SSL/TLS para conexões, criptografia de backup para compliance
  • Configure retenção de backup apropriada — 7-35 dias dependendo da criticidade, mínimo 14 dias para produção, PITR até 35 dias, teste restore regularmente
  • Restrinja acesso de security group — Apenas IPs/SGs necessários, nunca 0.0.0.0/0, segregue dev/staging/prod, audite regras regularmente
  • Use apenas subnets privadas — Nunca publicamente acessível em produção, use NAT gateway para outbound, bastion/jump host para acesso admin
  • Habilite monitoramento e insights — Performance Insights para tuning, alertas CloudWatch para anomalias, monitore métricas de CPU/Storage/IOPS
  • Ajuste parameter groups — Customize configurações por engine (shared_buffers, work_mem para PostgreSQL), documente razão das mudanças, teste em dev primeiro
  • Tagueie todos os recursos — Environment (dev/staging/prod), application, cost center, owner/team, flag de backup required
  • Dimensione instâncias corretamente — Comece pequeno e monitore crescimento, use t3/t4g para cargas variáveis, m5 para cargas de produção previsíveis
  • Otimize custos — Delete dev/staging após uso, retenção de backup apropriada, reserved instances para produção
  • Planeje disaster recovery — Read replicas para DR regional, snapshots em outra região, documente RTO/RPO, automatize failover
  • Habilite audit e compliance — CloudTrail para chamadas API, CloudWatch Logs para queries, autenticação IAM de banco de dados
  • Otimize queries — Performance Insights para bottlenecks, logs de slow query, estratégia de índice apropriada, connection pooling na app

Casos de Uso

1. Aplicação Web Transacional

E-commerce ou SaaS com muitas transações pequenas:

dbInstanceClass: db.t3.small
allocatedStorage: 100
multiAZ: true
backupRetentionPeriod: 30
# Índices em user_id, order_id, timestamps

2. E-commerce com Carrinhos e Pedidos

Dados de alto volume com transações críticas:

dbInstanceClass: db.m5.large
allocatedStorage: 500
storageType: io1
iops: 10000
multiAZ: true
backupRetentionPeriod: 35
# Read replica para analytics

3. CMS (WordPress, Drupal)

Aplicações web com conteúdo dinâmico:

engine: mysql  # ou mariadb
dbInstanceClass: db.t3.small
allocatedStorage: 50
multiAZ: true
enableCloudwatchLogsExports: [slowquery, error]

4. ERP/CRM com Alta Concorrência

Múltiplos usuários acessando simultaneamente:

dbInstanceClass: db.m5.2xlarge
allocatedStorage: 1000
storageType: io2
iops: 64000
multiAZ: true
backupRetentionPeriod: 35
enableEnhancedMonitoring: true

Recursos Relacionados