Infraestrutura como Código: Por Que o Terraform Mudou o Jogo
Estado, plano e reconciliação declarativa: entenda os conceitos que fazem a infraestrutura como código funcionar, e as armadilhas do state e do drift.
Neste artigo
Durante décadas, provisionar infraestrutura foi um trabalho manual e artesanal. Alguém abria o console do provedor, clicava para criar um servidor, configurava a rede na mão, ajustava regras de firewall uma a uma. Funcionava até parar de funcionar, e parava sempre pelos mesmos motivos: ninguém lembrava exatamente o que tinha sido feito, o ambiente de produção divergia do de homologação de formas misteriosas, recriar tudo do zero após um desastre era uma odisseia de dias, e cada mudança era uma oportunidade de erro humano sem registro.
A infraestrutura como código, ou IaC, resolve isso com uma ideia simples e poderosa: descrever toda a infraestrutura em arquivos de texto, versionados como qualquer outro código, e deixar uma ferramenta aplicar essa descrição ao mundo real. O Terraform é a ferramenta que popularizou essa abordagem e continua sendo a referência para entender os conceitos, que valem para qualquer ferramenta da categoria. Este artigo trata desses conceitos, não da sintaxe: o que faz IaC funcionar, e as armadilhas que derrubam quem adota sem entender.
Declarativo, de novo: descrever em vez de mandar#
Assim como o Kubernetes, o Terraform é declarativo. Você não escreve um roteiro de passos ("crie a rede, depois o servidor, depois o banco"). Você descreve o estado final desejado ("quero esta rede, este servidor e este banco existindo, com estas propriedades"), e a ferramenta descobre sozinha o que precisa fazer para chegar lá a partir do que existe hoje.
A diferença é a mesma que separa dar um endereço de destino de ditar cada curva do caminho. Se você descreve o destino, a ferramenta calcula a rota a partir de onde você está. Se já existe metade da infraestrutura, ela cria só a outra metade. Se nada existe, ela cria tudo. Se você mudar uma propriedade, ela altera apenas o que mudou. Você nunca escreve a lógica de "verificar se já existe antes de criar"; essa comparação é o trabalho da ferramenta.
Essa é a fonte da propriedade mais valiosa da IaC: a idempotência. Aplicar a mesma descrição dez vezes seguidas produz o mesmo resultado que aplicar uma. Na primeira vez, a infraestrutura é criada; nas seguintes, nada muda porque a realidade já bate com a declaração. Não há efeito colateral acumulado, não há duplicação. Isso torna a IaC segura de rodar repetidamente, o que é a base para automatizá-la em pipelines.
O state: o mapa entre código e mundo real#
Aqui entra o conceito mais importante e mais mal compreendido do Terraform: o state, ou estado.
Para saber o que precisa mudar, o Terraform precisa saber o que ele já criou. Ele não descobre isso escaneando o provedor toda vez, o que seria lento e ambíguo. Ele mantém um arquivo de estado, um registro de tudo que gerencia e do mapeamento entre os recursos descritos no seu código e os recursos reais no provedor. Quando você declara um servidor com um certo nome no código, o state guarda que esse nome corresponde àquele servidor específico, com aquele identificador, no provedor.
O state é o que permite ao Terraform fazer três coisas. Ele sabe quais recursos ele gerencia, distinguindo o que é dele do que existe por outros meios. Ele sabe o mapeamento entre a abstração no código e o recurso concreto, para poder alterá-lo em vez de recriá-lo. E ele guarda metadados que aceleram operações e resolvem dependências.
O state é também a maior fonte de dor de quem usa Terraform, por dois motivos. Primeiro, ele é sensível: costuma conter valores que vazaram dos recursos, inclusive segredos, o que significa que o arquivo de state precisa ser tratado como confidencial, nunca commitado no repositório em texto plano. Segundo, quando várias pessoas ou pipelines operam a mesma infraestrutura, dois apply simultâneos sobre o mesmo state o corrompem. A solução para os dois problemas é o remote state: guardar o estado num backend remoto compartilhado, cifrado, com state locking, um mecanismo que trava o state durante uma operação para impedir que outra rode ao mesmo tempo. Rodar Terraform sério em equipe sem remote state com lock é convite ao desastre.
O plano: ver antes de aplicar#
Uma das práticas que mais reduz o risco em IaC é a separação entre planejar e aplicar. O Terraform materializa isso em dois comandos, e a disciplina em torno deles é o que torna mudanças de infraestrutura seguras.
O plan calcula e mostra o que aconteceria se você aplicasse a descrição atual, sem tocar em nada. Ele compara três coisas: o que o código declara, o que o state diz que existe, e opcionalmente o que o provedor realmente tem. Dessa comparação sai um relatório: estes recursos serão criados, estes serão alterados assim, estes serão destruídos. É a chance de revisar a intenção antes de executá-la.
Prestar atenção ao plan não é opcional; é a barreira que separa uma mudança tranquila de um incidente. Uma linha aparentemente inofensiva no código pode gerar um plan que destrói e recria um banco de dados, porque alterou uma propriedade que o provedor não permite mudar sem recriar. O plan mostra isso em vermelho antes de qualquer estrago. Ignorá-lo e aplicar direto é como assinar um contrato sem ler. O hábito saudável é gerar o plan, revisá-lo com olhos críticos (especialmente o que será destruído), e só então aplicar exatamente aquele plan revisado.
Drift: quando a realidade foge do código#
O maior inimigo silencioso da IaC é o drift, a divergência entre o que o código descreve e o que realmente existe na infraestrutura. O drift acontece quando alguém altera a infraestrutura por fora do Terraform: entra no console do provedor e muda uma configuração na mão, tipicamente sob pressão de um incidente.
O drift corrói a promessa central da IaC, que é o código ser a fonte da verdade. Se alguém mudou uma regra de firewall pelo console, o código não reflete mais a realidade, e o próximo apply do Terraform, ao ver a divergência, vai desfazer a mudança manual para restaurar o que o código diz, possivelmente reabrindo o problema que a mudança manual resolveu, ou pior. O drift transforma a ferramenta de aliada em fonte de surpresas.
A disciplina que evita drift é inegociável: toda mudança de infraestrutura passa pelo código. Nada de ajustes manuais no console em produção, nem mesmo em emergências, porque a emergência de hoje vira o incidente de amanhã quando o Terraform desfizer a correção. Se um ambiente precisa ser tratado assim, o acesso de escrita manual deve ser fechado por padrão, liberado apenas com auditoria. Detectar drift também vale: rodar plan periodicamente sem aplicar mostra se a realidade divergiu, funcionando como um alarme de que alguém mexeu por fora.
Módulos: infraestrutura que se reutiliza#
À medida que a infraestrutura cresce, copiar e colar blocos de configuração vira insustentável. A resposta é a modularização. Um módulo é um pedaço de infraestrutura empacotado e parametrizado, que pode ser reutilizado em vários lugares com valores diferentes.
O ganho é o mesmo de funções na programação. Em vez de repetir a descrição de um ambiente de aplicação em dez lugares, você define um módulo uma vez, expõe as variáveis que mudam entre os usos, e o instancia com valores distintos para produção, homologação e desenvolvimento. Corrigir um problema no módulo corrige em todos os usos. Padrões da empresa, como a forma certa de configurar rede segura ou um banco com backup, viram módulos reutilizáveis que carregam as boas práticas embutidas, de modo que quem usa herda o acerto sem precisar reinventá-lo.
Bons módulos têm interfaces bem definidas: entradas claras, saídas úteis, e nenhuma suposição escondida sobre o ambiente. Módulos mal desenhados, com dependências implícitas e configuração espalhada, viram armadilhas piores que a duplicação que tentavam evitar. A regra é a mesma da boa engenharia de software: coesão alta, acoplamento baixo, interface explícita.
Testar infraestrutura e revisar como código#
Uma vez que a infraestrutura vira código versionado, ela herda as práticas que amadureceram no desenvolvimento de software, e ignorá-las é desperdiçar metade do valor da IaC. A primeira é a revisão por pares. Uma mudança de infraestrutura deve passar por um pull request, com o plan anexado, revisado por outra pessoa antes de ser aplicada. O revisor olha não só o código mas o plan que ele gera, especialmente o que será destruído, funcionando como uma segunda barreira contra o apply desastroso. Produção deixa de ser mudada por alguém sozinho num terminal e passa a exigir aprovação rastreável.
A segunda é a validação automática no pipeline. Antes de qualquer aplicação, é possível checar a formatação do código, validar a sintaxe, e rodar análise estática que pega problemas comuns e mesmo questões de segurança, como um bucket de armazenamento configurado como público sem intenção, ou uma regra de firewall aberta demais. Essas verificações rodam em segundos e barram classes inteiras de erro antes que cheguem ao provedor.
A terceira, mais avançada, é o teste de infraestrutura de verdade: provisionar os recursos num ambiente descartável, verificar que ficaram como esperado, e destruir tudo em seguida. É mais caro e mais lento que os testes de software comuns, porque envolve criar recursos reais, mas para módulos reutilizáveis de alto impacto, que serão usados em muitos lugares, esse investimento se paga ao pegar regressões antes que se propaguem. Infraestrutura como código só entrega sua promessa completa quando é tratada com o mesmo rigor de qualquer outro código: revisada, validada e, quando faz sentido, testada.
IaC além do Terraform, e o passo seguinte#
Vale um contexto para não confundir categorias. O Terraform faz provisionamento: cria e gerencia a infraestrutura de base, servidores, redes, bancos, balanceadores. Ferramentas de gerenciamento de configuração, de outra família, cuidam de configurar o que roda dentro dessas máquinas, instalando pacotes e ajustando arquivos. E orquestradores de container tratam do ciclo de vida das aplicações. As três camadas se complementam, e é comum uma organização usar uma de cada. Entender qual problema cada uma resolve evita a tentação de forçar uma ferramenta a fazer o trabalho de outra.
A infraestrutura como código muda o jogo porque transforma infraestrutura em algo que se versiona, se revisa, se testa e se recria. Um desastre que antes custava dias de reconstrução manual vira um apply a partir do código versionado. Uma diferença misteriosa entre ambientes vira um diff entre arquivos. Uma mudança arriscada vira um plan revisado antes de aplicar. A infraestrutura deixa de ser um artesanato frágil e vira um artefato de engenharia.
O destino natural dessa jornada é fechar o ciclo com automação de reconciliação contínua: o código no repositório sendo a única fonte da verdade e um agente garantindo que a realidade sempre a honre, sem ninguém rodar apply na mão. Esse é o território do GitOps como modelo de entrega, que aplica à operação os mesmos princípios que a IaC trouxe para o provisionamento. Mas o alicerce é sempre o mesmo: descrever o desejado, versionar a descrição, e deixar a ferramenta reconciliar a realidade com ela.