Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

02 - Versionamento e Imutabilidade

#fonte-de-verdade#git#golden-image#imutabilidade#rollback
video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

Versionamento e Imutabilidade

Versionamento e imutabilidade são os dois princípios que transformam IaC de automação conveniente em sistema confiável de produção. O versionamento coloca toda a definição de infraestrutura em Git, com histórico completo de quem mudou o quê, quando e por quê; a imutabilidade estende o mesmo raciocínio aos artefatos executáveis, servidores e imagens que, uma vez criados, não são mais alterados, apenas substituídos por versões novas. Juntos, eles eliminam a categoria de problemas em que produção é um estado irreproduzível que só existe por acumulação de decisões não registradas. Em produção, o valor aparece em três momentos: ao revisar uma mudança antes de ela tocar o mundo real, ao investigar um incidente com linha do tempo confiável e ao reverter, de forma limpa, uma mudança que causou regressão. Este arquivo cobre os dois princípios, o fluxo de trabalho que os materializa e os trade-offs entre servidores mutáveis e imutáveis.

Conceito: o repositório como fonte de verdade

Quando a infraestrutura vive em Git, o repositório passa a responder qualquer pergunta sobre o estado do sistema. Qual regra de security group protege o banco: olha-se o código. Quem aprovou a mudança de ontem: olha-se o pull request. Como produção estava no mês passado, antes do incidente: olha-se o commit anterior. Essa propriedade, fonte de verdade, é o que separa uma operação auditável de uma operação baseada em memória oral.

O versionamento também define o contrato de confiança entre times: nada existe em produção sem correspondência no repositório, e nada entra no repositório sem revisão. Quando esse contrato vale, a discussão técnica acontece no pull request, com evidência e contexto, e a produção reflete a decisão aprovada, não a decisão do último que teve acesso ao console.

O paralelo com software é direto e proposital. Se a infraestrutura é código, ela herda o modelo mental do desenvolvimento: branches para mudanças em andamento, tags para releases, revert para desfazer, blame para investigar. Times que já dominam Git transportam a competência inteira para infraestrutura com pouco atrito, e a curva de aprendizado do IaC se concentra na parte de infraestrutura, não na parte de código.

O problema que resolve: o servidor como caixa preta

Servidores mutáveis operados manualmente são caixas pretas acumuladoras. Cada patch aplicado, cada pacote instalado e cada ajuste de configuração ficam gravados apenas na máquina, sem histórico e sem explicação; com o tempo, o sistema passa a depender de estados locais que ninguém sabe reproduzir. A frase clássica da área resume o risco: se o servidor não pode ser recriado, ele não está em produção, está de refém.

A caixa preta cobra o preço mais alto no pior momento possível. Durante um incidente, o time precisa responder o que mudou recentemente, e sem versionamento a resposta é um palpite; durante uma reconstrução de emergência, o time precisa reproduzir a máquina, e sem imutabilidade a resposta é tentativa e erro. Versionamento e imutabilidade existem para que essas duas perguntas tenham resposta mecânica.

Existe ainda o problema da divergência ao longo do tempo. Uma frota de dez servidores mutáveis provisionados há dois anos contém, na prática, dez versões diferentes do sistema operacional, das bibliotecas e da configuração, porque cada um absorveu patches e intervenções próprios. Essa heterogeneidade invisível é fonte clássica de bugs que aparecem em uma instância e nunca se reproduzem em outra.

O fluxo de mudança versionada

O fluxo canônico replica o desenvolvimento de software. A mudança nasce em um branch descritivo, avança por pull request com plano de execução anexado, recebe revisão, é executada por pipeline em ambientes na ordem de menor para maior risco e termina em commit aplicado à produção. Em cada etapa, o artefato é o mesmo: código que descreve infraestrutura.

A proteção de branch é o mecanismo que sustenta o contrato. Branch principal protegido, aprovação obrigatória, checagens automatizadas de formatação e validação, e proibição de push direto transformam o repositório em portão único de mudança. Sem proteção, o fluxo existe só no papel, e o console volta a ser o caminho real.

