Cada ferramenta abordada nesta seção - Ansible, Pulumi, Terraform encapsulado em Python, ou um script boto3 desenvolvido internamente - é julgada pelo mesmo modelo subjacente, quer sua documentação diga isso explicitamente ou não.
Esse modelo é infraestrutura declarativa: você descreve o que deve existir, um processo de reconciliação compara essa descrição com o que realmente existe, e apenas a diferença é tratada.
Esta é uma forma diferente de programar do que a maioria dos engenheiros aprende inicialmente, onde o código é uma sequência de passos executados em ordem, e tornar-se confortável com a mudança é o que realmente torna os playbooks do Ansible, os programas Pulumi e os planos do Terraform previsíveis em vez de misteriosos.
Ferramentas de infraestrutura declarativa pegam uma descrição do estado desejado e reconciliam a infraestrutura real em direção a ele, em vez de executar uma sequência fixa de passos imperativos.
Por que Importa: Scripts imperativos ("crie isso, depois aquilo") falham imprevisivelmente em reexecuções e após falhas parciais; a reconciliação declarativa é projetada para ser reexecutada com segurança a partir de qualquer ponto de partida.
Conceitos Chave:estado desejado, idempotência, loop de reconciliação, drift, arquivo de estado, plan/apply.
Quando Usar: Qualquer infraestrutura que será criada mais de uma vez, tocada por mais de uma pessoa, ou que precise convergir após falha parcial - o que na prática significa quase toda infraestrutura real além de um protótipo solo.
Limitações / Trade-offs: Ferramentas declarativas trocam controle processual granular por previsibilidade, e introduzem uma nova superfície de falha própria - drift do arquivo de estado, bloqueio e staleness do plan/apply.
Tópicos Relacionados: gerenciamento de configuração, GitOps, provisionamento de nuvem, política-como-código.
Um script imperativo diz ao computador exatamente o que fazer, em ordem: crie este bucket, então anexe esta política, então crie esta fila.
Execute-o duas vezes e a segunda execução geralmente falha, porque o bucket já existe e a maioria das APIs rejeita uma chamada de criação duplicada diretamente.
Uma ferramenta declarativa, em vez disso, pede para você descrever o estado final que deseja - "este bucket deve existir, com versionamento ativado" - e deixa a sequenciação e o tratamento de duplicatas para a própria ferramenta.
Idempotência é a propriedade que torna isso seguro: uma operação idempotente produz o mesmo resultado final quer seja executada uma ou dez vezes, então reexecuções após uma falha, um soluço de rede, ou uma nova tentativa de CI nunca são destrutivas por padrão.
O mecanismo por trás da idempotência é um loop de reconciliação: lê o estado atual do mundo real, compara-o com o estado desejado declarado, calcula a diferença, e age apenas sobre essa diferença.
Se o bucket já existe com versionamento ativado, o loop de reconciliação não vê diferença e não faz nada - esse comportamento de "no-op na reexecução" é a assinatura prática de um sistema corretamente idempotente.
Uma analogia simples: um termostato não executa "ligue o aquecedor por exatamente 4 minutos" como um script fixo.
Ele compara continuamente a temperatura atual do ambiente com a temperatura alvo e age apenas sobre a lacuna, que é por isso que funciona corretamente independentemente da temperatura inicial do ambiente.
Ansible, Pulumi e Terraform (com ou sem um wrapper Python) são todas implementações dessa mesma ideia de reconciliação, diferindo principalmente em onde elas mantêm seu registro do estado atual e como elas expressam o estado desejado em código.
O loop de reconciliação precisa de duas entradas para calcular uma diferença: o estado desejado (seu código) e um registro do estado atual.
As ferramentas diferem acentuadamente em como obtêm a segunda entrada, e essa diferença explica a maioria de suas peculiaridades comportamentais.
Terraform e Pulumi mantêm um arquivo de estado explícito - um registro serializado de cada recurso que a ferramenta acredita ter criado e seus últimos atributos conhecidos - e eles comparam seu código com esse arquivo, não necessariamente com a infraestrutura ao vivo, a menos que uma etapa de atualização (refresh) seja executada primeiro.
Ansible, por outro lado, é majoritariamente sem estado: cada tarefa consulta diretamente o alvo ao vivo (este arquivo está presente, este pacote está instalado) e só então decide se age, que é por que os playbooks do Ansible tendem a ser naturalmente idempotentes por tarefa sem um arquivo de estado separado para gerenciar.
Essa distinção é a fonte mais comum de confusão para engenheiros que mudam entre ferramentas: "drift" no Terraform significa que o arquivo de estado discorda da infraestrutura real (alguém mudou algo no console), enquanto "drift" no Ansible significa que o alvo ao vivo discorda do estado declarado do playbook, verificado a cada execução.
Plan before apply existe porque uma diferença contra um registro de estado desatualizado ou incompleto pode estar errada, e a etapa de plano é o ponto de revisão humana onde uma ação destrutiva proposta (excluir um recurso com estado, por exemplo) é capturada antes de ser executada.
# A forma da reconciliação, independente da API de qualquer ferramenta específicadef reconcile(desired: dict, get_current: callable, apply_change: callable) -> dict: current = get_current() # lê o estado do mundo real diff = {k: v for k, v in desired.items() if current.get(k) != v} if diff: apply_change(diff) # age apenas sobre a diferença return {"changed": bool(diff), "delta": diff}
Esta é a forma que toda ferramenta declarativa implementa internamente, seja um binário Go de 500 linhas (Terraform) ou um provedor de recursos Python (Pulumi) - o ponto é o padrão de comparação-então-apenas-delta, não qualquer implementação específica.
Bloqueio (Locking) é o outro detalhe mecânico que vale a pena internalizar: como o arquivo de estado (ou o alvo ao vivo, para Ansible) é compartilhado, aplicaçãos concorrentes de dois engenheiros ou dois trabalhos de CI competindo contra a mesma infraestrutura corromperão ou entrarão em conflito nesse registro compartilhado, a menos que a ferramenta imponha um bloqueio durante a aplicação.
Em escala, o modelo de reconciliação tem que lidar com um caso que a simples analogia do termostato não aborda: falha parcial durante a aplicação, onde alguns recursos em um lote são bem-sucedidos e outros falham.
Uma ferramenta bem comportada deixa o arquivo de estado refletindo exatamente o que foi realmente criado, então a diferença da próxima execução pega corretamente apenas o trabalho restante, em vez de tentar novamente recursos já criados ou ignorar silenciosamente a falha.
Detecção de drift torna-se uma preocupação operacional de primeira classe assim que a infraestrutura é gerenciada por mais de uma equipe ou mais de uma ferramenta - uma mudança manual no console, um script separado usando boto3 diretamente, ou um recurso expirado podem fazer com que os estados declarado e real diverjam silenciosamente, sem nenhum erro até que o próximo plano o apresente como uma mudança inesperada.
Política-como-código estende o portão de plan/apply: em vez de um humano inspecionar uma diferença de texto, uma verificação de política automatizada inspeciona o delta planejado e bloqueia a aplicação se violar uma regra (tags obrigatórias ausentes, um grupo de segurança excessivamente permissivo, um bucket S3 público), transformando a etapa de revisão em um portão testável e repetível em vez de uma decisão manual.
Configurações multi-ambiente (dev, staging, prod) levam o modelo adiante: cada ambiente precisa de seu próprio registro de estado e, muitas vezes, de seus próprios parâmetros de estado desejado, e a disciplina que impede uma aplicação acidental em produção é quase inteiramente sobre manter o estado isolado por ambiente, não sobre o código ser fundamentalmente diferente.
Python entra nesse cenário em dois papéis distintos que valem a pena distinguir: como um runtime IaC de primeira classe (Pulumi, onde Python é a linguagem de estado desejado), ou como uma camada de orquestração em torno do ciclo de plan/apply de outra ferramenta (um script que executa terraform plan, verifica a política e condicionalmente executa terraform apply) - o modelo de reconciliação subjacente é idêntico de qualquer forma.
Abordagem
Força
Fraqueza
Melhor Ajuste
Script boto3 imperativo
Controle total, sem ferramentas extras
Não idempotente por padrão, sem detecção de drift, sem etapa de plano
Tarefas únicas pequenas, scripts de cola
Ansible
Sem agente, naturalmente idempotente por tarefa, sem arquivo de estado para gerenciar
Grafo de dependência embutido mais fraco entre recursos do que Terraform/Pulumi
Gerenciamento de configuração, convergência ad-hoc
Terraform (HCL ou via wrapper Python)
Modelo de estado maduro, vasto ecossistema de provedores, fortes diffs de plano
HCL é uma linguagem separada para aprender (a menos que encapsulado)
Multi-cloud, IaC padrão de organização com portões de plano rigorosos
Pulumi (Python nativo)
Linguagem de programação real - loops, funções, testes
Ecossistema de provedores menor que Terraform em algumas áreas
Equipes que desejam IaC como código Python genuíno e testável
"Declarativo apenas significa usar YAML ou um arquivo de configuração em vez de um script." O formato do arquivo é incidental; o que importa é se um loop de reconciliação compara o estado desejado com o estado atual, em vez de um script simplesmente executando passos em ordem, independentemente do que já existe.
"Idempotente significa que a operação é somente leitura ou inofensiva." Operações idempotentes podem absolutamente criar, modificar ou excluir recursos - a garantia é apenas que repetir a mesma operação não produz um resultado final diferente ou duplicado.
"Se o plano do Terraform não mostra mudanças, a infraestrutura definitivamente corresponde ao código." O plano apenas compara o código com o arquivo de estado; se alguém mudou o recurso real fora do Terraform e nenhuma atualização foi executada, o próprio arquivo de estado pode estar desatualizado, mesmo que o plano pareça limpo.
"Ansible não tem estado, então não pode detectar drift." Ansible verifica o estado ao vivo em cada execução de tarefa em vez de um registro em cache, que é um mecanismo diferente para o mesmo objetivo, não uma ausência de consciência de estado.
"Plan e apply são apenas um diálogo de confirmação." A etapa de plano é um cálculo completo da diferença real contra um snapshot de estado específico; tratá-lo como um carimbo de borracha ignora o único local onde mudanças destrutivas são visíveis antes de serem executadas.
O que exatamente significa "idempotente" para código de infraestrutura?
Executar a mesma declaração duas vezes produz o mesmo estado final em ambas as vezes.
A segunda execução deve relatar "sem mudanças" se nada realmente mudou.
Não significa que a operação é segura ou reversível - apenas que a repetição não duplica ou corrompe o resultado.
Por que Terraform e Pulumi precisam de um arquivo de estado?
As APIs de nuvem geralmente não podem responder "quais recursos meu código criou", apenas "o que existe". O arquivo de estado é o próprio registro da ferramenta que vincula as declarações de recursos do seu código aos IDs de recursos reais, que é o que torna possíveis diffs precisos e atualizações direcionadas.
O Ansible tem um equivalente a um arquivo de estado do Terraform?
Não por padrão - a maioria dos módulos Ansible consulta o alvo ao vivo diretamente em cada execução em vez de consultar um registro em cache, que é por que os playbooks Ansible são naturalmente idempotentes por tarefa sem gerenciamento de estado separado.
O que é drift de infraestrutura, mecanicamente?
Drift é qualquer lacuna entre o estado que uma ferramenta acredita existir (seu arquivo de estado, para Terraform/Pulumi, ou o alvo ao vivo, para Ansible) e o que está realmente implantado - comumente causado por mudanças manuais no console ou por uma segunda ferramenta modificando os mesmos recursos.
Por que "plan before apply" é considerado tão importante?
A etapa de plano calcula e exibe a diferença exata que a aplicação atuará, que é o único ponto onde uma revisão humana ou de política automatizada pode detectar uma mudança destrutiva inesperada (como a exclusão acidental de um recurso) antes que ela aconteça.
Como o Pulumi difere do Terraform se ambos são declarativos?
Pulumi expressa o estado desejado como Python nativo (ou outra linguagem de propósito geral) com loops, condicionais e funções reais; Terraform usa sua própria linguagem HCL, embora CDKTF permita gerar configuração Terraform a partir de Python como uma camada sobre ela.
Posso escrever código de infraestrutura idempotente sem nenhuma ferramenta IaC?
Sim - um script boto3 que verifica a existência antes de criar, e verifica a configuração atual antes de atualizar, é idempotente pela mesma definição, apenas sem um arquivo de estado compartilhado ou uma etapa de plano.
O que acontece se uma aplicação falhar no meio do caminho?
Um modelo de estado corretamente implementado registra exatamente quais recursos foram bem-sucedidos antes da falha, então a diferença da próxima aplicação visa apenas os recursos restantes, ainda não criados - este é um dos principais benefícios práticos do modelo de reconciliação sobre um script linear.
Por que as equipes adicionam verificações de política sobre plan/apply?
Porque um humano revisando uma grande diferença de plano pode perder um problema sutil, mas importante (um bucket público, uma tag ausente); uma verificação de política automatizada inspeciona a mesma diferença programaticamente e bloqueia a aplicação em violações específicas e definidas.
O bloqueio de estado é realmente necessário para uma equipe pequena?
Torna-se necessário assim que duas pessoas ou dois trabalhos de CI podem executar apply na mesma infraestrutura concorrentemente - sem um bloqueio, ambos podem ler o mesmo estado desatualizado e aplicar mudanças conflitantes.
Como este modelo se relaciona especificamente com ferramentas de gerenciamento de configuração?
Gerenciamento de configuração (Ansible) aplica o mesmo modelo declarativo/idempotente no nível da configuração de uma única máquina (pacotes, arquivos, serviços) em vez do nível de provisionamento de recursos de nuvem inteiros, mas o modelo mental de reconciliação é idêntico.
Qual é o maior risco prático do modelo declarativo?
Tratar o arquivo de estado (ou a verificação do alvo ao vivo, para Ansible) como infalível - se ele sair de sincronia com a realidade e ninguém perceber, a diferença do próximo plano pode estar perigosamente errada, propondo "corrigir" algo que um humano mudou intencionalmente fora de banda.