0 XP
Módulo 7 · Terraform e Ansible

Ansible: inventário, playbooks e idempotência

Intermediário 50 min+25 XPAnsibleSSH

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: reloaded

Nota 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.yml

Playbook 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, idempotente

Por 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. 1. Um playbook idempotente executado duas vezes deve resultar em:

  2. 2. O que indica changed=0 na segunda execução?

  3. 3. Quando um handler roda?

Minhas anotações

Salvo automaticamente neste navegador.

AnteriorPróxima