O fluxo também precisa lidar com emergências sem destruir a disciplina. A política comum abre um caminho expresso: a mudança emergencial entra por commit imediato com revisão retroativa, acompanhada de issue de reconciliação obrigatória em janela curta. O importante é que emergências sejam exceções rastreáveis, e não a porta de entrada rotineira de mudança sem revisão.

# Pipeline GitHub Actions: validação, plano e apply de infraestrutura
name: infra-pipeline
on:
  pull_request:
    paths: ["infra/**"]          # roda apenas quando o IaC muda
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: terraform fmt -check -recursive   # estilo consistente
      - run: terraform validate                # sintaxe e semântica
      - run: terraform plan -out=tfplan        # plano anexado ao PR
  apply:
    needs: validate
    if: github.ref == 'refs/heads/main'      # só na main, após merge
    runs-on: ubuntu-latest
    environment: producao                     # exige aprovação humana
    steps:
      - uses: actions/checkout@v4
      - run: terraform apply -auto-approve tfplan

Imutabilidade: substituir em vez de alterar

A imutabilidade aplica a lógica do versionamento aos artefatos executáveis. Numa infraestrutura mutável, a correção entra no servidor existente: pacote atualizado, arquivo editado, serviço reiniciado. Numa infraestrutura imutável, a correção gera um novo artefato, imagem ou container, e o servidor antigo é descartado e substituído; nunca se edita o que está em execução.

O ganho central é a eliminação da divergência acumulada. Um servidor imutável nasce de uma imagem construída por pipeline, idêntica às irmãs da mesma versão, e permanece idêntico até a morte. Não existem snowflakes porque não existe tempo para eles se formarem: a instância vive dias ou semanas, não anos, e a heterogeneidade da frota passa a ser apenas a lista de versões em rollout.

A imutabilidade também muda a natureza do rollback. Voltar atrás deixa de ser desfazer mudanças dentro do servidor, operação frágil e sem garantia de estado limpo, e passa a ser reexecutar a versão anterior da imagem, operação determinística. O estado que se restaura não é o servidor, é a versão do artefato.

O custo do modelo é estrutural e precisa ser aceito: cada mudança exige novo build, novo rollout e, no caso de VMs, substituição de instâncias com orquestração de drain, health check e destruição gradual. Auto Scaling Groups, grupos de instâncias gerenciados e controladores de rollout de Kubernetes existem, em grande parte, para pagar esse custo de forma automatizada e segura.

Golden images: o pipeline da imagem

A golden image é o artefato da imutabilidade: uma imagem de máquina construída por pipeline, contendo sistema operacional endurecido, dependências, agentes e configuração base, versionada e testada antes de virar base de frota. Packer e EC2 Image Builder são as ferramentas dominantes para construí-la de forma repetível e auditável, e a imagem vira insumo do IaC, referenciada por id ou por filtro de versão.

O ciclo de vida da imagem replica o ciclo de release de software. Uma mudança de dependência abre pull request no repositório de imagens, a pipeline constrói uma versão nova, executa testes de smoke e varredura de vulnerabilidade, publica com tag imutável e a frota adota a versão por rollout gradual. A imagem anterior permanece disponível para rollback imediato, e versões antigas são aposentadas por política de retenção, não por esquecimento.

A fronteira entre imagem e configuração dinâmica é uma decisão de desenho: o que for igual a toda a frota entra na imagem; o que variar por instância ou por ambiente entra como user data, parâmetros ou gerenciamento de configuração no boot. Colocar na imagem o que muda por ambiente multiplica builds sem ganho; deixar na configuração dinâmica o que é comum reacende a mutabilidade.

# Packer HCL: construção de golden image versionada
packer {
  required_plugins {
    amazon = {
      version = ">= 1.3.0"
      source  = "github.com/hashicorp/amazon"
    }
  }
}

source "amazon-ebs" "app" {
  region        = "sa-east-1"
  instance_type = "t3.small"
  ami_name      = "app-base-${local.timestamp}"  # tag imutável por build
  ssh_username  = "ec2-user"
  ami_tags = {
    Version = var.versao      # versão semântica vinda da pipeline
    GitSha  = var.git_sha     # rastreabilidade até o commit
  }
}

