Ansible

HTB

O Ansible é uma forma de comunicação superlumínica. Ou seja, passar uma informação ao mesmo tempo para vários objetos.

É uma ferramenta open source que possibilita comunicação e interação com diversos destinos ao mesmo tempo, tudo de forma automatizada.

Gerenciamento de Mudança

=> Idempotente Executa somente uma vez as alterações; se não houve alteração, ele não executa.

=> Pode também criar rotinas automatizadas por versão — por exemplo: se uma máquina client está com PHP 7, ao rodar o Ansible configurado com PHP 7.5, ele vai reverter tudo para o 7.5.

Provisionamento

=> Configuração => Instalação => Preparação => Alteração do System State

Automação

=> Execução de tarefas de forma automática => Ordenação de tarefas (tasks) => Realizar decisões => Ad-hoc tasks

Orquestração

=> Múltiplos servidores => Múltiplas aplicações => Diferentes tarefas => Ambiente Híbrido

Por que o Ansible?

De que forma o Ansible é diferente de outras ferramentas?

É fácil - o Ansible usa uma sintaxe simples (YAML) e é fácil para qualquer pessoa (desenvolvedores, administradores de sistemas, gerentes) entender. APIs são simples e úteis.

Sem agente - O Ansible usa SSH para conectar e executar comandos. Você não precisa de nenhum agente ou software adicional em execução no seu cliente.

Configuração rápida - como você não precisa instalar agentes ou daemons extras, a configuração é muito simples e rápida.

Seguro - como usa SSH para comunicação, é muito seguro e protegido. Não requer nenhuma porta extra ou daemons vulneráveis em seus servidores.

Arquitetura & funcionamento do Ansible

HTB

HTB

Como ele funciona?

Desenvolvido em Python, versão >= 3.5 ou Python >= 2.7.

Procura sempre o interpretador em /usr/bin/python. –> Variável: ansible_python_interpreter

Utiliza-se também do serviço SSH para comunicação com servidores Linux, e WinRM para servidores Windows.

-> Usuário + Senha -> Chave SSH (para servidores Linux)

Autenticação descentralizada.

Pode-se autenticar/conectar-se com LDAP e Kerberos.

Instalação do Ansible

Por padrão, o Ansible gerencia as máquinas por meio do protocolo SSH. Depois que o Ansible for instalado, ele não adicionará um banco de dados e não haverá daemons para iniciar ou manter em execução. Você só precisa instalá-lo em uma máquina e ele pode gerenciar uma frota inteira de máquinas remotas a partir desse ponto central. Quando o Ansible gerencia máquinas remotas, ele não deixa o software instalado ou em execução nelas, então não há dúvidas reais sobre como atualizar o Ansible ao mudar para uma nova versão.

A única dependência que o Ansible tem para instalação é o Python. O Ansible pode ser instalado diretamente usando o gerenciador de pacotes do sistema operacional com base no sistema operacional que você está executando e via pip, que é o gerenciador de pacotes do Python.

RHEL / CentOS / Fedora:

Certifique-se de habilitar o repo EPEL antes de executar o comando abaixo para RHEL e CentOS.

sudo yum install ansible

Ubuntu:

sudo apt-add-repository ppa:ansible/ansible
sudo apt-get update
sudo apt-get install ansible

Instalação Ansible usando pip

(caso não tenha o pip instalado faça:)

$ sudo apt-get install python3-pip

E depois instale o ansible:

$ sudo pip3 install ansible

Se precisar fazer upgrade

$ sudo pip3 install ansible --upgrade

HTB

Configurando o Ansible

O principal arquivo de configuração do ansible, é o ansible.cfg

Sua localização padrão é /etc/ansible/ansible.cfg

Alterações e configurações são interpretadas respeitando a seguinte ordem:

-> Variável ANSIBLE_CONFIG -> ansible.cfg no diretório corrente -> .ansible.cfg diretório home -> /etc/ansible/ansible.cfg

A primeira coisa a fazer é copiar o ansible.cfg, que fica dentro de /etc/ansible/.

Preservei o original e criei um arquivo mais resumido com as opções mais utilizadas do Ansible.

[defaults]

#--- General settings
forks                   = 5
log_path                = /var/log/ansible.log
module_name             = command
executable              = /bin/bash
ansible_managed         = Ansible managed

