01 - O que é IaC (Infrastructure as Code)
video: https://youtu.be/... no frontmatter da nota.O que é IaC (Infrastructure as Code)
Infrastructure as Code é a prática de descrever infraestrutura, redes, máquinas virtuais, bancos de dados, balanceadores, filas e DNS, em arquivos de código versionados que uma ferramenta interpreta para criar e manter os recursos reais. Em vez de um time executar passos manuais em consoles web, o estado desejado da infraestrutura vive em um repositório Git, passa por revisão de código e é aplicado por ferramentas como Terraform, CloudFormation, Pulumi e Ansible. A prática é pilar da engenharia de produção porque transforma provisionamento, historicamente artesanal e não reproduzível, em processo automatizado, auditável e repetível. É o IaC que permite recriar um ambiente completo em minutos, promover mudanças entre ambientes com a mesma disciplina de um deploy de aplicação e tratar infraestrutura com os padrões de qualidade exigidos do software. Em operações maduras, quase nada em produção nasce de clique manual: tudo o que existe na nuvem tem origem declarada em código, autor identificável e histórico verificável.
Conceito: o estado desejado como artefato
O núcleo do IaC é a separação entre estado desejado e estado real. O código descreve o que deve existir, uma VPC com duas sub-redes, um cluster com cinco nós, um banco com backup semanal, e a ferramenta calcula as operações necessárias para aproximar o mundo real dessa descrição. Esse deslocamento muda a natureza do trabalho de infraestrutura: o time deixa de ser executor de tarefas e passa a ser autor e mantenedor de código que descreve tarefas.
A segunda ideia central é o ciclo de vida de engenharia de software aplicado à infraestrutura: versionamento em Git, branches, pull requests, revisão por pares, pipeline de CI, testes e releases. Uma mudança de rede passa a ter autor, revisor, motivo e rastro documentado, exatamente como uma mudança de código de aplicação. Essa disciplina é o que permite a um time grande operar infraestrutura grande sem depender de coordenação tribal.
A terceira ideia é a homogeneidade de ambientes. Com código compartilhado e parâmetros por ambiente, desenvolvimento, staging e produção divergem apenas pelo que foi explicitamente parametrizado, o que elimina a classe inteira de bugs que existem porque produção foi montada à mão de um jeito diferente. A fidelidade entre ambientes deixa de ser aspiração e vira consequência estrutural do modelo.
O problema que resolve: a infraestrutura manual como dívida
Ambientes construídos manualmente acumulam dívida silenciosa. Cada clique no console é uma decisão não documentada, sem autor, sem revisão e sem possibilidade de reprodução fiel; com o tempo, ninguém sabe por que um security group tem aquela regra, ou por que uma instância roda uma versão de AMI diferente das demais. Servidores configurados à mão tornam-se snowflakes: únicos, frágeis e impossíveis de reconstruir sob pressão.
A dívida manual cobra juros em quatro moedas. Em tempo de recuperação, porque recriar um servidor perdido exige arqueologia; em velocidade de entrega, porque toda mudança depende de alguém disponível que saiba os passos; em confiabilidade, porque passos manuais falham de forma inconsistente; e em risco de segurança, porque exceções criadas no improviso sobrevivem para sempre sem auditoria.
O IaC ataca a raiz do problema. Se a infraestrutura é código, existe fonte de verdade única, o ambiente pode ser recriado do zero, qualquer mudança pode ser revisada antes de acontecer e qualquer recurso pode ser inspecionado. O conhecimento deixa de morar na memória de uma pessoa e passa a morar no repositório, legível e transferível.
Há também um efeito organizacional menos óbvio: o IaC objetiva discussões técnicas. A pergunta "qual é a configuração de produção de hoje?" tem resposta executável em vez de parecer oral, e divergências de projeto se resolvem em pull request, com evidência e contexto, e não em guerra de opiniões.
Declarativo versus imperativo
Ferramentas imperativas descrevem como: uma sequência de comandos executada em ordem, criar VPC, criar subnet, esperar, criar instância. Ferramentas declarativas descrevem o que: o conjunto de recursos com seus atributos finais, e o motor da ferramenta decide a ordem e as operações de criação, alteração e destruição. Terraform, CloudFormation e Pulumi são declarativos; scripts de shell encadeando chamadas de CLI são imperativos.
A diferença não é estética. Num modelo imperativo, rodar o script duas vezes cria recursos duplicados, e atualizar o estado significa descobrir manualmente quais passos ainda faltam. Num modelo declarativo, rodar novamente é inofensivo, e atualizar significa mudar a descrição e reaplicar; a ferramenta compara o desejado com o real e executa apenas o delta.
Scripts imperativos continuam úteis para passos pontuais, como migrações de dados e bootstrap específico, mas não escalam como motor de provisionamento. Muitas ferramentas declarativas aceitam pequenos trechos imperativos no caminho principal, provisioners e user data, e é uma fronteira conhecida: quanto mais lógica imperativa entra no fluxo principal, menores a repetibilidade e a previsibilidade do provisionamento.
Idempotência: a propriedade que sustenta o modelo
Idempotência é a propriedade de uma operação que produz o mesmo resultado independentemente de quantas vezes seja executada. Em IaC, significa que aplicar o mesmo código duas vezes não duplica nem corrompe nada: a segunda execução constata que o mundo já está conforme e não faz nada. Sem idempotência, automação vira aposta; com ela, convergência de estado vira rotina segura.
A propriedade opera em dois níveis. No nível do motor declarativo, o comparativo entre estado desejado e estado real garante que operações só acontecem quando há diferença. No nível de cada recurso, o tipo de recurso define o que é atualização e o que exige recriação: alterar uma tag de uma instância EC2 é operação in-place, alterar o AMI de um Auto Scaling Group normalmente implica substituição controlada.
Idempotência também é exigência das ações de configuração embutidas no fluxo. Um playbook Ansible precisa poder rodar em cron sem acumular efeitos; regras de firewall adicionadas sem verificação de existência são o antiexemplo clássico que gera listas com milhares de entradas duplicadas. Em produção, todo passo automatizado deve responder com segurança à pergunta: o que acontece se rodar de novo?
Funcionamento interno: o motor de convergência
Todo motor declarativo segue a mesma sequência interna. Primeiro lê o estado registrado da última execução; depois consulta os provedores para obter as propriedades reais de cada recurso, o chamado refresh; em seguida compara o desejado com o real e calcula o delta; por fim executa as operações na ordem que o grafo de dependências exige e grava o novo estado. A execução é paralela onde o grafo permite, com paralelismo limitado por configuração.
O grafo de dependências é o que dá previsibilidade ao modelo. Recursos são nós, referências entre recursos são arestas, e a execução respeita a ordenação topológica: um banco só nasce depois da subnet que o hospeda, e um DNS só aponta depois do load balancer existir. A destruição segue o caminho inverso, o que explica por que remover um ambiente inteiro na ordem certa é mecânico e não artesanal.
Falhas parciais são tratadas como estado, não como exceção fatal. Se a execução morre no meio, o state registra o que já convergiu, e a próxima execução retoma apenas o que falta; por isso o state é o ativo mais crítico de uma operação de IaC, e sua proteção é tema de arquivo próprio neste módulo.
Drift: a divergência entre código e realidade
Drift é o desvio entre o que o código declara e o que a infraestrutura realmente é, causado por mudanças fora do fluxo: um ajuste de emergência no console, um patch aplicado via SSH, um recurso criado por outra equipe. Toda mudança manual em produção cria drift por definição, mesmo quando tecnicamente necessária, e o drift acumulado corrói a confiança no código até ele deixar de representar a realidade.
O risco operacional do drift é sutil: a próxima execução do IaC pode reverter sem aviso aquele ajuste de emergência que estabilizou o sistema, porque para o código aquilo é divergência indesejada. Por isso mudanças manuais de emergência exigem política explícita de reconciliação: o código é atualizado logo após o incidente para refletir a mudança, ou a mudança é revertida assim que a correção definitiva entrar pelo fluxo normal.
Ferramentas modernas oferecem detecção dedicada: terraform plan expõe divergências entre state e realidade, e o CloudFormation tem drift detection nativo por recurso. A prática saudável executa a detecção em intervalo regular e trata divergência como incidente a classificar, não como curiosidade; regras de acesso que restringem escrita no console para recursos gerenciados por IaC reduzem o drift na fonte.
# Detecção rotineira de drift em produção
terraform plan -detailed-exitcode \
-out=drift.tfplan # exit code 2 indica divergência detectada
aws cloudformation detect-stack-drift \
--stack-name producao-core # marca recursos fora do template
O ciclo plan e apply
O ciclo operacional canônico do IaC declarativo tem duas fases explícitas. Na fase plan, a ferramenta lê o código, lê o estado atual e consulta os provedores para calcular um plano: o conjunto exato de operações que serão executadas, criar, alterar, destruir ou substituir. Na fase apply, o plano é executado. O plano é o contrato de segurança da prática: nada muda no mundo real sem antes existir um documento revisável do que vai mudar.
O ciclo se integra ao Git de forma natural. O pull request carrega o plano gerado pela mudança proposta, o revisor valida não apenas o código, mas o efeito concreto sobre a infraestrutura, e o apply é disparado pela pipeline após a aprovação. Esse é o padrão GitOps para infraestrutura, e ele transforma cada mudança de produção em evento rastreável de ponta a ponta, com autor, revisor e plano arquivados.
O plano também é a base da automação de gate. Filtros sobre o plano, como bloquear apply quando existem recursos marcados como destruição ou substituição, permitem políticas de segurança automatizadas; ferramentas de policy as code, OPA e Sentinel, operam exatamente sobre esse artefato para proibir, por exemplo, buckets públicos ou portas abertas para o mundo.
# Exemplo mínimo em Terraform: descrição declarativa de uma instância
provider "aws" {
region = "sa-east-1" # região alvo do provedor
}
resource "aws_instance" "app" {
ami = "ami-0abc123def456" # imagem base da instância
instance_type = "t3.medium" # mudar aqui pode gerar replace
subnet_id = aws_subnet.privada.id # referência declarativa a outro recurso
tags = {
Name = "app-producao"
ManagedBy = "terraform" # marca de origem do recurso
}
}
# Ciclo operacional canônico
terraform init # baixa providers e inicializa o backend de state
terraform plan # calcula e exibe o delta entre desejado e real
terraform apply # executa o plano aprovado e converge o mundo real
Revisão de código para infraestrutura
Revisão de pull request muda de natureza quando o artefato é infraestrutura. O revisor não avalia apenas legibilidade: avalia a natureza das operações do plano (destruições e substituições merecem escrutínio redobrado), o blast radius da mudança (ela toca produção inteira ou um recurso isolado), a reversibilidade (como a mudança volta atrás se falhar) e o acoplamento (a mudança quebra dependências implícitas de outros componentes).
Comentários de revisão ganham carga operacional: perguntar "por que essa mudança de tipo de instância?" pode revelar um replace silencioso de banco em produção. Boas equipes exigem que o PR carregue o plano anexado pela pipeline, que mudanças destrutivas tenham etiqueta própria e que caminhos críticos, redes, IAM e bancos, exijam dois aprovadores com contexto de segurança. A revisão vira, na prática, o principal mecanismo de prevenção de incidente do domínio.
Aplicação prática: onde o IaC entra no dia a dia
O uso dominante é o provisioning de nuvem: redes, clusters, bancos, filas e DNS gerenciados por Terraform ou CloudFormation, com state remoto e pipeline dedicada. O segundo uso é a configuração de sistemas operacionais e runtimes, com Ansible, Chef ou Puppet, sobre as máquinas criadas. O terceiro é o bootstrap de plataforma: criar os componentes que sustentam a própria automação, inclusive o backend de state e as credenciais das pipelines, o clássico problema de autoinicialização do IaC.
Numa operação real, o IaC sustenta quatro momentos. A criação inicial do ambiente, primeira convergência do código. A evolução contínua, com PRs que mudam recursos toda semana. A recuperação de desastre, recriar região ou ambiente a partir do código. E o descomissionamento, destruir com o mesmo rigor com que se cria. A ausência de IaC torna os dois últimos longos, caros e arriscados; a presença os transforma em exercícios rotineiros, testados antes do incidente real.
Comparação: provisionamento manual versus IaC
A tabela abaixo condensa o contraste operacional entre os dois modos de produção. O objetivo não é caricatura: muitas operações convivem com os dois modelos em transição, e a tabela serve para localizar o estágio atual e priorizar o próximo passo.
| Dimensão | Provisionamento manual | Infraestrutura como código |
|---|---|---|
| Fonte de verdade | Consoles, memórias e anotações | Repositório Git versionado |
| Reprodutibilidade | Baixa, cada recriação diverge | Alta, ambientes idênticos por parâmetros |
| Auditoria | Limitada a logs de console | Commits, PRs, planos e applies arquivados |
| Tempo de recuperação | Horas a dias, dependendo de quem sabe | Minutos a horas, via pipeline |
| Revisão prévia | Inexistente | Code review com plano anexado |
| Custo inicial | Baixo e imediato | Curva de aprendizado e bootstrap |
| Risco de drift | Estrutural e permanente | Detectável e reconciliável |
| Escala do time | Conhecimento concentrado | Conhecimento distribuído no repositório |
A coluna de custo inicial é a que trava adoções: IaC tem custo real de entrada, aprendizado, módulos e pipeline, e ele se paga quando o ambiente muda com frequência, quando existem múltiplos ambientes ou quando o time é maior que uma pessoa. Um ambiente estático, criado uma vez e raramente tocado, pode até sobreviver sem código; produção com evolução constante não sobrevive.
Panorama das famílias de ferramenta
O mercado organiza o IaC em três famílias complementares. Provisionamento declarativo de recursos de nuvem, com Terraform, CloudFormation e Pulumi, cria e mantém a infraestrutura; gerenciamento de configuração, com Ansible, Chef e Puppet, configura o que roda dentro das máquinas; e imagens imutáveis, com Packer, congelam configuração em artefatos prontos. A tabela abaixo situa cada família, e os arquivos seguintes do módulo detalham as ferramentas individualmente.
| Família | Ferramentas típicas | Responsabilidade | Unidade de trabalho |
|---|---|---|---|
| Provisionamento declarativo | Terraform, CloudFormation, Pulumi | Criar e evoluir recursos de nuvem | Recurso e stack |
| Gerenciamento de configuração | Ansible, Chef, Puppet | Configurar sistemas e runtimes | Servidor ou conjunto de servidores |
| Imagens imutáveis | Packer, EC2 Image Builder | Congelar configuração em imagem | Artefato de imagem |
| Orquestração de contêineres | Kubernetes, ECS | Executar cargas em contêineres | Workload declarativa |
Erros comuns e boas práticas
- Tratar o console como canal legítimo de mudança rotineira; exceto em emergência documentada, toda mudança entra pelo código, e toda emergência gera reconciliação imediata.
- Executar apply cego em pipeline, sem revisão do plano; o plano precisa ser lido, e aplicações destrutivas pedem aprovação extra.
- Copiar código entre ambientes em vez de parametrizar; a cópia cria divergência silenciosa e multiplica o custo de manutenção.
- Deixar credenciais no código de infraestrutura; segredos vivem em gerenciadores dedicados, Secrets Manager ou Vault, e o código apenas referencia.
- Versionar o state em disco local e aplicar da máquina pessoal; state remoto com lock é pré-requisito de produção.
- Escrever código imperativo disfarçado de declarativo, com provisioners longos e lógica de script no caminho principal; quanto mais imperativo, menor a garantia de convergência.
- Adotar IaC sem pipeline e sem testes; infraestrutura é código e merece CI com formatação, validação estática, plano automatizado e promoção controlada.
- Ignorar a documentação dos módulos; variáveis sem descrição e sem exemplo de uso transferem dívida para o próximo consumidor.
- Tratar o plano como formalidade de compliance; o plano é o documento operacional mais importante da mudança, e ignorá-lo é programar incidente.