Ansible Fundamentos: Inventário, Playbooks e Módulos
Ansible é uma ferramenta de automação de infraestrutura que revoluciona a forma como gerenciamos servidores e ambientes. Diferente de outras soluções que exigem agentes instalados em cada máquina, Ansible utiliza SSH para se comunicar com seus hosts, tornando a implementação simples e segura. Neste artigo, você aprenderá os três pilares do Ansible: como organizar seus hosts através de inventários, como orquestrar tarefas com playbooks e como executar operações específicas usando módulos.
O aprendizado deve ser progressivo. Começaremos entendendo como estruturar um inventário adequado, depois exploraremos a sintaxe e lógica dos playbooks, e finalmente mergulharemos nos módulos que realizam o trabalho pesado. Todos esses conceitos se conectam de forma orgânica — um inventário bem estruturado facilita a escrita de playbooks reutilizáveis, e playbooks eficientes dependem do conhecimento profundo dos módulos disponíveis.
Inventário: Organizando sua Infraestrutura
Entendendo o Propósito do Inventário
O inventário é o mapa de sua infraestrutura dentro do Ansible. Ele define quais máquinas você deseja gerenciar, como agrupá-las logicamente e quais variáveis associar a cada host ou grupo. Sem um inventário bem estruturado, seus playbooks se tornam frágeis e difíceis de manter. O inventário responde perguntas fundamentais: quais são meus servidores web? Quais máquinas rodam banco de dados? Quais credenciais usar para cada grupo?
Existem dois formatos principais para inventários: INI (tradicional e simples) e YAML (mais poderoso e legível). A escolha entre eles depende da complexidade de sua infraestrutura. Para pequenos ambientes, INI é suficiente. Para infraestruturas complexas com muitas variáveis e hierarquias, YAML é o caminho certo.
Inventário em Formato INI
O formato INI é direto e intuitivo. Você define grupos entre colchetes e lista os hosts dentro deles. Variáveis podem ser associadas a hosts individuais ou a grupos inteiros através de seções especiais.
# /etc/ansible/hosts ou seu_inventario.ini
[webservers]
web1.example.com ansible_user=ubuntu
web2.example.com ansible_user=ubuntu
192.168.1.10 ansible_port=2222
[databases]
db1.example.com ansible_user=deploy
db2.example.com ansible_user=deploy
[all:vars]
ansible_connection=ssh
ansible_become=yes
ansible_become_user=root
[webservers:vars]
server_role=frontend
http_port=80
Neste exemplo, criamos dois grupos: webservers e databases. Os hosts podem ser especificados por FQDN ou IP. As variáveis como ansible_user definem como Ansible se conectará. A seção [all:vars] aplica variáveis a todos os hosts, enquanto [webservers:vars] aplica apenas ao grupo webservers.
Inventário em Formato YAML
YAML permite uma estrutura mais clara e hierárquica. É ideal quando você precisa de várias variáveis por host ou quando quer organizar inventários dinâmicos.
# inventario.yml
all:
children:
webservers:
hosts:
web1.example.com:
ansible_user: ubuntu
server_role: frontend
http_port: 80
web2.example.com:
ansible_user: ubuntu
server_role: frontend
http_port: 80
vars:
environment: production
databases:
hosts:
db1.example.com:
ansible_user: deploy
db_type: postgresql
db2.example.com:
ansible_user: deploy
db_type: mysql
vars:
backup_enabled: true
vars:
ansible_connection: ssh
ansible_become: yes
A estrutura YAML é aninhada e clara. children define subgrupos, hosts lista as máquinas, e vars aplica variáveis. Este formato é especialmente útil em ambientes grandes onde a clareza estrutural facilita a manutenção.
Testando e Validando seu Inventário
Antes de executar qualquer playbook, verifique se seu inventário está correto. Ansible oferece comandos simples para isso.
# Listar todos os hosts
ansible-inventory -i inventario.yml --list
# Listar hosts de um grupo específico
ansible-inventory -i inventario.yml --graph
# Testar conectividade com todos os hosts
ansible all -i inventario.yml -m ping
# Executar um comando simples em um grupo
ansible webservers -i inventario.yml -m command -a "hostname"
O módulo ping verifica se Ansible consegue se conectar aos hosts. Se receber um erro, verifique as credenciais, conectividade de rede e acesso SSH.
Playbooks: Orquestrando Automação
Estrutura e Anatomia de um Playbook
Um playbook é um arquivo YAML que define uma sequência de tarefas (tasks) a serem executadas em hosts específicos. A estrutura fundamental consiste em uma lista de plays, onde cada play mapeia um conjunto de tarefas a um grupo de hosts. Um playbook pode conter um ou múltiplos plays, permitindo orquestração complexa de múltiplos grupos de máquinas.
A beleza do Ansible está em sua sintaxe declarativa. Você descreve o estado desejado, não os passos imperativos para alcançá-lo. Isso torna playbooks idempotentes: executá-los múltiplas vezes leva ao mesmo resultado final.
Seu Primeiro Playbook
Vamos criar um playbook prático que configura um servidor web básico.
---
- name: Configurar servidores web
hosts: webservers
become: yes
vars:
nginx_port: 80
nginx_user: www-data
tasks:
- name: Atualizar cache de pacotes
apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family == "Debian"
- name: Instalar Nginx
apt:
name: nginx
state: present
when: ansible_os_family == "Debian"
- name: Criar diretório de conteúdo
file:
path: /var/www/meu_site
state: directory
owner: "{{ nginx_user }}"
group: "{{ nginx_user }}"
mode: '0755'
- name: Copiar arquivo index.html
copy:
content: |
<!DOCTYPE html>
<html>
<body>
<h1>Bem-vindo!</h1>
<p>Servidor configurado pelo Ansible</p>
</body>
</html>
dest: /var/www/meu_site/index.html
owner: "{{ nginx_user }}"
mode: '0644'
- name: Configurar Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/default
backup: yes
notify: reiniciar nginx
- name: Ativar Nginx
systemd:
name: nginx
enabled: yes
state: started
handlers:
- name: reiniciar nginx
systemd:
name: nginx
state: restarted
Este playbook demonstra conceitos-chave: hosts especifica o grupo alvo, vars define variáveis, tasks lista as ações. Cada tarefa tem um nome descritivo (boa prática) e um módulo com seus parâmetros. A cláusula when adiciona condicionalidade — a tarefa só executa se a condição for verdadeira. Handlers são disparados por notificações — neste caso, Nginx reinicia apenas se sua configuração mudou.
Playbooks Avançados: Variáveis e Lógica
Playbooks reais precisam lidar com complexidade. Variáveis permitem reutilização, loops processam listas, e condicionais tratam diferentes cenários.
---
- name: Deploy da aplicação web
hosts: webservers
become: yes
vars:
app_version: "1.2.3"
app_port: 8080
deploy_user: deployer
required_packages:
- git
- python3
- python3-pip
- curl
tasks:
- name: Instalar pacotes obrigatórios
apt:
name: "{{ item }}"
state: present
loop: "{{ required_packages }}"
- name: Criar usuário de deploy
user:
name: "{{ deploy_user }}"
shell: /bin/bash
createhome: yes
- name: Clonar repositório da aplicação
git:
repo: https://github.com/usuario/app.git
dest: /opt/app
version: "v{{ app_version }}"
become_user: "{{ deploy_user }}"
- name: Instalar dependências Python
pip:
requirements: /opt/app/requirements.txt
virtualenv: /opt/app/venv
virtualenv_command: python3 -m venv
become_user: "{{ deploy_user }}"
- name: Gerar configuração da aplicação
template:
src: app_config.j2
dest: /opt/app/config.yml
become_user: "{{ deploy_user }}"
- name: Iniciar serviço da aplicação
systemd:
name: app
state: started
enabled: yes
daemon_reload: yes
register: service_status
- name: Verificar saúde da aplicação
uri:
url: "http://localhost:{{ app_port }}/health"
method: GET
status_code: 200
retries: 3
delay: 5
until: result.status == 200
- name: Exibir mensagem de sucesso
debug:
msg: "Aplicação v{{ app_version }} deployada com sucesso!"
when: service_status.changed
Aqui utilizamos loop para iterar sobre uma lista de pacotes. register captura a saída de uma tarefa em uma variável (service_status), permitindo verificar se houve mudanças. retries e until implementam retry logic — útil ao aguardar que um serviço fique disponível. uri testa endpoints HTTP, validando que a aplicação está saudável.
Módulos: Os Executores do Trabalho
Entendendo Módulos
Módulos são os blocos de construção do Ansible. Cada módulo encapsula uma funcionalidade específica: instalar pacotes, gerenciar arquivos, reiniciar serviços, executar comandos. Ansible vem com centenas de módulos built-in, e você pode criar módulos customizados em Python ou qualquer linguagem que gere JSON.
A chave para dominar Ansible é conhecer os módulos relevantes para seu trabalho. Não é necessário decorar todos, mas você deve saber quais existem, o que fazem, e como utilizá-los. A documentação oficial é excelente — ansible-doc nome_do_modulo exibe documentação completa no terminal.
Módulos Essenciais para Administração
---
- name: Exemplo de módulos essenciais
hosts: all
become: yes
tasks:
# Módulo command: executar comandos shell
- name: Executar comando shell
command: /usr/bin/uptime
register: uptime_output
- name: Exibir resultado do comando
debug:
var: uptime_output.stdout
# Módulo shell: similar a command, mas com pipes e redirecionamento
- name: Processar saída com pipes
shell: |
ps aux | grep nginx | wc -l
register: nginx_processes
# Módulo file: gerenciar arquivos e diretórios
- name: Criar diretório
file:
path: /opt/app/data
state: directory
owner: app
group: app
mode: '0755'
- name: Remover arquivo antigo
file:
path: /var/log/old_app.log
state: absent
- name: Criar link simbólico
file:
src: /opt/app/current
dest: /opt/app/latest
state: link
# Módulo copy: copiar arquivos locais para hosts remotos
- name: Copiar arquivo de configuração
copy:
src: /local/path/config.yml
dest: /etc/myapp/config.yml
owner: root
group: root
mode: '0600'
backup: yes
# Módulo template: processar Jinja2 e copiar
- name: Gerar config com variáveis
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
validate: /usr/sbin/nginx -t -c %s
notify: restart nginx
# Módulo lineinfile: modificar linhas em arquivos
- name: Adicionar linha ao arquivo
lineinfile:
path: /etc/hosts
line: "192.168.1.100 myserver.local"
state: present
- name: Modificar parâmetro em arquivo de configuração
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PermitRootLogin'
line: 'PermitRootLogin no'
state: present
notify: restart sshd
# Módulo apt/yum: gerenciar pacotes
- name: Instalar múltiplos pacotes
apt:
name: ['curl', 'wget', 'git', 'vim']
state: present
update_cache: yes
- name: Remover pacote
apt:
name: apache2
state: absent
# Módulo systemd: gerenciar serviços
- name: Iniciar e ativar serviço
systemd:
name: nginx
state: started
enabled: yes
daemon_reload: yes
- name: Reiniciar serviço se necessário
systemd:
name: mysql
state: restarted
when: database_config_changed
# Módulo user: gerenciar usuários
- name: Criar usuário do sistema
user:
name: appuser
shell: /bin/bash
home: /opt/app
createhome: yes
state: present
- name: Adicionar chave SSH pública
authorized_key:
user: appuser
key: "{{ lookup('file', '/local/ssh_key.pub') }}"
state: present
# Módulo cron: gerenciar agendamentos
- name: Agendar backup diário
cron:
name: "Daily backup"
hour: "2"
minute: "0"
job: "/opt/scripts/backup.sh > /dev/null 2>&1"
user: root
handlers:
- name: restart nginx
systemd:
name: nginx
state: restarted
- name: restart sshd
systemd:
name: sshd
state: restarted
Estes módulos cobrem 80% das tarefas de administração. command executa comandos sem processamento shell, enquanto shell permite pipes e redirecionamento. file é versátil para criar, remover e gerenciar permissões. lineinfile é perfeito para modificações cirurgicais em arquivos de configuração. systemd é o padrão moderno para gerenciar serviços em distribuições Linux atuais.
Módulos Avançados para Aplicações
---
- name: Deploy e configuração de aplicação
hosts: webservers
tasks:
# Módulo git: clonar e atualizar repositórios
- name: Clonar repositório
git:
repo: https://github.com/usuario/projeto.git
dest: /opt/projeto
version: main
depth: 1
become: yes
# Módulo pip: gerenciar pacotes Python
- name: Instalar dependências Python
pip:
requirements: /opt/projeto/requirements.txt
virtualenv: /opt/projeto/venv
virtualenv_command: python3 -m venv
# Módulo mysql_db: gerenciar bancos de dados MySQL
- name: Criar banco de dados
mysql_db:
name: myapp_db
state: present
login_user: root
login_password: "{{ mysql_root_password }}"
# Módulo postgresql_db: gerenciar bancos PostgreSQL
- name: Criar usuário PostgreSQL
postgresql_user:
name: appuser
password: "{{ db_password }}"
state: present
become_user: postgres
# Módulo docker_container: gerenciar containers Docker
- name: Executar container da aplicação
docker_container:
name: myapp
image: "myapp:{{ app_version }}"
state: started
restart_policy: always
ports:
- "8080:8080"
env:
DATABASE_URL: "{{ database_url }}"
# Módulo uri: fazer requisições HTTP
- name: Testar endpoint da API
uri:
url: "http://localhost:8080/api/status"
method: GET
status_code: 200
retries: 5
delay: 10
until: result.status == 200
# Módulo assert: validações customizadas
- name: Validar versão da aplicação
assert:
that:
- app_version is defined
- app_version | length > 0
fail_msg: "app_version deve ser definido e não vazio"
Estes módulos lidam com cenários mais específicos: repositories, dependências de linguagem, bancos de dados, containers e validações.
Documentação e Descoberta de Módulos
Nunca tente memorizar todos os módulos. Use a documentação disponível.
# Listar todos os módulos instalados
ansible-doc -l
# Ver documentação de um módulo específico
ansible-doc apt
# Buscar módulos por palavra-chave
ansible-doc -l | grep user
# Ver exemplos práticos
ansible-doc -s user
A flag -s mostra o "snippet" — estrutura básica com parâmetros principais. Sempre consulte a documentação quando tiver dúvidas sobre sintaxe ou comportamento de um módulo.
Conclusão
Você aprendeu que Ansible funciona em três camadas interdependentes: o inventário define sua infraestrutura, playbooks orquestram o fluxo de trabalho, e módulos executam as ações concretas. Uma das lições mais importantes é que Ansible é declarativo, não imperativo — você descreve o estado desejado, e Ansible converge para ele. Isso torna sua automação robusta e reutilizável.
O terceiro ponto crucial é que a maestria em Ansible vem da prática e do conhecimento dos módulos disponíveis. Você não precisa decorar tudo no início — precisa saber onde procurar e como estruturar seu código para ser mantível. Invista tempo em escrever playbooks claros, use nomes descritivos para tarefas, organize seu inventário logicamente, e consulte a documentação frequentemente. Comece com playbooks simples, evolua para orquestrações complexas, e nunca deixe de testar sua automação múltiplas vezes antes de usar em produção.