#--- Files/Directory settings
inventory               = /etc/ansible/hosts
library                 = /usr/share/my_modules
remote_tmp              = ~/.ansible/tmp
local_tmp               = ~/.ansible/tmp
roles_path              = /etc/ansible/roles

#--- Users settings
remote_user             = root
sudo_user               = root
ask_pass                = no
ask-sudo_pass           = no

#--- SSH settings
remote_port             = 22
timeout                 = 10
host_key_checking       = False
ssh_executable          = /usr/bin/ssh
private_key_file        = ~/.ssh/id_rsa

[privilege_escalation]

become                  = True
become_method           = sudo
become_user             = root
become_ask_pass         = False

[ssh_connection]

scp_if_ssh              = smart
transfer_method         = smart
retries                 = 3

 

Testando na máquina alvo

osboxes@FXSHELL:/etc/ansible$ ansible 192.168.1.151 -u osboxes -k -m ping
[WARNING]: log file at /var/log/ansible.log is not writeable and we cannot create it, aborting

SSH password: 
[DEPRECATION WARNING]: Distribution debian 10.0 on host 192.168.1.151 should 
use /usr/bin/python3, but is using /usr/bin/python for backward compatibility 
with prior Ansible releases. A future Ansible release will default to using the
 discovered platform python for this host. See https://docs.ansible.com/ansible
/2.10/reference_appendices/interpreter_discovery.html for more information. 
This feature will be removed in version 2.12. Deprecation warnings can be 
disabled by setting deprecation_warnings=False in ansible.cfg.
192.168.1.151 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
osboxes@FXSHELL:/etc/ansible$ 
[DEPRECATION WARNING]: Distribution debian 10.0 on host 192.168.1.234 should 
use /usr/bin/python3, but is using /usr/bin/python for backward compatibility 
with prior Ansible releases. A future Ansible release will default to using the
 discovered platform python for this host. See https://docs.ansible.com/ansible
/2.10/reference_appendices/interpreter_discovery.html for more information. 
This feature will be removed in version 2.12. Deprecation warnings can be 
disabled by setting deprecation_warnings=False in ansible.cfg.
192.168.1.234 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "invocation": {
        "module_args": {
            "data": "pong"
        }
    },
    "ping": "pong"
}
META: ran handlers
META: ran handlers
osboxes@FXSHELL:/etc/ansible$ 

Podemos também explicitar para ele ignorar a mensagem do Python.

Basta adicionar no ansible.cfg a linha:

interpreter_python    = auto_legacy_silent
osboxes@FXSHELL:/etc/ansible$ ansible 192.168.1.234 -u osboxes -k -m ping
[WARNING]: log file at /var/log/ansible.log is not writeable and we cannot create it, aborting

SSH password: 
192.168.1.234 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
osboxes@FXSHELL:/etc/ansible$ 

Existe um módulo bem interessante chamado Ansible Facts, que varre todos os targets montando uma espécie de inventário deles.

Para buscar essas informações, basta executar o módulo setup:

osboxes@FXSHELL:/etc/ansible$ ansible 192.168.1.234 -u osboxes -k -m setup

Também existe um módulo chamado systemd com o argumento -a com "name=ssh state=restarted".

Ficando dessa forma:

osboxes@FXSHELL:/etc/ansible$ ansible 192.168.1.151 -u osboxes -k -b -m systemd -a "name=ssh state=restarted"
osboxes@FXSHELL:/etc/ansible$ ansible 192.168.1.151 -u osboxes -k -b -m systemd -a "name=ssh state=restarted"
[WARNING]: log file at /var/log/ansible.log is not writeable and we cannot create it, aborting

