A bagunça que todo mundo já viveu
Sabe aquele momento quando você abre um projeto Terraform depois de 6 meses e pensa “quem foi o animal que escreveu isso”? E aí percebe que foi você mesmo. Já passei por isso mais vezes do que gostaria de admitir.
Organizar código Terraform não é luxo, é necessidade. Especialmente quando a gente trabalha com múltiplos ambientes, equipes grandes ou projetos que crescem além do que imaginávamos inicialmente.
A estrutura básica que funciona
Depois de anos organizando infraestrutura na AWS, Azure e Google Cloud, descobri que existe uma estrutura que funciona na maioria dos casos:
project-name/
├── environments/
│ ├── dev/
│ ├── staging/
│ └── prod/
├── modules/
│ ├── vpc/
│ ├── eks/
│ └── rds/
├── shared/
└── scripts/
Cada pasta tem seu propósito específico. Os environments guardam as configurações de cada ambiente. Os modules são pedaços reutilizáveis de código. O shared fica com recursos compartilhados entre ambientes.
Módulos: seu melhor amigo
Se você ainda não usa módulos Terraform, está perdendo tempo e dinheiro. Eles são como funções no código: escreveu uma vez, usa em qualquer lugar.
Exemplo prático de um módulo VPC simples:
# modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.project_name}-vpc"
Environment = var.environment
}
}
resource "aws_subnet" "public" {
count = length(var.public_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnets[count.index]
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-public-${count.index + 1}"
}
}
Agora você pode usar esse módulo em qualquer ambiente:
# environments/prod/vpc.tf
module "vpc" {
source = "../../modules/vpc"
project_name = "meu-projeto"
environment = "prod"
cidr_block = "10.0.0.0/16"
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
}
Variáveis e outputs organizados
Cada módulo precisa de três arquivos básicos: main.tf, variables.tf e outputs.tf. Parece burocracia, mas salva sua vida depois.
# modules/vpc/variables.tf
variable "project_name" {
description = "Nome do projeto"
type = string
}
variable "environment" {
description = "Ambiente (dev, staging, prod)"
type = string
}
variable "cidr_block" {
description = "CIDR block da VPC"
type = string
}
variable "public_subnets" {
description = "Lista de CIDR blocks para subnets públicas"
type = list(string)
}
E os outputs para referenciar em outros módulos:
# modules/vpc/outputs.tf
output "vpc_id" {
description = "ID da VPC criada"
value = aws_vpc.main.id
}
output "public_subnet_ids" {
description = "IDs das subnets públicas"
value = aws_subnet.public[*].id
}
Separação por ambientes
Cada ambiente deve ter sua própria pasta com state separado. Isso evita que mudanças em dev quebrem produção (já vi isso acontecer, não é bonito).
# environments/prod/main.tf
terraform {
backend "s3" {
bucket = "meu-projeto-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
}
}
module "vpc" {
source = "../../modules/vpc"
# configurações específicas de prod
}
module "eks" {
source = "../../modules/eks"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.public_subnet_ids
# outras configurações
}
Caso real: refatoração que salvou o projeto
Semana passada ajudamos uma startup que tinha tudo em um arquivo main.tf de 800 linhas. Deploy demorava 40 minutos e qualquer mudança era um risco.
Quebramos em 6 módulos: VPC, EKS, RDS, ElastiCache, ALB e monitoring. Resultado: deploys de 8 minutos e zero downtime nos últimos 30 dias.
O segredo foi criar módulos pequenos e específicos. Cada um com responsabilidade única.
Ferramentas que facilitam a vida
Algumas ferramentas que uso todo dia:
- terraform-docs: gera documentação automática dos módulos
- tflint: pega erros antes do apply
- terragrunt: DRY para configurações Terraform
- pre-commit hooks: valida código antes do commit
Configuração básica do pre-commit:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.77.0
hooks:
- id: terraform_fmt
- id: terraform_validate
- id: terraform_docs
- id: terraform_tflint
Versionamento de módulos
Quando os módulos começam a ser usados por várias equipes, versionar vira obrigatório. Uso tags Git simples:
module "vpc" {
source = "git::https://github.com/empresa/terraform-modules.git//vpc?ref=v1.2.0"
# configurações
}
Assim cada ambiente pode usar versões diferentes sem quebrar nada.
Naming conventions que salvam
Padronize nomes desde o início. Uso este padrão:
- Resources:
${projeto}-${ambiente}-${tipo} - Variáveis: snake_case sempre
- Outputs: descritivos e consistentes
- Tags: Project, Environment, Owner obrigatórias
Organização não é perfumaria. É economia de tempo, dinheiro e stress. Comece simples, mas comece desde o primeiro dia. Seu eu do futuro vai agradecer.
