Como Montei uma Arquitetura Three-Tier na AWS que Aguenta Pancada
Minha experiência montando uma arquitetura de 3 camadas na AWS. VPC, Load Balancer, Auto Scaling e RDS Multi-AZ - o que funcionou e o que eu mudaria.
Depois de quebrar a cabeça algumas vezes com arquiteturas mal planejadas, resolvi documentar o que aprendi montando uma infraestrutura three-tier na AWS que realmente funciona em produção.
Por que Three-Tier?
Antes de sair criando recursos, vale entender o porquê dessa separação em camadas:
- Camada Pública - ALB fica aqui, exposto pra internet
- Camada de Aplicação - Onde seus servidores rodam, protegidos
- Camada de Dados - Banco de dados isolado, sem acesso externo
Parece óbvio, mas já vi muita gente jogando RDS em subnet pública “porque é mais fácil conectar”. Não faça isso.
A VPC que Uso
Aprendi que vale a pena gastar um tempo planejando o CIDR block. Nada pior que ficar sem IPs ou ter conflito com VPN depois.
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
}
Com /16 você tem 65.536 IPs - suficiente pra crescer sem dor de cabeça.
Subnets em 3 AZs
Distribuo em 3 Availability Zones. Já tive problema quando uma AZ ficou fora do ar - com apenas 2, metade do tráfego caiu. Com 3, o impacto é bem menor.
# Públicas - ALB fica aqui
resource "aws_subnet" "public" {
count = 3
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index + 1}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
}
# Privadas App - EC2/ECS ficam aqui
resource "aws_subnet" "private_app" {
count = 3
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index + 10}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
}
# Privadas Data - RDS/ElastiCache
resource "aws_subnet" "private_data" {
count = 3
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index + 20}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
}
O NAT Gateway que Dói no Bolso
Uma coisa que me pegou de surpresa: NAT Gateway é caro. Cada um custa uns $32/mês parado, mais $0.045 por GB de dados.
A tentação é usar só 1 NAT pra economizar. Problema: se a AZ onde ele tá cair, suas instâncias privadas perdem acesso à internet.
Minha decisão foi usar 3 NATs (um por AZ) em produção, mas apenas 1 em ambiente de dev/staging.
resource "aws_nat_gateway" "main" {
count = var.environment == "production" ? 3 : 1
allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.public[count.index].id
}
Load Balancer com as Configs que Importam
O ALB é simples de configurar, mas tem detalhes que fazem diferença:
resource "aws_lb" "main" {
name = "app-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = aws_subnet.public[*].id
# Ativa isso em produção - evita deletar sem querer
enable_deletion_protection = true
}
resource "aws_lb_listener" "https" {
load_balancer_arn = aws_lb.main.arn
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
certificate_arn = aws_acm_certificate.main.arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.app.arn
}
}
O health check também precisa de atenção. Já vi aplicação ser derrubada porque o health check tava muito agressivo:
resource "aws_lb_target_group" "app" {
name = "app-tg"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.main.id
health_check {
enabled = true
healthy_threshold = 2
unhealthy_threshold = 3 # Dá 3 chances antes de marcar unhealthy
timeout = 5
interval = 30 # Não precisa checar toda hora
path = "/health"
matcher = "200"
}
}
Auto Scaling que Funciona
O Auto Scaling parece mágico no papel, mas na prática tem pegadinhas.
Primeiro, o launch template precisa ter tudo que a instância precisa pra subir sozinha:
resource "aws_launch_template" "app" {
name_prefix = "app-"
image_id = data.aws_ami.amazon_linux_2023.id
instance_type = "t3.medium"
user_data = base64encode(<<-EOF
#!/bin/bash
# Suas dependências aqui
yum update -y
# Puxa a aplicação e sobe
docker pull minha-app:latest
docker run -d -p 80:80 minha-app:latest
EOF
)
# IMDSv2 obrigatório - questão de segurança
metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
}
}
As políticas de scaling que uso:
resource "aws_autoscaling_group" "app" {
name = "app-asg"
desired_capacity = 3
min_size = 2 # Nunca fica zerado
max_size = 10
target_group_arns = [aws_lb_target_group.app.arn]
vpc_zone_identifier = aws_subnet.private_app[*].id
health_check_type = "ELB" # Usa o health check do ALB
}
# Scale up quando CPU passar de 70%
resource "aws_autoscaling_policy" "scale_up" {
name = "scale-up"
scaling_adjustment = 2
adjustment_type = "ChangeInCapacity"
cooldown = 300 # 5 min entre scales
autoscaling_group_name = aws_autoscaling_group.app.name
}
RDS Multi-AZ - Não Economize Aqui
Banco de dados é onde você não quer ter downtime. Multi-AZ custa mais, mas o failover automático já me salvou.
resource "aws_db_instance" "main" {
identifier = "production-db"
engine = "mysql"
engine_version = "8.0"
instance_class = "db.r6g.large"
allocated_storage = 100
max_allocated_storage = 500 # Cresce automático
storage_type = "gp3"
storage_encrypted = true
multi_az = true # Failover automático
backup_retention_period = 30
deletion_protection = true
# Performance Insights ajuda muito no debug
performance_insights_enabled = true
}
Quanto Isso Custa?
Sendo realista com os números (us-east-1):
| Recurso | Custo/mês |
|---|---|
| ALB | ~$25 |
| 3x t3.medium | ~$90 |
| 3x NAT Gateway | ~$100 |
| RDS r6g.large Multi-AZ | ~$350 |
| Total | ~$565/mês |
Dá pra reduzir bastante usando Reserved Instances ou Savings Plans se o workload for previsível.
O que Eu Mudaria
Olhando pra trás, algumas coisas que faria diferente:
- Começaria com Fargate ao invés de EC2 - menos coisa pra gerenciar
- Usaria Parameter Store desde o início pra secrets
- Terraform workspaces ao invés de pastas separadas por ambiente
A arquitetura three-tier é battle-tested e funciona. O importante é entender o porquê de cada componente, não só copiar configs.
Se quiser trocar ideia sobre arquitetura cloud, me chama no LinkedIn ou vê meus projetos no GitHub.