Pular para o conteúdo

Ansible

Intermediário18 min de leituraiac

Terraform provisiona o que não existe; Ansible configura o que já existe. A diferença explica onde cada um ganha: criar a VM, a rede e o balanceador é trabalho do primeiro; instalar pacote, ajustar arquivo de configuração, aplicar baseline de segurança e orquestrar um procedimento em várias máquinas é do segundo.

Ansible ainda é a resposta certa em três cenários muito comuns no Brasil: parque de servidores que não vai para container tão cedo, equipamento e appliance sem API declarativa, e procedimentos operacionais que precisam de ordem entre máquinas. Ele funciona por SSH, sem agente instalado — o que reduz a barreira em ambiente legado.

O inventário descreve o parque. Comece estático, vá para dinâmico quando a nuvem for a fonte da verdade.

inventario/prod.yml
all:
children:
web:
hosts:
web-01: { ansible_host: 10.0.1.11 }
web-02: { ansible_host: 10.0.1.12 }
vars:
porta_app: 8080
banco:
hosts:
db-01: { ansible_host: 10.0.2.21 }
vars:
ansible_user: deploy
ansible_python_interpreter: /usr/bin/python3
Janela do terminal
ansible-inventory -i inventario/prod.yml --graph
ansible web -i inventario/prod.yml -m ping # conectividade antes de qualquer coisa

Variáveis vivem em group_vars/ e host_vars/, não espalhadas nos playbooks. Segredo vai para ansible-vault ou, melhor, para um cofre externo consultado em tempo de execução.

- name: Configurar servidores web
hosts: web
become: true
serial: 1 # uma máquina por vez: o resto continua atendendo
max_fail_percentage: 0
tasks:
- name: Instalar nginx
ansible.builtin.package:
name: nginx
state: present
- name: Publicar configuração do site
ansible.builtin.template:
src: templates/site.conf.j2
dest: /etc/nginx/conf.d/site.conf
owner: root
mode: "0644"
validate: "nginx -t -c %s" # não publica configuração que não passa no teste
notify: recarregar nginx
- name: Garantir serviço ativo e habilitado
ansible.builtin.service:
name: nginx
state: started
enabled: true
handlers:
- name: recarregar nginx
ansible.builtin.service: { name: nginx, state: reloaded }

Handler roda uma vez, no fim, e só se alguma task notificou — é o que evita recarregar o serviço a cada mudança. serial: 1 transforma o playbook em atualização progressiva: com balanceador na frente, ninguém percebe.

Role é o módulo do Ansible: estrutura previsível (tasks/, templates/, defaults/, handlers/) que outros projetos consomem por versão.

# requirements.yml — dependências versionadas, como qualquer biblioteca
roles:
- src: https://github.com/empresa/ansible-role-nginx.git
version: v1.4.0
collections:
- { name: community.general, version: ">=9.0.0" }

Valores em defaults/main.yml (fáceis de sobrescrever) e não em vars/main.yml (difíceis) — a precedência de variáveis do Ansible é a principal fonte de confusão para quem começa.

O relatório final é o seu teste: rodar o playbook duas vezes deve terminar com changed=0 na segunda.

Janela do terminal
ansible-playbook -i inventario/prod.yml site.yml --check --diff # simulação
ansible-playbook -i inventario/prod.yml site.yml
ansible-playbook -i inventario/prod.yml site.yml | grep -E "changed=[1-9]" # deve sair vazio

Quem quebra a idempotência é quase sempre command ou shell sem guarda. Use o módulo específico quando existir; quando não existir, torne a execução condicional:

- name: Inicializar o cluster apenas uma vez
ansible.builtin.command: /opt/app/bin/init-cluster
args:
creates: /var/lib/app/.inicializado # não roda se o arquivo já existe
changed_when: false # ou defina o critério real de mudança

Ative --check no CI contra um ambiente de homologação: um playbook que não passa em simulação não deveria chegar a produção.

A divisão que funciona: Terraform cria a máquina, entrega IP e tags; Ansible configura o sistema operacional e a aplicação. Ligue os dois pelo inventário dinâmico, lendo tags da nuvem, e não por lista escrita à mão.

# inventario/aws_ec2.yml — plugin de inventário dinâmico
plugin: amazon.aws.aws_ec2
regions: [sa-east-1]
filters:
tag:ambiente: prod
keyed_groups:
- key: tags.papel # tag "papel: web" vira o grupo "web"
prefix: ""
separator: ""

Evite local-exec chamando ansible-playbook dentro do Terraform: a execução deixa de ser idempotente, o erro fica ilegível e o state passa a depender de algo que ele não controla. Orquestre os dois pelo pipeline, em etapas separadas.

Quando a máquina puder ser descartável, considere o passo seguinte: usar Ansible para construir a imagem (com Packer) em vez de configurar servidores vivos — você ganha infraestrutura imutável sem reescrever o que já tem.

Próximo passo: para IaC escrita em linguagem de programação, veja Pulumi e CDK.