build {
  sources = ["source.amazon-ebs.app"]
  provisioner "shell" {
    inline = [
      "sudo yum update -y",                     # patch de segurança
      "sudo amazon-linux-extras install -y docker",
      "sudo systemctl enable docker"            # estado base congelado
    ]
  }
}

Mutable versus immutable: comparação

Dimensão Infraestrutura mutável Infraestrutura imutável
Unidade de mudança Patch no servidor em execução Nova imagem substituindo a anterior
Divergência da frota Acumula com o tempo Zerada a cada substituição
Rollback Desfazer mudanças, frágil Reexecutar imagem anterior, determinístico
Tempo de aplicação Minutos, direto no host Ciclo de build e rollout completo
Testabilidade da mudança Limitada ao próprio servidor Testada antes, na imagem
Debug pós-incidente Estado local pode desaparecer Instância substituída preservada para forense
Custo de armazenamento Baixo, estado vivo Maior, múltiplas versões de imagem
Exigência de automação Opcional, funciona à mão Estrutural, sem rollout automático não escala

A leitura prática da tabela é de transição, não de fé: operações começam mutáveis por velocidade e migram para imutáveis quando a divergência da frota e o custo dos incidentes superam o custo do build. A migração típica ocorre por partes, primeiro serviços stateless em contêineres e Auto Scaling Groups, depois camadas de estado com estratégias próprias de reconstrução e réplicas.

Há também um ponto de articulação entre os dois mundos: servidores imutáveis ainda precisam de parametrização no boot, endereço, papel, credenciais efêmeras, e essa camada é exatamente onde gerenciamento de configuração e user data operam no modelo imutável. A imutabilidade não elimina configuração; ela restringe a configuração a um momento único e reproduzível, o nascimento da instância.

Rollback e recuperação versionada

O rollback em infraestrutura versionada é um revert de commit seguido de plano e apply, e a garantia de que a reversão reproduz o estado anterior vem justamente do versionamento: o commit antigo descreve integralmente o estado desejado de antes. Sem estado descrito, rollback é improvisação; com estado descrito, rollback é execução rotineira do fluxo normal em ordem inversa.

O rollback de infraestrutura imutável é ainda mais direto: reexecutar a versão anterior da imagem no rollout, mantendo o plano de dados intocado. A armadilha clássica é a incompatibilidade entre versão de código e versão de schema de banco, e por isso rollbacks de schema pedem compatibilidade bidirecional durante um período de transição, tema tratado nos módulos de banco deste material.

Em recuperação de desastre, o versionamento é o que transforma o plano em exercício realista: recriar a região a partir do código é o teste completo da fonte de verdade, e times maduros executam esse teste de forma programada. Se a reconstrução regional depende de estado que não está no repositório, o teste revela, e a lacuna é fechada antes do desastre, e não durante.

Erros comuns e boas práticas

  • Deixar exceções manuais em produção sem reconciliação no código; a exceção não registrada vira drift e bomba-relógio para a próxima execução.
  • Revisar apenas a sintaxe do IaC e não o plano; o pull request precisa mostrar o que muda no mundo real, não só o que muda no texto.
  • Aplicar patches diretamente na golden image publicada; imagem é imutável, e correção gera versão nova, nunca edição da existente.
  • Manter frota mutável sem inventário de versão; se o modelo mutável persistir, registre versão, patches e intervenções por instância.
  • Construir golden images sem testes; imagem sem smoke test e sem varredura de vulnerabilidade é dívida empacotada e distribuída em escala.
  • Usar tags latest ou referências não versionadas para imagens; referência imprecisa destrói a rastreabilidade que a imutabilidade promete.
  • Descartar instâncias substituídas em incidentes antes da forense; preserve o artefato de diagnóstico antes de encerrar o recurso.
  • Confundir imutabilidade com ausência de configuração; a parametrização no boot continua existindo e precisa de versionamento próprio.
  • Permitir push direto no branch principal do repositório de infraestrutura; o fluxo de revisão só vale se for o único caminho para produção.