0 XP
Módulo 7 · Terraform e Ansible

Módulos, reuso e combate ao drift

Avançado 50 min+25 XPTerraformCI

Objetivos desta aula

  • Escrever módulo com interface clara
  • Reutilizar entre ambientes
  • Detectar drift automaticamente

Módulo é a unidade de reuso: entradas (variables), lógica (resources) e saídas (outputs). Um bom módulo tem interface pequena, valores padrão sensatos e nenhuma suposição escondida sobre o ambiente. Módulo de rede, de aplicação e de banco cobrem a maior parte das necessidades de um projeto do porte do CloudShop.

Drift é a divergência entre o código e a realidade, geralmente causada por alteração manual no console durante uma emergência. O problema não é apenas estético: o próximo apply pode desfazer uma correção urgente ou destruir algo que passou a ser necessário.

A defesa é processo: plan agendado em CI que falha quando há diferença, notificação para o time e regra clara de que alteração manual precisa ser refletida no código no mesmo dia. Quando o recurso já existe fora do Terraform, use import (ou blocos import) para trazê-lo ao controle.

1. O que é um módulo

Qualquer diretório com arquivos .tf. Um bom módulo tem interface pequena (variáveis com tipos e validação), outputs claros e um propósito só, como 'rede do CloudShop'.

2. Versionar módulos

Referencie por tag Git (?ref=v1.2.0) ou registry. Assim prod pode ficar em v1.2 enquanto dev testa v1.3.

3. count e for_each

for_each sobre um map gera recursos com chaves estáveis; count usa índices, e remover um item do meio recria os seguintes. Prefira for_each.

4. Drift

Drift é quando alguém altera a nuvem pelo console. terraform plan -refresh-only revela; a correção é trazer a mudança para o código ou reaplicar. Rode um plan agendado no CI que alerta quando há diferença.

5. Importar e mover

Blocos import trazem recursos existentes para o código; blocos moved renomeiam sem destruir.

6. Checagem final

Você deve criar um módulo de rede reutilizado por dev e prod e detectar uma mudança manual feita no console.

Na prática

Módulo de rede e consumo por ambiente

hcl

# modules/network/variables.tf
variable "env"       { type = string }
variable "cidr"      { type = string }
variable "azs"       { type = list(string), default = ["us-east-1a", "us-east-1b"] }

# modules/network/main.tf
resource "aws_vpc" "this" {
  cidr_block = var.cidr
  tags       = { Name = "cloudshop-${var.env}" }
}

resource "aws_subnet" "private" {
  for_each          = { for i, az in var.azs : az => i }
  vpc_id            = aws_vpc.this.id
  availability_zone = each.key
  cidr_block        = cidrsubnet(var.cidr, 8, each.value + 10)
  tags              = { Name = "cloudshop-${var.env}-priv-${each.key}" }
}

output "vpc_id"      { value = aws_vpc.this.id }
output "private_ids" { value = [for s in aws_subnet.private : s.id] }

# envs/staging/main.tf
module "network" {
  source = "../../modules/network"
  env    = "staging"
  cidr   = "10.30.0.0/16"
}

Detecção de drift em CI

yaml

name: drift-check
on:
  schedule: [{ cron: "0 7 * * 1-5" }]
  workflow_dispatch:

permissions:
  contents: read
  id-token: write

jobs:
  plan:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        env: [dev, staging]
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/cloudshop-plan
          aws-region: us-east-1
      - uses: hashicorp/setup-terraform@v3
      - run: terraform -chdir=infra/envs/${{ matrix.env }} init
      - name: Plan detecta drift
        run: terraform -chdir=infra/envs/${{ matrix.env }} plan -detailed-exitcode -no-color
        # exit 2 = ha mudancas pendentes (drift)

Nota de segurança: A role de plan deve ter permissão somente de leitura; apply usa role separada com aprovação.

for_each com chaves estáveis

hcl

variable "subnets" {
  type = map(object({ cidr = string, az = string }))
}
resource "aws_subnet" "this" {
  for_each          = var.subnets            # chave = nome da subnet
  vpc_id            = aws_vpc.this.id
  cidr_block        = each.value.cidr
  availability_zone = each.value.az
  tags              = { Name = each.key }
}

Detectar drift e renomear sem destruir

hcl

# terraform plan -refresh-only -detailed-exitcode  (exit 2 = ha drift)
moved {
  from = aws_s3_bucket.imgs
  to   = aws_s3_bucket.images
}
import {
  to = aws_s3_bucket.logs
  id = "cloudshop-dev-logs"
}

Por que isso importa

Drift é o boss deste território e uma dor real de todo time que opera nuvem em escala.

Erro comum

Criar módulo gigante com dezenas de variáveis que ninguém entende nem reutiliza.

Dica de produção

Fixe versão do módulo (tag Git) ao consumi-lo: atualização de módulo deve ser decisão explícita.

Pergunta de entrevista

Como você detecta e corrige drift em uma infraestrutura de produção?

Glossário

drift
Divergência entre o estado descrito no código e o estado real da infraestrutura.
import
Trazer um recurso existente para o controle do Terraform.
drift
Diferença entre o código/state e o que existe de fato na nuvem.
for_each
Meta-argumento que cria uma instância por item de um map ou set.
moved block
Declaração que renomeia um recurso no state sem recriá-lo.

Conexão com o CloudShop

Extrair o módulo de rede do CloudShop e usá-lo em dev e staging.

Quiz da aula

  1. 1. O que o exit code 2 de terraform plan -detailed-exitcode indica?

  2. 2. Por que preferir for_each a count em listas que mudam?

  3. 3. Como detectar drift sem alterar nada?

Minhas anotações

Salvo automaticamente neste navegador.

AnteriorPróxima