Ansible: inventário, playbooks e idempotência
Objetivos desta aula
- Escrever inventário e playbook
- Garantir idempotência
- Usar handlers e variáveis
Terraform cria a infraestrutura; Ansible configura o que roda dentro dela. Ele age por SSH, sem agente, e é declarativo por módulo: você diz 'o pacote deve estar presente' e 'o serviço deve estar rodando' — não escreve os comandos. Isso é o que produz idempotência.
Idempotência é o coração do Ansible: aplicar o playbook duas vezes deve resultar em changed=0 na segunda. Quando você recorre ao módulo shell/command sem creates ou changed_when, perde essa garantia e volta ao mundo dos scripts imprevisíveis.
Organize com roles quando o playbook cresce: tasks, handlers, templates, defaults e vars separados. Templates Jinja2 geram configuração por ambiente, e handlers reiniciam serviço apenas quando a configuração realmente mudou.
1. Terraform cria, Ansible configura
Terraform é ótimo para provisionar recursos de nuvem. Ansible é ótimo para configurar o que está dentro das máquinas: pacotes, arquivos, usuários, serviços. Ele se conecta por SSH (ou SSM) e não exige agente.
2. Inventário
Lista de hosts e grupos, estática (INI/YAML) ou dinâmica (plugin aws_ec2 busca instâncias por tag). Variáveis ficam em group_vars e host_vars.
3. Idempotência
Módulos como apt, copy, template e systemd só mudam algo se necessário. Rodar duas vezes deve mostrar changed=0 na segunda. Evite shell quando existir módulo.
4. Handlers e roles
Handlers rodam só quando notificados (ex.: reiniciar Nginx após mudar config). Roles organizam tasks, templates e defaults para reuso.
5. Segredos com Ansible Vault
ansible-vault encrypt cifra arquivos de variáveis sensíveis que podem ir para o Git.
6. Checagem final
Seu playbook deve instalar e configurar o Nginx e rodar a segunda vez com changed=0.
Na prática
Playbook do host da API
yaml
# inventory.ini
# [api]
# 10.20.11.20 ansible_user=ubuntu
- name: Configurar host da API do CloudShop
hosts: api
become: true
vars:
app_dir: /opt/cloudshop
node_version: "22"
tasks:
- name: Pacotes base presentes
ansible.builtin.apt:
name: [curl, git, ufw, nginx]
state: present
update_cache: true
- name: Usuario de servico existe
ansible.builtin.user:
name: cloudshop
system: true
shell: /usr/sbin/nologin
- name: Diretorio da aplicacao com dono correto
ansible.builtin.file:
path: "{{ app_dir }}"
state: directory
owner: cloudshop
group: cloudshop
mode: "0750"
- name: Configuracao do Nginx a partir do template
ansible.builtin.template:
src: templates/nginx-api.conf.j2
dest: /etc/nginx/conf.d/cloudshop.conf
mode: "0644"
notify: reload nginx
- name: Firewall permite apenas 22, 80 e 443
community.general.ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop: ["22", "80", "443"]
- name: Servico habilitado e rodando
ansible.builtin.systemd:
name: cloudshop-api
enabled: true
state: started
handlers:
- name: reload nginx
ansible.builtin.systemd:
name: nginx
state: reloadedNota de segurança: Segredos vão em ansible-vault ou variáveis de ambiente do executor, nunca em texto no playbook ou no inventário.
Execução e validação de idempotência
bash
ansible-inventory -i inventory.ini --list
ansible all -i inventory.ini -m ping
ansible-playbook -i inventory.ini site.yml --check --diff # dry-run
ansible-playbook -i inventory.ini site.yml
ansible-playbook -i inventory.ini site.yml # 2a vez: changed=0
ansible-vault encrypt group_vars/api/vault.yml
ansible-lint site.ymlPlaybook idempotente com handler
yaml
- hosts: web
become: true
tasks:
- name: instalar nginx
ansible.builtin.apt: { name: nginx, state: present, update_cache: true }
- name: configurar site
ansible.builtin.template:
src: cloudshop.conf.j2
dest: /etc/nginx/sites-enabled/cloudshop.conf
notify: reload nginx # so dispara se o arquivo mudou
handlers:
- name: reload nginx
ansible.builtin.systemd: { name: nginx, state: reloaded }Executar com segurança
bash
ansible-inventory -i aws_ec2.yml --graph # hosts por tag
ansible-playbook -i aws_ec2.yml site.yml --check --diff # simula
ansible-playbook -i aws_ec2.yml site.yml
# PLAY RECAP: web-1 ok=3 changed=0 <- segunda execucao, idempotentePor que isso importa
Muitas empresas ainda operam frotas de VMs; Ansible é o padrão para configurá-las com previsibilidade.
Erro comum
Usar shell para tudo e perder idempotência — o playbook passa a 'mudar' algo em toda execução.
Dica de produção
Rode sempre com --check --diff antes de aplicar em produção e mantenha ansible-lint no CI.
Alerta de segurança
Playbook com become e módulo shell recebendo variável externa é vetor de execução arbitrária.
Pergunta de entrevista
Como você garante que um playbook é idempotente?
Glossário
- role
- Estrutura padronizada que agrupa tasks, templates e variáveis reutilizáveis.
- handler
- Task executada apenas quando notificada por uma mudança.
- playbook
- Arquivo YAML com a sequência de tarefas a aplicar em hosts.
- handler
- Tarefa executada apenas quando notificada por uma mudança.
- inventário dinâmico
- Lista de hosts obtida em tempo real de uma fonte como a AWS.
Conexão com o CloudShop
Configurar o host de produção do CloudShop inteiramente por Ansible.
Quiz da aula
1. Um playbook idempotente executado duas vezes deve resultar em:
2. O que indica changed=0 na segunda execução?
3. Quando um handler roda?
Minhas anotações
Salvo automaticamente neste navegador.