SSH password: 
192.168.1.151 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "name": "ssh",
    "state": "started",
    "status": {
        "ActiveEnterTimestamp": "Wed 2021-04-07 22:52:06 EDT",
        "ActiveEnterTimestampMonotonic": "246017520",
        "ActiveExitTimestampMonotonic": "0",
        "ActiveState": "active",
        "After": "system.slice -.mount network.target auditd.service systemd-journald.socket basic.target sysinit.target",
        "AllowIsolate": "no",
        "AmbientCapabilities": "",
        "AssertResult": "yes",
        "AssertTimestamp": "Wed 2021-04-07 22:52:06 EDT",
        "AssertTimestampMonotonic": "245980232",
        "Before": "multi-user.target shutdown.target",
        "BlockIOAccounting": "no",
        "BlockIOWeight": "[not set]",
        "CPUAccounting": "no",
        "CPUQuotaPerSecUSec": "infinity",
        "CPUSchedulingPolicy": "0",
        "CPUSchedulingPriority": "0",
        "CPUSchedulingResetOnFork": "no",
        "CPUShares": "[not set]",
        "CPUUsageNSec": "[not set]",
        "CPUWeight": "[not set]",
        "CacheDirectoryMode": "0755",
        "CanIsolate": "no",
        "CanReload": "yes",
        "CanStart": "yes",
        "CanStop": "yes",
        "CapabilityBoundingSet": "cap_chown cap_dac_override cap_dac_read_search cap_fowner cap_fsetid cap_kill cap_setgid cap_setuid cap_setpcap cap_linux_immutable cap_net_bind_service cap_net_broadcast cap_net_admin cap_net_raw cap_ipc_lock cap_ipc_owner cap_sys_module cap_sys_rawio cap_sys_chroot cap_sys_ptrace cap_sys_pacct cap_sys_admin cap_sys_boot cap_sys_nice cap_sys_resource cap_sys_time cap_sys_tty_config cap_mknod cap_lease cap_audit_write cap_audit_control cap_setfcap cap_mac_override cap_mac_admin cap_syslog cap_wake_alarm cap_block_suspend",
        "CollectMode": "inactive",
        "ConditionResult": "yes",
        "ConditionTimestamp": "Wed 2021-04-07 22:52:06 EDT",
        "ConditionTimestampMonotonic": "245980220",
        "ConfigurationDirectoryMode": "0755",
        "Conflicts": "shutdown.target",
        "ControlGroup": "/system.slice/ssh.service",
        "ControlPID": "0",
        "DefaultDependencies": "yes",
        "Delegate": "no",
        "Description": "OpenBSD Secure Shell server",
        "DevicePolicy": "auto",
        "Documentation": "man:sshd(8) man:sshd_config(5)",
        "DynamicUser": "no",
        "EnvironmentFiles": "/etc/default/ssh (ignore_errors=yes)",
        "ExecMainCode": "0",
        "ExecMainExitTimestampMonotonic": "0",
        "ExecMainPID": "2270",
        "ExecMainStartTimestamp": "Wed 2021-04-07 22:52:06 EDT",
        "ExecMainStartTimestampMonotonic": "246010909",
        "ExecMainStatus": "0",
        "ExecReload": "{ path=/bin/kill ; argv[]=/bin/kill -HUP $MAINPID ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }",
        "ExecStart": "{ path=/usr/sbin/sshd ; argv[]=/usr/sbin/sshd -D $SSHD_OPTS ; ignore_errors=no ; start_time=[Wed 2021-04-07 22:52:06 EDT] ; stop_time=[n/a] ; pid=2270 ; code=(null) ; status=0/0 }",
        "ExecStartPre": "{ path=/usr/sbin/sshd ; argv[]=/usr/sbin/sshd -t ; ignore_errors=no ; start_time=[Wed 2021-04-07 22:52:06 EDT] ; stop_time=[Wed 2021-04-07 22:52:06 EDT] ; pid=2269 ; code=exited ; status=0 }",
        "FailureAction": "none",
        "FailureActionExitStatus": "-1",
        "FileDescriptorStoreMax": "0",
        "FinalKillSignal": "9",
        "FragmentPath": "/lib/systemd/system/ssh.service",
        "GID": "[not set]",
        "GuessMainPID": "yes",
        "IOAccounting": "no",
        "IOSchedulingClass": "0",
        "IOSchedulingPriority": "0",
        "IOWeight": "[not set]",
        "IPAccounting": "no",
        "IPEgressBytes": "18446744073709551615",
        "IPEgressPackets": "18446744073709551615",
        "IPIngressBytes": "18446744073709551615",
        "IPIngressPackets": "18446744073709551615",
        "Id": "ssh.service",
        "IgnoreOnIsolate": "no",
        "IgnoreSIGPIPE": "yes",
        "InactiveEnterTimestamp": "Wed 2021-04-07 22:48:07 EDT",
        "InactiveEnterTimestampMonotonic": "5387216",
        "InactiveExitTimestamp": "Wed 2021-04-07 22:52:06 EDT",
        "InactiveExitTimestampMonotonic": "245983310",
        "InvocationID": "6561c69561a14f76842d4a1ce3592f4a",
        "JobRunningTimeoutUSec": "infinity",
        "JobTimeoutAction": "none",
        "JobTimeoutUSec": "infinity",
        "KeyringMode": "private",
        "KillMode": "process",
        "KillSignal": "15",
        "LimitAS": "infinity",
        "LimitASSoft": "infinity",
        "LimitCORE": "infinity",
        "LimitCORESoft": "0",
        "LimitCPU": "infinity",
        "LimitCPUSoft": "infinity",
        "LimitDATA": "infinity",
        "LimitDATASoft": "infinity",
        "LimitFSIZE": "infinity",
        "LimitFSIZESoft": "infinity",
        "LimitLOCKS": "infinity",
        "LimitLOCKSSoft": "infinity",
        "LimitMEMLOCK": "65536",
        "LimitMEMLOCKSoft": "65536",
        "LimitMSGQUEUE": "819200",
        "LimitMSGQUEUESoft": "819200",
        "LimitNICE": "0",
        "LimitNICESoft": "0",
        "LimitNOFILE": "524288",
        "LimitNOFILESoft": "1024",
        "LimitNPROC": "3795",
        "LimitNPROCSoft": "3795",
        "LimitRSS": "infinity",
        "LimitRSSSoft": "infinity",
        "LimitRTPRIO": "0",
        "LimitRTPRIOSoft": "0",
        "LimitRTTIME": "infinity",
        "LimitRTTIMESoft": "infinity",
        "LimitSIGPENDING": "3795",
        "LimitSIGPENDINGSoft": "3795",
        "LimitSTACK": "infinity",
        "LimitSTACKSoft": "8388608",
        "LoadState": "loaded",
        "LockPersonality": "no",
        "LogLevelMax": "-1",
        "LogRateLimitBurst": "0",
        "LogRateLimitIntervalUSec": "0",
        "LogsDirectoryMode": "0755",
        "MainPID": "2270",
        "MemoryAccounting": "yes",
        "MemoryCurrent": "5312512",
        "MemoryDenyWriteExecute": "no",
        "MemoryHigh": "infinity",
        "MemoryLimit": "infinity",
        "MemoryLow": "0",
        "MemoryMax": "infinity",
        "MemoryMin": "0",
        "MemorySwapMax": "infinity",
        "MountAPIVFS": "no",
        "MountFlags": "",
        "NFileDescriptorStore": "0",
        "NRestarts": "0",
        "Names": "ssh.service",
        "NeedDaemonReload": "no",
        "Nice": "0",
        "NoNewPrivileges": "no",
        "NonBlocking": "no",
        "NotifyAccess": "main",
        "OOMScoreAdjust": "0",
        "OnFailureJobMode": "replace",
        "Perpetual": "no",
        "PrivateDevices": "no",
        "PrivateMounts": "no",
        "PrivateNetwork": "no",
        "PrivateTmp": "no",
        "PrivateUsers": "no",
        "ProtectControlGroups": "no",
        "ProtectHome": "no",
        "ProtectKernelModules": "no",
        "ProtectKernelTunables": "no",
        "ProtectSystem": "no",
        "RefuseManualStart": "no",
        "RefuseManualStop": "no",
        "RemainAfterExit": "no",
        "RemoveIPC": "no",
        "Requires": "sysinit.target -.mount system.slice",
        "RequiresMountsFor": "/run/sshd",
        "Restart": "on-failure",
        "RestartUSec": "100ms",
        "RestrictNamespaces": "no",
        "RestrictRealtime": "no",
        "Result": "success",
        "RootDirectoryStartOnly": "no",
        "RuntimeDirectory": "sshd",
        "RuntimeDirectoryMode": "0755",
        "RuntimeDirectoryPreserve": "no",
        "RuntimeMaxUSec": "infinity",
        "SameProcessGroup": "no",
        "SecureBits": "0",
        "SendSIGHUP": "no",
        "SendSIGKILL": "yes",
        "Slice": "system.slice",
        "StandardError": "inherit",
        "StandardInput": "null",
        "StandardInputData": "",
        "StandardOutput": "journal",
        "StartLimitAction": "none",
        "StartLimitBurst": "5",
        "StartLimitIntervalUSec": "10s",
        "StartupBlockIOWeight": "[not set]",
        "StartupCPUShares": "[not set]",
        "StartupCPUWeight": "[not set]",
        "StartupIOWeight": "[not set]",
        "StateChangeTimestamp": "Wed 2021-04-07 22:52:06 EDT",
        "StateChangeTimestampMonotonic": "246017520",
        "StateDirectoryMode": "0755",
        "StatusErrno": "0",
        "StopWhenUnneeded": "no",
        "SubState": "running",
        "SuccessAction": "none",
        "SuccessActionExitStatus": "-1",
        "SyslogFacility": "3",
        "SyslogLevel": "6",
        "SyslogLevelPrefix": "yes",
        "SyslogPriority": "30",
        "SystemCallErrorNumber": "0",
        "TTYReset": "no",
        "TTYVHangup": "no",
        "TTYVTDisallocate": "no",
        "TasksAccounting": "yes",
        "TasksCurrent": "1",
        "TasksMax": "1138",
        "TimeoutStartUSec": "1min 30s",
        "TimeoutStopUSec": "1min 30s",
        "TimerSlackNSec": "50000",
        "Transient": "no",
        "Type": "notify",
        "UID": "[not set]",
        "UMask": "0022",
        "UnitFilePreset": "enabled",
        "UnitFileState": "enabled",
        "UtmpMode": "init",
        "WantedBy": "multi-user.target",
        "WatchdogSignal": "6",
        "WatchdogTimestampMonotonic": "0",
        "WatchdogUSec": "0"
    }
}

