Software · Computação em Nuvem & DevOps
Infraestrutura como Código: Estado Declarativo, Idempotência e Terraform
Como eliminar o provisionamento manual por consoles, garantir idempotência em topologias de nuvem e gerenciar estado e drift com Terraform.
Neste artigo
Nos primórdios da computação em nuvem, a criação de ambientes corporativos dependia quase exclusivamente de ações manuais em consoles gráficos (o pejorativamente chamado ClickOps) ou de sequências frágeis de scripts imperativos em Shell ou PowerShell. Essa dependência operacional manual produzia três problemas crônicos para as organizações: deriva de configuração (configuration drift, onde o ambiente de produção gradualmente diverge do ambiente de testes), ausência de rastreabilidade e auditoria (ninguém sabe com precisão quem alterou uma regra de firewall ou quando ela foi modificada) e ambientes irreproduzíveis em cenários de desastre.
A Infraestrutura como Código (IaC - Infrastructure as Code) transformou radicalmente esse paradigma. Ao tratar servidores, redes virtuais, bancos de dados gerenciados e políticas de segurança exatamente como código-fonte de aplicação — versionado no Git, revisado por pares e validado por pipelines automatizados —, a IaC estabeleceu o padrão de ouro para operações modernas de nuvem. Dentre as ferramentas disponíveis, o Terraform consolidou-se como o ecossistema declarativo mais influente da indústria.
O Paradigma Declarativo versus Imperativo
A grande divisão técnica nas ferramentas de automação reside na filosofia de modelagem da infraestrutura:
flowchart LR
subgraph Imperative["IMPERATIVO — descreve como executar"]
direction TB
I1["1. Criar VM"] --> I2["2. Verificar e atualizar IP"] --> I3["3. Criar Security Group"]
I2 -. falha intermediária .-> Drift["Estado inconsistente"]
end
subgraph Declarative["DECLARATIVO — descreve o estado desejado"]
direction TB
Desired["VPC + 2 subnets<br/>cluster Kubernetes com 3 nós"] --> Delta["Motor calcula o delta"] --> Apply["Aplica somente as mudanças necessárias"]
end
classDef imperative fill:#321c24,stroke:#f87171,color:#f8fafc;
classDef declarative fill:#0f2724,stroke:#34d399,color:#f8fafc;
class I1,I2,I3,Drift imperative;
class Desired,Delta,Apply declarative;
| Critério | IaC Declarativa (Terraform, OpenTofu, Bicep) | IaC Imperativa (Scripts Bash, Python, Ansible em modo procedural) |
|---|---|---|
| Foco do Engenheiro | O estado final desejado do ambiente | A sequência cronológica de comandos a executar |
| Idempotência | Nativa. Executar o código dez vezes produz exatamente o mesmo resultado | Exige tratamento manual complexo de checagens condicionais prévias |
| Detecção de Drift | Automática por comparação contra o estado registrado | Difícil ou inexistente sem varreduras customizadas |
| Rollback e Auditoria | Transparente via histórico de commits no repositório | Arriscado e dependente de scripts reversos construídos manualmente |
A Mecânica Interna do Terraform: O Ciclo de Vida
O Terraform opera através de manifestos escritos em HCL (HashiCorp Configuration Language), organizando seu ciclo de execução em quatro fases determinísticas:
flowchart TD
Inputs["Manifestos .tf + provedores de nuvem"] --> Init["terraform init<br/>baixa plugins e provedores"]
Init --> Plan["terraform plan<br/>compara código e infraestrutura real"]
Plan --> Apply["terraform apply<br/>chama APIs para atingir o estado desejado"]
Apply --> State["terraform.tfstate<br/>mapeia recursos e IDs de nuvem"]
classDef input fill:#172033,stroke:#38bdf8,color:#f8fafc;
classDef action fill:#2a1f32,stroke:#a855f7,color:#f8fafc;
classDef state fill:#0f2724,stroke:#34d399,color:#f8fafc;
class Inputs input;
class Init,Plan,Apply action;
class State state;
1. terraform init
Inicializa o diretório de trabalho, baixando os plugins binários dos provedores especificados (como provedores da AWS, Azure, Google Cloud ou Kubernetes) e configurando o backend de estado.
2. terraform plan
Lê o estado atual da infraestrutura em nuvem através de chamadas de leitura às APIs do provedor, compara a realidade encontrada com as definições dos arquivos .tf e apresenta um relatório delta detalhado: o que será criado (+), modificado (~) ou destruído (-). Nenhuma alteração física é feita nesta etapa, proporcionando previsibilidade total ao time.
3. terraform apply
Aplica as mudanças aprovadas de forma programática, respeitando a árvore de dependências do grafo de recursos construído pelo Terraform.
4. terraform destroy
Elimina de forma ordenada todos os recursos declarados nos manifestos, facilitando o encerramento seguro de ambientes efêmeros de teste e homologação.
O Arquivo de Estado (terraform.tfstate) e a Gestão de Concorrência
O arquivo de estado é o componente mais crítico da arquitetura do Terraform. Ele atua como uma fonte única de verdade que mapeia os nomes lógicos de recursos declarados no código aos IDs físicos gerados na nuvem:
- Risco de Segurança: O arquivo de estado pode conter informações confidenciais (como senhas iniciais de bancos de dados geradas pelo provedor). Ele jamais deve ser comitado em repositórios de código Git.
- Backend Remoto e Travamento de Estado (State Locking): Em ambientes corporativos com múltiplos engenheiros e pipelines de CI/CD simultâneos, o estado deve residir em um armazenamento remoto seguro (como um bucket S3 com criptografia ou Azure Blob Storage), acompanhado de um mecanismo de lock transacional (como DynamoDB ou leases de blob). O bloqueio impede que dois pipelines executem
applysimultaneamente, o que corromperia o estado da infraestrutura.
Detecção de Deriva (Drift Detection)
Um dos maiores diferenciais da IaC é a detecção automática de desvios. Se um operador acessar o console web da nuvem de madrugada e alterar manualmente o tamanho de uma máquina virtual ou abrir uma porta no grupo de segurança, a próxima execução de terraform plan identificará a discrepância:
"O recurso
aws_security_group.appsofreu modificação externa fora do Terraform. O plano restaurará a configuração original declarada no repositório."
Dessa forma, o código Git permanece como a autoridade inquestionável sobre o que existe em produção.
Modularização e Segregação de Ambientes
Para evitar arquivos monolíticos gigantescos de milhares de linhas, a engenharia de plataforma estrutura a infraestrutura em módulos reutilizáveis:
infra/
├── modules/
│ ├── vpc-network/ <-- Módulo reutilizável com subnets e gateways
│ ├── database-cluster/ <-- Módulo parametrizado para instâncias de banco
│ └── container-apps/ <-- Módulo para orquestração de containers
└── environments/
├── dev/ <-- Manifestos enxutos chamando os módulos com tiers básicos
├── staging/ <-- Réplica exata com tier intermediário
└── prod/ <-- Configuração de alta disponibilidade e multi-região
Essa separação garante que melhorias e patches de segurança aplicados em um módulo beneficiem todos os ambientes de maneira padronizada e previsível.
Padrões Recomendados para Infraestrutura como Código
Em operações maduras em nuvem, a infraestrutura declarativa é tratada com o mesmo rigor de engenharia do software de aplicação:
- ClickOps Zero em Produção: O acesso de escrita aos consoles de nuvem é bloqueado para contas humanas em ambientes produtivos. Toda e qualquer alteração de infraestrutura é obrigatoriamente submetida via Pull Request no Git e aplicada por pipelines automatizados.
- Varredura Estática de Segurança (Policy as Code): Antes do provisionamento, ferramentas como Checkov e TFSec inspecionam o código HCL em busca de violações de conformidade, como buckets de armazenamento com acesso público, bancos de dados sem criptografia em repouso ou regras de firewall permissivas (
0.0.0.0/0). - Imutabilidade e Destruição Limpa: Priorizamos a infraestrutura imutável: em vez de aplicar patches manuais em servidores vivos, novas versões de infraestrutura são provisionadas paralelamente e o tráfego é comutado de maneira suave via DNS ou balanceadores de carga.