Voltar ao blog

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.

RS
Richard Sakaguchi Solution Architect

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):

RecursoCusto/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:

  1. Começaria com Fargate ao invés de EC2 - menos coisa pra gerenciar
  2. Usaria Parameter Store desde o início pra secrets
  3. 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.

Gostou do conteudo?

Descubra como implementar IA no seu negocio com uma analise gratuita.

Agendar Analise Gratuita

Pronto para automatizar seu atendimento?

Agende uma analise gratuita e descubra como IA pode transformar seu negocio.

Agendar Analise Gratuita