Infraestrutura como código é a prática de descrever servidores, redes e serviços em arquivos versionados, em vez de configurá-los manualmente no console do provedor. Neste tutorial, você vai montar um fluxo básico e reproduzível com Terraform, passando por estrutura de projeto, state remoto, ciclo plan/apply e automação em pipeline.
O objetivo é prático: sair com um repositório que qualquer pessoa do time consiga clonar, revisar e aplicar com previsibilidade. Os exemplos usam o provider Docker para rodar localmente, mas a lógica vale para qualquer cloud.
Por que adotar infraestrutura como código
Quando o ambiente é criado por cliques, ninguém sabe ao certo o que existe, quem alterou o quê e como recriar tudo após um incidente. Com infraestrutura como código, o estado desejado fica em Git, e cada mudança passa por revisão, histórico e rollback.
- Reprodutibilidade: ambientes de desenvolvimento, homologação e produção nascem da mesma definição.
- Auditoria: o histórico de commits mostra quem mudou o quê e quando.
- Revisão: o plan mostra o impacto antes de qualquer alteração real.
- Recuperação: recriar um ambiente deixa de depender da memória de uma pessoa.
Passo 1: estruture o projeto
Comece com uma organização simples. Evite criar módulos antes de ter repetição real; abstração prematura só atrapalha a leitura.
infra/
main.tf
variables.tf
outputs.tf
providers.tf
backend.tf
.gitignore
No .gitignore, inclua .terraform/, arquivos *.tfstate* e qualquer *.tfvars com segredos. Versione o arquivo .terraform.lock.hcl, pois ele fixa as versões dos providers e garante builds consistentes entre máquinas.
Passo 2: declare provider e recursos
Fixe a versão do provider no bloco required_providers. Sem isso, uma atualização inesperada pode alterar o comportamento do plano. Confira na documentação oficial a versão adequada ao seu caso.
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 3.0"
}
}
}
provider "docker" {}
variable "porta_externa" {
type = number
default = 8080
}
resource "docker_image" "web" {
name = "nginx:stable"
}
resource "docker_container" "web" {
name = "web"
image = docker_image.web.image_id
ports {
internal = 80
external = var.porta_externa
}
}
Perceba a natureza declarativa: você descreve o resultado esperado, e o Terraform calcula o grafo de dependências e a ordem de criação. Trocar o provider por um de cloud pública muda os tipos de recurso, mas o fluxo de trabalho continua o mesmo.
Passo 3: configure o state remoto
O state é o mapa entre o que está no código e o que existe de fato. Mantê-lo apenas na sua máquina é o erro mais comum em quem começa com infraestrutura como código: ele se perde, diverge e impede o trabalho em equipe.
terraform {
backend "s3" {
bucket = "meu-bucket-de-state"
key = "projeto/terraform.tfstate"
region = "us-east-1"
}
}
Use um backend remoto com criptografia e controle de acesso, e habilite o bloqueio (locking) conforme o suporte do backend escolhido. O state pode conter dados sensíveis, então trate-o como um segredo: acesso restrito e versionamento do bucket.
Passo 4: execute o ciclo init, plan e apply
- terraform init: baixa providers e configura o backend.
- terraform fmt -check e terraform validate: verificam formatação e consistência.
- terraform plan -out=tfplan: mostra o que será criado, alterado ou destruído.
- terraform apply tfplan: aplica exatamente o plano revisado.
Leia o plano com atenção, principalmente linhas marcadas para destruição ou recriação (forced replacement). Em recursos com dados, como bancos e volumes, uma recriação acidental pode significar perda de informação.
Passo 5: automatize em pipeline de CI
O ganho real aparece quando ninguém aplica mudanças do próprio notebook. Rode o plan em cada pull request e o apply somente após merge na branch principal, de preferência com aprovação manual para produção.
name: terraform
on:
pull_request:
push:
branches: [main]
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
- run: terraform fmt -check
- run: terraform validate
- run: terraform plan -no-color
Guarde credenciais nos secrets do repositório ou, melhor, use autenticação federada (OIDC) com o provedor de cloud, evitando chaves de longa duração. O mesmo raciocínio de pipeline se aplica a deploys de aplicação; se você roda cargas em cluster, vale ler também o comparativo Orquestração de containers: Kubernetes, Swarm ou Nomad?.
Trade-offs que você precisa conhecer
Nenhuma ferramenta resolve tudo. Antes de padronizar a infraestrutura como código no time, considere os pontos abaixo.
- Drift: alterações manuais no console fazem a realidade divergir do código. Use
terraform planperiódico para detectar e restrinja permissões de escrita manual. - Gestão do state: é um ponto único de falha e de risco de segurança. Backup, locking e controle de acesso são obrigatórios.
- Curva de aprendizado: HCL é simples, mas modelar redes, IAM e dependências exige disciplina.
- Modularização: módulos reduzem repetição, mas módulos demais dificultam depuração.
- Escopo: Terraform provisiona recursos; configuração interna de servidores costuma pedir ferramentas como Ansible ou imagens pré-construídas.
Em times pequenos, a decisão de quem mantém essa camada também importa. Se você está pesando entre terceirizar ou internalizar, o framework de outsourcing de desenvolvimento ou time interno ajuda a estruturar o raciocínio.
Boas práticas para evoluir
- Separe states por ambiente e por domínio (rede, dados, aplicação) para limitar o raio de impacto.
- Rode ferramentas de análise estática de segurança sobre o código antes do apply.
- Use
prevent_destroyem recursos críticos. - Documente variáveis com
descriptione valide entradas com blocosvalidation.
Conclusão
Adotar infraestrutura como código não é instalar uma ferramenta, é mudar o processo: tudo versionado, revisado e aplicado por pipeline. Comece pequeno, com um ambiente, state remoto e um fluxo de plan em pull request. Depois que isso estiver estável, evolua para módulos, múltiplos ambientes e verificações de segurança automatizadas.