
Módulos reutilizáveis: contratos, validação e evolução segura
Objetivos desta aula
- Desenhar uma interface pequena de módulo
- Validar entradas antes do provisionamento
- Expor outputs sem acoplar consumidores
- Planejar mudanças de endereço com moved
- Versionar e revisar atualizações de módulo
O módulo de rede já demonstrou reuso; agora vamos tratar um módulo como produto interno com contrato. Quem o consome precisa entender entradas, saídas e garantias sem ler todos os recursos. Um módulo que exige conhecer sua implementação apenas moveu a complexidade para outra pasta.
Escolha uma responsabilidade coesa. Neste exercício, modules/private-subnet cria uma subnet sem IP público automático e devolve seu ID. Ele não cria VPC, NAT ou banco escondidos; a composição dessas peças fica no módulo raiz, onde o ambiente é decidido.
Valide o que puder antes da API. Uma variável cidr com validation evita um erro básico de formato, mas não comprova ausência de sobreposição nem capacidade futura de endereçamento. Documente essas limitações e revise o desenho de rede junto com o plano.
Use outputs estáveis como interface: o consumidor depende de subnet_id, não de caminhos internos de recursos. Evite exportar objetos inteiros quando um ID basta. Isso reduz acoplamento e permite reorganizar a implementação sem obrigar cada ambiente a mudar.
O provider deve ser configurado no módulo raiz e recebido pelo filho, que declara seus requisitos. Assim dev e staging podem usar contas e regiões distintas sem credenciais embutidas no módulo. required_providers especifica compatibilidade, não autenticação.
Uma mudança de nome interno pode alterar o endereço no state sem alterar o recurso desejado. Um bloco moved informa a migração de endereço; não o use para esconder substituições reais. O plano deve mostrar a movimentação esperada e ausência de recriação indevida.
Versão fixa é decisão de atualização, não abandono de manutenção. Para módulo remoto, use versão de registry ou referência Git imutável revisada; para módulo local, a versão acompanha o commit do repositório. .terraform.lock.hcl fixa providers, não versões de módulos remotos.
Valide o contrato em um ambiente descartável: formato, validate, plano e saída esperada. Depois execute um segundo plano para conferir convergência. Antes de publicar uma mudança incompatível em subnet_id ou nas entradas obrigatórias, documente migração e combine a atualização com os consumidores.
Na prática
Contrato e implementação de modules/private-subnet/main.tf
hcl
# O provider será herdado do módulo raiz.
terraform {
required_providers {
aws = { source = "hashicorp/aws" }
}
}
variable "vpc_id" {
type = string
}
variable "az" {
type = string
}
variable "cidr" {
type = string
validation {
condition = can(cidrnetmask(var.cidr))
error_message = "Informe um CIDR IPv4 válido."
}
}
resource "aws_subnet" "this" {
vpc_id = var.vpc_id
availability_zone = var.az
cidr_block = var.cidr
map_public_ip_on_launch = false
# Privacidade também depende da tabela de rotas associada pelo módulo raiz.
}
output "subnet_id" {
description = "ID da subnet para composição no módulo raiz."
value = aws_subnet.this.id
}Migração de nome dentro do módulo
hcl
# Inclua apenas se uma versão anterior usava aws_subnet.private.
# Requer Terraform >= 1.1; mantenha o bloco durante a janela de migração.
moved {
from = aws_subnet.private
to = aws_subnet.this
}
# Rode plan em cada consumidor e confira que não há destruição inesperada.Por que isso importa
Interfaces previsíveis permitem atualizar infraestrutura de vários ambientes sem multiplicar correções manuais.
Erro comum
Renomear um resource sem migração e aceitar um plano de destruição por parecer apenas uma refatoração.
Dica de produção
Publique exemplos mínimos de consumo e uma lista de mudanças incompatíveis por versão do módulo.
Alerta de segurança
Não coloque access_key, secret_key ou credenciais de backend em módulos; autentique a execução por role.
Pergunta de entrevista
Como renomear um recurso dentro de um módulo sem recriá-lo nos ambientes consumidores?
Glossário
- contrato de módulo
- Entradas, saídas e garantias públicas para os consumidores.
- módulo raiz
- Configuração executada diretamente, que compõe módulos filhos e providers.
- moved
- Bloco declarativo de migração entre endereços de recursos no state.
- acoplamento
- Dependência de um consumidor em detalhes internos de outra parte.
- mudança incompatível
- Alteração que exige adaptação dos consumidores existentes.
Conexão com o CloudShop
Evoluir o módulo de rede do CloudShop com entradas validadas, outputs documentados e plano de migração sem recriação.
Quiz da aula
1. O que .terraform.lock.hcl fixa?
2. Qual recurso ajuda em uma renomeação de endereço no state?
3. Um módulo com map_public_ip_on_launch=false garante subnet privada?
Minhas anotações
Salvo automaticamente neste navegador.