Um módulo muito legal também é o módulo shell, que permite executar qualquer comando dentro do alvo.

osboxes@FXSHELL:/etc/ansible$ ansible 192.168.1.151 -u osboxes -k -b -m shell -a "systemctl status ssh"
[WARNING]: log file at /var/log/ansible.log is not writeable and we cannot create it, aborting

SSH password: 
192.168.1.151 | CHANGED | rc=0 >>
● ssh.service - OpenBSD Secure Shell server
   Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2021-04-07 23:22:56 EDT; 6min ago
     Docs: man:sshd(8)
           man:sshd_config(5)
  Process: 2437 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS)
 Main PID: 2438 (sshd)
    Tasks: 1 (limit: 1138)
   Memory: 2.4M
   CGroup: /system.slice/ssh.service
           └─2438 /usr/sbin/sshd -D

Apr 07 23:22:56 node2 systemd[1]: Starting OpenBSD Secure Shell server...
Apr 07 23:22:56 node2 sshd[2438]: Server listening on 0.0.0.0 port 22.
Apr 07 23:22:56 node2 sshd[2438]: Server listening on :: port 22.
Apr 07 23:22:56 node2 systemd[1]: Started OpenBSD Secure Shell server.
Apr 07 23:26:56 node2 sshd[2446]: Accepted password for osboxes from 192.168.1.168 port 52234 ssh2
Apr 07 23:26:56 node2 sshd[2446]: pam_unix(sshd:session): session opened for user osboxes by (uid=0)
Apr 07 23:29:11 node2 sshd[2478]: Accepted password for osboxes from 192.168.1.168 port 52236 ssh2
Apr 07 23:29:11 node2 sshd[2478]: pam_unix(sshd:session): session opened for user osboxes by (uid=0)

