Todo recurso de cloud que você já criou clicando em um console web (uma VM, um load balancer, um registro DNS) também pode ser descrito em um arquivo de texto e criado com um único comando. O arquivo vive no git, passa por uma pull request e reproduz o mesmo setup em uma segunda conta sem que ninguém precise lembrar quais das nove configurações foram alteradas na mão. É isso que o Terraform faz.
O que o Terraform realmente faz
Terraform é uma ferramenta open-source da HashiCorp que transforma infraestrutura em arquivos de configuração, escritos em HCL (HashiCorp Configuration Language), e os aplica contra a API de um provedor de cloud. Você escreve um bloco resource descrevendo o bucket S3, a instância EC2 ou o registro DNS da Cloudflare que quer, roda terraform apply, e o Terraform calcula as chamadas de API necessárias para que esse recurso exista — depois passa a rastreá-lo, de modo que um segundo apply só muda o que realmente mudou.
O modelo é declarativo, não procedural: você descreve o estado final, não os passos para chegar até ele. Você não escreve “crie um bucket, depois defina sua policy, depois ative o versioning”. Você escreve como o bucket deve ficar, e o Terraform calcula a ordem das operações, incluindo o que precisa existir primeiro quando um recurso depende de outro.
O Terraform sozinho não sabe nada sobre AWS, Azure ou Cloudflare. Esse conhecimento vive nos providers: plugins que traduzem blocos HCL em chamadas contra uma API específica. O Terraform Registry lista milhares deles, oficiais e mantidos pela comunidade, cobrindo desde as três grandes clouds até configurações de repositório do GitHub e monitores do Datadog. O mesmo mecanismo cria um cluster Kubernetes gerenciado (google_container_cluster, aws_eks_cluster) ou um único registro DNS na frente de um CDN. Se um serviço tem uma API, é bem provável que alguém já tenha escrito um provider para ele.
Como funcionam terraform plan e apply
Um diretório de trabalho mínimo tem pelo menos dois arquivos.
| |
| |
Quatro comandos cobrem o ciclo de trabalho do dia a dia:
| |
terraform init lê required_providers e baixa os binários dos plugins correspondentes para dentro de .terraform/. Você roda uma vez por diretório, e de novo sempre que adicionar um provider ou um módulo.
terraform plan é o comando que você vai usar com mais frequência. Ele compara seus arquivos .tf, o state registrado e a infraestrutura real como reportada pela API do provider, e então imprime um diff: recursos a criar (+), alterar (~) ou destruir (-). Nada acontece ainda. É isso que torna seguro apontar o Terraform para produção — você lê o plan antes de qualquer coisa ser tocada.
terraform apply roda o plan de novo, mostra ele outra vez e espera você digitar yes antes de chamar as APIs do provider na ordem de dependência correta. No CI você passa -auto-approve ou, melhor, aplica um arquivo de plan que já revisou: terraform apply tfplan. O mesmo pipeline que roda Construir e Publicar uma Imagem Docker com GitHub Actions a cada merge pode rodar terraform plan em uma pull request e terraform apply assim que ela é mergeada na main.
Para que serve o state file
Depois do primeiro apply, o Terraform escreve terraform.tfstate — um arquivo JSON que mapeia cada recurso da sua configuração ao objeto real que criou, ID incluído. Isso não é burocracia opcional. É assim que o plan sabe o que já existe sem re-escanear toda a sua conta AWS a cada execução, e é assim que o Terraform conecta aws_s3_bucket.reports no seu código ao bucket acme-monthly-reports-a8f3 na realidade.
Daí seguem duas consequências diretas.
O state pode conter segredos. Uma senha de banco de dados definida como argumento de um recurso acaba em texto puro no arquivo de state, porque o Terraform precisa dos atributos completos do recurso para detectar drift. Nunca faça commit de terraform.tfstate no git.
O state precisa ser compartilhado e travado. O padrão é um arquivo local, que funciona sozinho e quebra no momento em que uma segunda pessoa roda apply do próprio laptop: agora há duas fontes de verdade. A solução é um backend remoto, com o state guardado em S3, Azure Blob, GCS ou Terraform Cloud, com um lock que impede que dois apply corram ao mesmo tempo.
| |
use_lockfile é o locking nativo do backend S3, disponível de forma estável desde o Terraform 1.11 — ele escreve um arquivo de lock direto no bucket, então nas versões atuais não é mais preciso ter uma tabela DynamoDB dedicada ao locking.
Assim que o time aponta para o mesmo backend, o plan de cada um reflete o último apply de todos os outros.
Como reutilizar uma configuração com variáveis e módulos
Deixar eu-west-1 e um nome de bucket fixos no código funciona para um exemplo de cinco linhas, não para um ambiente real. O Terraform separa a forma da infraestrutura dos valores que mudam por ambiente.
| |
| |
| |
Ou coloque os valores em um arquivo terraform.tfvars para não redigitar as flags a cada execução. O outputs.tf faz o caminho inverso. Ele expõe um valor calculado pelo Terraform, como o IP público de uma instância ou uma ARN gerada, para que outra ferramenta ou outra configuração Terraform possa consumi-lo:
| |
Quando um conjunto de recursos se repete entre projetos (uma VPC padrão, uma stack de web-app padrão), você o encapsula em um módulo: um diretório de arquivos .tf referenciado com um argumento source, que recebe inputs e devolve outputs como uma função. A maioria dos times acaba com um punhado de módulos internos e muitas configurações enxutas que os chamam com variáveis diferentes.
Quando o Terraform é a ferramenta errada
O Terraform provisiona recursos; ele não configura o que roda neles. Ele vai criar uma instância EC2, mas instalar pacotes, gerenciar usuários e manter a configuração sincronizada nessa instância é um trabalho diferente — tradicionalmente do Ansible, de um script cloud-init, ou de uma imagem de container que a instância baixa e executa. Passar a configuração da aplicação pelo Terraform é a direção errada. Criar a VPC pelo Ansible é a outra direção errada. A maioria dos setups reais usa os dois, e o Terraform repassa o IP da instância direto para o inventory do Ansible via um output.
Para um bucket que você vai apagar em uma hora, ou uma VM de teste descartável, o arquivo de state e o ciclo escrever-plan-apply custam mais do que economizam. A CLI da AWS ou o console são mais rápidos para algo que você não pretende manter nem reproduzir.
Terraform, OpenTofu e Pulumi
O Terraform não é mais a única ferramenta que lê HCL. A HashiCorp o moveu da licença open-source MPL para a Business Source License em 2023, e a Linux Foundation agora mantém o OpenTofu, um fork que manteve a licença MPL e ficou compatível com a sintaxe HCL e o formato de state do Terraform. Trocar depois é uma mudança de configuração, não uma reescrita.
O Pulumi vai na direção oposta: em vez de HCL você escreve a infraestrutura em TypeScript, Python ou Go. Isso importa se o seu time quer controle de fluxo de verdade e testes unitários sobre a lógica de infraestrutura em vez das expressões mais limitadas do HCL.
Como testar o Terraform sem uma conta cloud
A rede de segurança do Terraform é o plan, e você pode exercitar o ciclo inteiro de graça antes de apontá-lo para algo cobrável. Os providers random e local não pedem nenhuma credencial de cloud.
| |
Você roda terraform init e terraform apply em um diretório vazio e ganha um state file real e um recurso gerenciado real, sem nada a pagar. Faça isso uma vez, leia a saída do plan linha por linha até os símbolos +, ~ e - fazerem sentido para você, e então aponte os mesmos quatro comandos para um provider que cobra por hora.