Ansible¶
TLDR: descreve o estado desejado de uma máquina em YAML e aplica via SSH, sem agente no destino; --check mostra o que vai mudar antes de mudar de verdade; ansible-pull faz o próprio host se reconfigurar sozinho, periodicamente.
| Termo | Vá pra |
|---|---|
| Push vs. pull | ansible-pull vs. push |
| Rodar de novo sem quebrar nada | Idempotência na prática |
| Ver o que vai mudar antes de mudar | Modo --check |
Por que nunca burlar o --check |
Por que nunca forçar mutação real sob --check |
| Rodar só um pedaço | Tags |
| Cifrar segredo em arquivo | Ansible Vault |
| Testar um role contra um sistema de verdade, não só simular | Molecule |
Ansible descreve o estado desejado de uma máquina (pacotes instalados, arquivos de configuração, serviços ativos) em YAML, e aplica isso via SSH, sem precisar de agente instalado no destino. Cada unidade de trabalho é uma task; um conjunto ordenado de tasks reutilizável é um role; um playbook decide quais roles rodam, em que ordem, contra quais hosts.
flowchart TD
P[playbook] -->|decide ordem e hosts| R1[role A]
P --> R2[role B]
R1 --> T1[task 1]
R1 --> T2[task 2]
R2 --> T3[task 1]
R2 --> T4[task 2]
ansible-pull vs. push¶
O jeito mais comum de usar Ansible é push: uma máquina de controle roda ansible-playbook contra um ou mais hosts remotos, via SSH, rodado da sua própria máquina.
ansible-pull inverte isso: o próprio node clona o repositório e roda o playbook localmente (ansible_connection: local), sem depender de nenhuma máquina de controle estar online. Um timer do systemd, disparado periodicamente, é o jeito mais comum de agendar isso, o que permite manter um host no estado declarado sem ninguém precisar rodar ansible-playbook na mão depois do bootstrap inicial.
flowchart LR
subgraph push[push, só no bootstrap]
direction LR
M[sua máquina] -->|SSH + ansible-playbook| N1[node]
end
subgraph pull[pull, todo o resto]
direction LR
N2[node] -->|git pull + ansible-playbook local| N2
end
Idempotência na prática¶
Uma task idempotente, rodada de novo sem nenhuma mudança real necessária, não faz nada e reporta isso (ok, não changed). É o que permite o ansible-pull rodar a cada ciclo sem risco: se nada mudou no repositório nem no node, a execução é um no-op. O papel do role é sempre comparar o estado atual com o desejado antes de agir, nunca aplicar às cegas (ver, por exemplo, como argocd-bootstrap lê o release Helm já instalado antes de decidir se roda helm upgrade).
Modo --check¶
--check simula a execução sem aplicar mudança nenhuma, e é o que torna possível revisar o que vai acontecer antes de acontecer de verdade. Mas nem todo módulo se comporta igual sob --check:
command,shell: pulados inteiramente (aparecem comoskipping), porque o Ansible não tem como saber o que aconteceria sem executar de verdade.get_url,template,copy(de origem local): simulam, relatamchangedsem tocar o destino.stat,assert: sempre refletem o estado real,--checknão muda o comportamento deles.copycomremote_src: true(copiar um arquivo que já está no node): tenta validar que a origem existe, mesmo sob--check. Se a origem só existiria depois de outra task que foi simulada (não real), isso quebra: um bug de classe comum na primeira execução de um role contra um host que ainda não tem nada instalado, corrigido pulando essas tasks específicas sob--checkem vez de forçar execução real.systemd(gerenciarenabled/statede uma unit): sempre consulta o estado real da unit no systemd,--checknão muda isso. Se a task anterior que instalaria o pacote ou copiaria o arquivo da unit foi só simulada (package,copy), a unit genuinamente não existe ainda, e o módulo falha com um erro fatal em vez de simular graciosamente. Mesma classe de bug docopycomremote_src: trueacima, mas sem um jeito de simplesmente pular a task, porque ela também precisa rodar de verdade fora do--check. A correção éignore_errors: "{{ ansible_check_mode }}": sob--checka falha vira só um aviso (ignored) na saída, numa execução real continua falhando duro se algo estiver genuinamente errado.
Por que nunca forçar mutação real sob --check¶
Existe um atalho tentador: adicionar check_mode: false numa task pra ela sempre rodar de verdade, mesmo sob --check, evitando esse tipo de inconsistência. O problema é que isso quebra a garantia central do --check, dar uma prévia segura antes de aplicar numa VM de produção, já que uma task que aplica de verdade sob --check engana quem está revisando o preview sem avisar. Uma solução mais robusta é um "gate": uma checagem que confere se o pré-requisito pra uma verificação significativa já existe de verdade, e se não existir, pula aquele pedaço com uma mensagem clara em vez de falhar ou de aplicar mudança sem querer.
flowchart TD
A[task começa] --> B{pré-requisito existe de verdade?}
B -->|sim| C[roda a checagem/diff normalmente]
B -->|não e é execução real| C
B -->|não e é --check| D[avisa e pula, sem aplicar nada]
Tags¶
Cada role pode ter sua própria tag, o que permite rodar só um pedaço com --tags ou pular um pedaço com --skip-tags. É comum reservar uma tag pra mudança de maior risco (mexer em firewall, por exemplo), pulada por padrão da execução automática e só disparada manualmente, com supervisão direta.
Ansible Vault¶
ansible-vault cifra arquivos com uma senha simétrica, guardada fora do git (ver Segredos e Estado fora do git). Um arquivo cifrado começa com $ANSIBLE_VAULT;1.1;AES256 e só é decriptado no momento de uso, com --vault-password-file apontando pra senha.
Molecule¶
--check simula, mas simular não é o mesmo que rodar contra um sistema de verdade: command/shell nem sequer executam sob --check (ver acima), e nenhum --check confere se a task, quando de fato executada, faz o sistema convergir pro estado esperado. Molecule é a ferramenta padrão de facto da comunidade Ansible pra fechar essa lacuna: cria um alvo efêmero e descartável (container ou VM), roda o role de verdade contra ele, e destrói o alvo no final, sem tocar em nada além desse ambiente temporário.
Uma sequência de teste típica encadeia vários passos, cada um com um objetivo diferente:
- create: sobe o alvo efêmero (o driver mais comum é Docker, por ser rápido de criar e destruir).
- converge: roda o role de verdade contra esse alvo, o equivalente a uma primeira execução real.
- idempotence: roda o mesmo role uma segunda vez e falha o teste se alguma task reportar
changed, automatizando exatamente a verificação manual descrita em Idempotência na prática, sem depender de alguém lembrar de rodar duas vezes e comparar o resultado na mão. - verify: roda checagem extra, escrita à parte, pra confirmar o estado final além do que o próprio
changed/okde cada task já garante. - destroy: descarta o alvo, garantindo que o próximo teste começa de um estado limpo, sem resíduo do anterior.
flowchart LR
Create[create: sobe alvo efêmero] --> Converge[converge: roda o role de verdade]
Converge --> Idempotence[idempotence: roda de novo, exige changed=0]
Idempotence --> Verify[verify: checagem extra do estado final]
Verify --> Destroy[destroy: descarta o alvo]
Nem todo role cabe num container Docker "pelado": qualquer role que gerencia um serviço via systemd (ansible.builtin.systemd) precisa de uma imagem que rode systemd de verdade como processo 1, dentro de um container privilegiado com o cgroup do host montado, bem diferente da imagem mínima que Molecule usa por padrão. E mesmo com systemd rodando, existe uma classe de daemon onde um container aninhado simplesmente não reproduz o ambiente real de forma confiável: qualquer coisa que dependa de D-Bus junto de PolicyKit (polkit) pra autorizar uma chamada privilegiada, comum em daemons de sistema como o firewalld (ver firewalld). Isso acontece porque polkit depende de gestão de sessão via systemd-logind, que tem comportamento documentadamente instável dentro de um container aninhado, tanto em relatos do próprio projeto Ansible quanto em issues do systemd. Quando essa fragilidade pesa mais que a velocidade de um container, a alternativa citada pela comunidade é trocar o driver Docker por uma VM real (libvirt/QEMU via Vagrant), que roda um kernel próprio e não depende de nenhuma emulação de systemd dentro de outro container.
flowchart TD
Role{o que o role gerencia?} -->|arquivo, pacote, diretório| Docker[Docker simples resolve bem]
Role -->|serviço systemd| DockerPriv[Docker privilegiado + imagem com systemd]
Role -->|D-Bus/polkit, ex.: firewalld| VM[VM real via libvirt/QEMU, Docker é frágil aqui]
Isso também torna Molecule uma ferramenta a aplicar com critério, não em todo role por padrão: pra um role simples, onde o único risco real é uma task mal escrita, --check mais lint já cobre a maior parte do risco, sem o peso extra de manter um scenario completo. Vale o investimento de um scenario Molecule quando o custo de um erro é alto (mudança de rede, serviço de sistema, algo com implicação de segurança) e o que precisa ser validado é o comportamento do sistema real convergindo, não só a lógica das tasks.
Pra ir além¶
Ansible é uma ferramenta de configuration management: agentless (só precisa de SSH e Python no destino), imperativa por dentro mas usada de forma declarativa (as tasks descrevem um estado, não um script). Outras ferramentas na mesma categoria, mais antigas e geralmente exigindo um agente instalado no destino: Puppet, Chef, e Salt (o projeto que era conhecido como SaltStack antes de passar por VMware e hoje Broadcom, mas segue open source). Cada uma tem sua própria linguagem de descrição de estado e seu próprio jeito de lidar com idempotência.
Configuration management (o que o Ansible faz) é uma camada diferente de infrastructure provisioning (criar a VM em si, a rede, o disco): Terraform, OpenTofu e Pulumi são as ferramentas mais comuns nessa outra camada. Muitos setups combinam as duas, provisionamento primeiro, depois configuração; outros, como um servidor que já existia antes da automação chegar, pulam a camada de provisionamento inteiramente e começam direto pela configuração. Crossplane inverte a lógica de novo: em vez de uma ferramenta externa provisionar recursos cloud, o próprio cluster Kubernetes ganha CRDs que representam esses recursos, e o Argo CD (ver Argo CD) poderia sincronizá-los do mesmo jeito que sincroniza qualquer outro manifesto, GitOps aplicado até na camada de provisionamento, não só na de aplicação.
Pra times maiores, existe uma camada de orquestração e UI sobre o Ansible puro, hoje chamada Ansible Automation Platform (o antigo Ansible Tower foi descontinuado e virou "automation controller", um componente dentro dessa plataforma maior), ou sua versão open source, AWX. Um setup baseado só em ansible-pull cumpre o mesmo papel de "rodar sozinho" sem precisar dessa camada extra.
Vale também conhecer o debate mutable vs. immutable infrastructure: a abordagem do Ansible é mutável, a mesma máquina é reconfigurada repetidamente, in-place. A antítese, imutável, reconstrói a imagem inteira a cada mudança e substitui a máquina, em vez de editá-la; Packer é a ferramenta mais citada nessa categoria pra imagem de VM (AMI da AWS, disco de VMware, e outros formatos, todos a partir da mesma definição), e a versão mais comum disso hoje é simplesmente a imagem de container em si, reconstruída a cada mudança de Dockerfile, o mesmo princípio aplicado numa unidade menor. Cada abordagem tem trade-offs diferentes de velocidade, auditabilidade e complexidade operacional.
flowchart LR
subgraph Mutavel["Mutável (Ansible)"]
M1[máquina existente] -->|reconfigura in-place| M1
end
subgraph Imutavel["Imutável (Packer, imagem de container)"]
I1[imagem nova] -->|substitui inteira| I2[máquina antiga descartada]
end
Cheatsheet¶
| Comando/conceito | O que faz |
|---|---|
ansible-playbook site.yml --check |
Simula, mostra o que mudaria, não aplica |
ansible-playbook site.yml --tags X |
Roda só a tag X |
ansible-playbook site.yml --skip-tags X |
Roda tudo, exceto a tag X |
ansible-pull -U <repo> |
O próprio host clona e aplica o playbook localmente |
ansible-vault encrypt <arquivo> |
Cifra um arquivo com senha simétrica |
--vault-password-file <arquivo> |
Aponta pra senha na hora de decifrar |
ok no resultado de uma task |
Idempotente, nada mudou |
changed no resultado de uma task |
Aplicou uma mudança real |
molecule test |
Roda a sequência inteira: create, converge, idempotence, verify, destroy |
molecule converge |
Só sobe o alvo e roda o role, sem destruir no final (útil pra depurar) |
molecule idempotence |
Roda o role de novo contra um alvo já convergido, exige changed=0 |
Onde aprofundar: a documentação oficial em docs.ansible.com cobre todo módulo em detalhe, mas é referência, não material de aprendizado sequencial. Pra isso, Ansible for DevOps, de Jeff Geerling (ansiblefordevops.com), é o livro mais citado da comunidade, escrito por alguém que administra Ansible em produção desde 2013 e mantém o livro atualizado continuamente.