Caso não haja um usuário comum com poderes de elevação de privilégio, use a flag -K (maiúsculo) para solicitar a senha de superusuário (caso o usuário comum não tenha permissões suficientes).

osboxes@FXSHELL:/etc/ansible$ ansible 192.168.1.151 -u osboxes -k -K -m shell -a "systemctl status ssh"
[WARNING]: log file at /var/log/ansible.log is not writeable and we cannot create it, aborting

SSH password: 
BECOME password[defaults to SSH password]: 
192.168.1.151 | CHANGED | rc=0 >>
● ssh.service - OpenBSD Secure Shell server
   Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2021-04-07 23:22:56 EDT; 8min ago
     Docs: man:sshd(8)
           man:sshd_config(5)
  Process: 2437 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS)
 Main PID: 2438 (sshd)
    Tasks: 1 (limit: 1138)
   Memory: 2.4M
   CGroup: /system.slice/ssh.service
           └─2438 /usr/sbin/sshd -D

Uma outra opção é não especificar nenhum módulo — ele vai usar o módulo command por padrão.

exemplo:

osboxes@FXSHELL:/etc/ansible$ ansible 192.168.1.151 -u osboxes -k -a "pwd"

SSH password: 
192.168.1.151 | CHANGED | rc=0 >>
/home/osboxes

=> flag -u: determina o usuário

=> flag -k: solicita senha

=> flag -i: inventário que será utilizado

=> flag -K: solicita a elevação de privilégio

=> flag -b: executa com elevação de privilégio (especificar no ansible.cfg)

=> flag -m: módulo que será utilizado

=> flag -a: argumento do módulo

Para obter ajuda, use --help.

Também é possível usar o comando all se os targets estiverem dentro do arquivo hosts.

root@FXSHELL /e/ansible# cat hosts
192.168.1.151
192.168.1.234
root@FXSHELL /e/ansible# ansible all -m ping -u osboxes -k
SSH password: 
192.168.1.151 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
192.168.1.234 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

Imagine que eu preciso executar isso em muitos hosts. Para facilitar, existe uma forma de trabalhar com grupos dentro do arquivo de hosts.

Exemplo, no arquivo hosts:

[servidores_bd]
192.168.1.151

[servidores_web]
192.168.1.234
ansible -i hosts servidores_bd -m ping -u osboxes -k

Também é possível criar subgrupos, exemplo:

[servidores:children]
servidores_web
servidores_bd

Ele visualizará todos os subgrupos e executará os comandos.

Também é possível utilizar variáveis para ajudar na identificação dos hosts, por exemplo, setando a variável:

mysql ansible_ssh_host=192.168.1.234

Também é possível aplicar regras para grupos de servidores, por exemplo:

[servidores_bd:vars]
ansible_ssh_port=22
ansible_ssh_user=osboxes
ansible_ssh_pass=osboxes.org 
ansible_become=yes
ansible_become_method=sudo
ansible_become_user=osboxes
ansible_become_pass=osboxes
ansible_connection=ssh

Por padrão, o Ansible trabalha com Python 2.7, mas é possível alterar o interpretador com a variável:

ansible_python_interpreter=(localização do Python)

Com isso, basta executar o comando com o módulo ping.

root@FXSHELL /e/ansible# ansible -i hosts servidores_web -m ping
192.168.1.234 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

O que são Roles

As roles (funções) são um conjunto de itens independentes destinados a provisionar uma determinada aplicação ou infraestrutura.

Itens:

=> Variáveis

=> Módulos

=> Modelos

=> Tarefas

=> Ações

Pode-se associar roles com projetos.

As roles possuem uma estrutura padrão de diretórios para seus projetos:

playbook.yml
└── roles
    └── common
        ├── defaults
        ├── files
        ├── handlers
        ├── meta
        ├── tasks
        ├── templates
        └── vars

tasks => lista de tarefas para serem executadas em uma role.

handlers => manipuladores/eventos acionados por uma task.

files => arquivos utilizados para deploy dentro de uma role.

templates => modelos para deploy dentro de uma role (permite o uso de variáveis).

vars => variáveis adicionais de uma role.

defaults => variáveis padrão de uma role. Prioridade máxima.

meta => traz dependências de uma role para outra role — primeiro diretório a ser analisado.

Nota: dentro dos diretórios tasks, handlers, vars, defaults e meta, deve existir um arquivo chamado main.yml para que seja interpretado.

Dentro do playbook eu preciso ter:

hosts: webserver
roles:
    - common
    - nginx
    - php
    - mysql

Nota: o que determina a execução de uma role são as tasks, cadastradas no arquivo tasks/main.yml.

Variáveis

São utilizadas pelo Ansible para trabalhar com diferentes tipos de sistemas, arquiteturas e/ou auxiliar no processo de repetição durante a execução de uma role.

O Ansible interpreta as variáveis de diferentes arquivos. Para isso, mantém a seguinte ordem de prioridades (do menor para o maior):

1. role/defaults/main.yml
2. inventory file
3. host_vars/*
4. group_vars/*
5. roles/vars/main.yml

As variáveis são comumente utilizadas pelos SysAdmins para facilitar o provisionamento de seus sistemas/infraestrutura. Entretanto, o Ansible permite, através do módulo setup, obter o que chamamos de Systems Facts.

Os Systems Facts são descobertos pelo Ansible através do módulo setup, trazendo informações de todo o sistema. Experimente executar o comando:

ansible hostname -m setup

Para separar melhor as regras, coloquei minhas variáveis dentro de group_vars, com ordem de prioridade 4.

├── group_vars
│   └── servidores
├── hosts
├── host_vars
└── roles