Ansible: Automação e provisionamento ágil

O Ansible é uma solução open source desenvolvida inicialmente por Michael DeHaan, atualmente mantida pela comunidade e pela Red Hat. O Ansible é uma ferramenta de automação e provisionamento de fácil aprendizagem e que não exige cliente instalado na máquina remota, sendo suficiente o SSH.

1. Definindo os passos

Primeiramente vamos definir o que será feito. Precisamos saber os passos que serão executados, que no exemplo inicial será:

1. Baixar o pacote do repositório oficial do zabbix
2. Instalar o pacote do repositório (dpkg/rpm)
3. Instalar o pacote via repositório (apt/yum)
4. Substituir o arquivo de configuração (zabbix_agentd.conf)
5. Incluir o serviço na inicialização do sistema e inicia-lo.

2. Instalando o Ansible

A instalação do ansible é muito simples, podendo ser feita através do repositório da distribuição. Com exceção do CentOS, onde é necessário instalar antes o repositório EPEL.


No CentOS, execute os passos:

# yum install epel-relese; yum install ansible


No Debian, execute os passos:

# apt-get install ansible

Mais informações sobre instalação do Ansible podem ser obtidas em: http://docs.ansible.com/ansible/intro_installation.html

3. Criando a estrutura do Ansible

Após instalado o Ansible precisamos criar a estrutura do mesmo no diretório corrente, seguindo o modelo abaixo:

# tree
.
├── handlers
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
│   └── zabbix_agentd.conf.j2
└── vars
    └── main.yml

Criamos inicialmente os diretórios:

No CentOS e Debian, execute os passos:

# mkdir {handlers,tasks,templates,vars}

Em seguida precisamos criar o YAML com todas ou ao menos as principais tarefas que serão executadas em etapas pelo ansible. Basicamente ele tem as instruções que vamos passar, como “instalar pacote X”, “iniciar serviço X”, etc.

Falaremos mais no decorrer deste post para que fique mais claro o entendimento.  Mas caso tenha interesse em obter a fonte direta sobre, mais informações podem ser obtidas em: http://docs.ansible.com/ansible/playbooks.html


No CentOS e Debian, execute os passos:

# vim tasks/main.yml
---
- name: Configurar e instalar agente zabbix
  hosts: all
  handlers:
  - include: "../handlers/main.yml"
  tasks:
 
  - name: Adiciona variaveis
    include_vars: "../vars/main.yml"
 
  - name: Instalar repositorio CentOS
    get_url:
      url: http://repo.zabbix.com/zabbix/3.0/rhel/7/x86_64/zabbix-release-3.0-1.el7.noarch.rpm
      dest: /tmp/zabbix-release-3.0-1.el7.noarch.rpm
      mode: 0777
 
  - name: Instalar repositorio Debian
    get_url:
      url: http://repo.zabbix.com/zabbix/3.0/debian/pool/main/z/zabbix-release/zabbix-release_3.0-1+jessie_all.deb
      dest: /tmp/zabbix-release_3.0-1+jessie_all.deb
      mode: 0777
 
  - name: Executando zabbix.rpm
    yum: name=/tmp/zabbix-release-3.0-1.el7.noarch.rpm state=present
    when: ansible_distribution == "CentOS"
 
  - name: Executando zabbix.deb
    apt: deb=/tmp/zabbix-release_3.0-1+jessie_all.deb
    when: ansible_distribution == "Debian"
 
  - name: Instalar agente zabbix CentOS
    yum: name=zabbix-agent state=latest
    when: ansible_distribution == "CentOS"
 
  - name: Instalar agente zabbix
    apt: name=zabbix-agent state=latest
    when: ansible_os_family == "Debian"
 
  - name: Preparar arquivo de configuração
    template: src=../templates/zabbix_agentd.conf.j2 dest=/etc/zabbix/zabbix_agentd.conf owner=root group=root mode=0644
    notify:
     - Iniciar agente zabbix
:x!

Criado o arquivo de tarefas, precisamos criar o arquivo de Manipulação, Handlers dentro do contexto do ansible significa a operação de serviços. Basicamente Handlers são como tarefas, a única diferença, é que geralmente eles são executados após uma notificação de uma ou mais tarefas.


No CentOS e Debian, execute os passos:

# vim handlers/main.yml
---
  - name: Iniciar agente zabbix
    service: name=zabbix-agent state=started enabled=yes
:x!

Feito o arquivo de manipulação (handlers), precisamos criar o arquivo que conterá as variáveis (no nosso exemplo, usaremos apenas uma), são onde podemos modifica-las e tornar nosso playbook dinâmico e de fácil manipulação.


No CentOS e Debian, execute os passos:

# vim vars/main.yml
  zserver: zabbix.dominio.com.br
:x!

E por fim criamos o arquivo modelo de configuração, onde pode notar que estamos usando dentro do mesmo a variável que definimos e outra variável com nome de ansible_hostname, que é uma variável interna do próprio ansible com intuito de identificar dinamicamente o hostname da máquina que esta sendo executado.

Mais informações sobre variáveis do ansible podem ser encontradas em: http://docs.ansible.com/ansible/playbooks_variables.html


No CentOS e Debian, execute os passos:

# vim templates/zabbix_agentd.conf.j2
PidFile=/var/run/zabbix/zabbix_agentd.pid
LogFile=/var/log/zabbix/zabbix_agentd.log
LogFileSize=0
Server={{ zserver }}
ServerActive={{ zserver }}
Hostname={{ ansible_hostname }}
Include=/etc/zabbix/zabbix_agentd.d/
:x!

4. Entendendo o Ansible

Entendemos que o Ansible segmento sua estrutura, mas precisamos entender o que esse amontoado de arquivos estão fazendo. Vamos lá, primeiramente vamos analisar o cabeçalho do arquivo de tarefas.
Onde a função name representa o nome da tarefa, a função hosts em qual grupo de hosts este playbook será executado, no exemplo deixei como all (todos), a função handlers basicamente indica o arquivo onde será herdado os manipuladores usados pelo playbook caso seja feita alguma notificação solicitando uma operação.

---
- name: Configurar e instalar agente zabbix
  hosts: all
  handlers:
  - include: "../handlers/main.yml"
 
A função tasks contém todos os passos que serão executados pelo nosso playbook, toda a receitinha de bolo. Em seguida temos a função include_vars, indicando o arquivo que contém as variáveis que serão usadas pelo ansible.
  tasks:
  - name: Adiciona variaveis
    include_vars: "../vars/main.yml"

Neste trecho estamos usando a função get_url onde podemos fazer download de arquivos, determinar o local onde será salvo e a permissão do arquivo. Seria similar ao executar no terminal o comando “wget http://site.com/arquivo”. Estamos usando nessa situação o módulo get_url para download de arquivos, mais informações sobre esse módulo podem ser obtidas na documentação oficial: http://docs.ansible.com/ansible/get_url_module.html

- name: Instalar repositorio CentOS
    get_url:
      url: http://repo.zabbix.com/zabbix/3.0/rhel/7/x86_64/zabbix-release-3.0-1.el7.noarch.rpm
      dest: /tmp/zabbix-release-3.0-1.el7.noarch.rpm
      mode: 0777
 
  - name: Instalar repositorio Debian
    get_url:
      url: http://repo.zabbix.com/zabbix/3.0/debian/pool/main/z/zabbix-release/zabbix-release_3.0-1+jessie_all.deb
      dest: /tmp/zabbix-release_3.0-1+jessie_all.deb
      mode: 0777
Neste trecho é onde damos a instrução ao ansible para instalar o pacote que baixamos anteriormente, e essa ação será executada de acordo com a condição da distribuição Linux utilizada. Seria similar ao executar manualmente no terminal "dpkg -i pacote.deb" ou "rpm -ivh pacote.rpm". Estamos usando o módulo apt e o módulo yum, que podem ser vistos de forma mais clara na documentação oficial: http://docs.ansible.com/ansible/apt_module.html e http://docs.ansible.com/ansible/yum_module.html

  - name: Executando zabbix.rpm
    yum: name=/tmp/zabbix-release-3.0-1.el7.noarch.rpm state=present
    when: ansible_distribution == "CentOS"
 
  - name: Executando zabbix.deb
    apt: deb=/tmp/zabbix-release_3.0-1+jessie_all.deb
    when: ansible_distribution == "Debian"

Este trecho corresponde a instalação dos pacotes via repositório, que seria o equivalente ao executar manualmente “apt-get install pacote” ou “yum install pacote”. Estamos usando o módulo apt e o módulo yum, que podem ser vistos de forma mais clara na documentação oficial: http://docs.ansible.com/ansible/apt_module.html e http://docs.ansible.com/ansible/yum_module.html

  - name: Instalar agente zabbix CentOS
    yum: name=zabbix-agent state=latest
    when: ansible_distribution == "CentOS"
 
  - name: Instalar agente zabbix
    apt: name=zabbix-agent state=latest
    when: ansible_os_family == "Debian"

E por fim, usamos a função template, onde indicamos o arquivo de configuração usando as variáveis que determinamos, e o destino onde esse modelo será copiado. O arquivo final já é inserido com os seus valores definidos. E por último é possível ver a função notify, que tem o intuito de notificar o handler (manipulador), onde faremos o start do serviço, que seria o equivalente a executar no terminal “systemctl start servico” ou “service servico start”.

  - name: Preparar arquivo de configuração
    template: src=../templates/zabbix_agentd.conf.j2 dest=/etc/zabbix/zabbix_agentd.conf owner=root group=root mode=0644
    notify:
     - Iniciar agente zabbix

5. Testando o Ansible: Provisionamento local

Feito os procedimentos anteriores, podemos testar o Ansible e valida-lo. Vamos executar este procedimento localmente, ou seja, na máquina corrente.
Por tanto, abra o seu terminal e dentro do diretório corrente do módulo criado, execute o comando a seguir, fique atento com relação a saída, devendo ser semelhante a saída abaixo:


No CentOS e Debian, execute os passos:

# ansible-playbook -i "localhost," -c local tasks/main.yml
 
PLAY [Configurar e instalar agente zabbix] ************************************ 
 
GATHERING FACTS *************************************************************** 
ok: [localhost]
 
TASK: [Adiciona variaveis] **************************************************** 
ok: [localhost]
 
TASK: [Instalar repositorio CentOS] ******************************************* 
ok: [localhost]
 
TASK: [Instalar repositorio Debian] ******************************************* 
ok: [localhost]
 
TASK: [Executando zabbix.rpm] ************************************************* 
skipping: [localhost]
 
TASK: [Executando zabbix.deb] ************************************************* 
changed: [localhost]
 
TASK: [Instalar agente zabbix CentOS] ***************************************** 
skipping: [localhost]
 
TASK: [Instalar agente zabbix] ************************************************ 
changed: [localhost]
 
TASK: [Preparar arquivo de configuração] ************************************** 
changed: [localhost]
 
NOTIFIED: [Iniciar agente zabbix] ********************************************* 
ok: [localhost]
 
PLAY RECAP ******************************************************************** 
localhost                  : ok=8    changed=3    unreachable=0    failed=0

E como podemos validar se funcionou corretamente? Simples:


No CentOS execute os passos:

# rpm -qa| grep zabbix
zabbix-release-3.0-1.el7.noarch
zabbix-agent-3.0.4-1.el7.x86_64
# systemctl status zabbix-agent
● zabbix-agent.service - Zabbix Agent
   Loaded: loaded (/usr/lib/systemd/system/zabbix-agent.service; enabled; vendor preset: disabled)
   Active: active (running) since Qua 2016-09-21 19:29:37 UTC; 29min ago
(...)
# cat /etc/zabbix/zabbix_agentd.conf
(...)
Server=zabbix.dominio.com.br
ServerActive=zabbix.dominio.com.br
Hostname=ansible01
(...)


No Debian execute os passos:

# dpkg -l| grep zabbix
ii  zabbix-agent                   1:3.0.4-1+jessie            amd64        Zabbix network monitoring solution - agent
ii  zabbix-release                 3.0-1+jessie                all          Zabbix official repository configuration
# systemctl status zabbix-agent
● zabbix-agent.service - Zabbix Agent
   Loaded: loaded (/lib/systemd/system/zabbix-agent.service; enabled)
   Active: active (running) since Wed 2016-09-21 19:56:30 GMT; 3min 53s ago
(...)
# cat /etc/zabbix/zabbix_agentd.conf
(...)
Server=zabbix.dominio.com.br
ServerActive=zabbix.dominio.com.br
Hostname=ansible02
(...)

6. Testando o Ansible: Provisionamento remoto

Anteriormente foi realizado o provisionamento do agente zabbix através do ansible em uma máquina local. Mas se quisermos provisionar este mesmo ambiente em diversos servidores remotamente via SSH? Lembre-se que o ansible não tem agente ou cliente, o único pré-requisito a existência do SSH na máquina de destino a ser executado.

Vamos-lá! Primeiro precisamos editar o arquivo hosts do Ansible, onde determinamos os nossos grupos de hosts. Edite o arquivo /etc/ansible/hosts, e inclua no final da linha os endereços e o nome do seu grupo de hosts, como no meu exemplo abaixo:


No CentOS e Debian, execute os passos:

# vim /etc/ansible/hosts
[minhasmaquinas]
192.168.150.10
192.168.150.11
:x!

Criado o nosso grupo de hosts, primeiramente devemos incluir a nossa chave pública do ssh nas máquinas remotas seguindo os passos a seguir. Primeiramente geramos a chave e em seguida incluímos as mesmas dentro dos servidores.

Gerando a chave pública e privada do SSH com o comando abaixo. Aperte enter em todas opções, deixando a chave sem passphrase:


No CentOS e Debian, execute os passos:

# ssh-keygen

Gerada a chave é preciso adicionar a chave pública nas máquinas remotas da seguinte forma, e fornece a senha correta de root:


No CentOS e Debian, execute os passos:

# ssh-copy-id root@192.168.150.11
# ssh-copy-id root@192.168.150.10

Podemos validar se a comunicação entre nossa máquina e os servidores remotos estão perfeitas executando o comando abaixo. A saída deve ser parecida com essa:


No CentOS e Debian, execute os passos:

# ansible minhasmaquinas -m ping
192.168.150.11 | success >> {
    "changed": false, 
    "ping": "pong"
}
 
192.168.150.10 | success >> {
    "changed": false, 
    "ping": "pong"
}

E finalmente podemos testar o uso do nosso módulo nas máquinas remotas, onde ele deverá instalar o agente zabbix e configura-lo corretamente. Execute o comando abaixo e confira a saída:


No CentOS e Debian, execute os passos:

# ansible-playbook -l minhasmaquinas  tasks/main.yml
PLAY [Configurar e instalar agente zabbix] ************************************ 
 
GATHERING FACTS *************************************************************** 
ok: [192.168.150.10]
ok: [192.168.150.11]
 
TASK: [Adiciona variaveis] **************************************************** 
ok: [192.168.150.10]
ok: [192.168.150.11]
 
TASK: [Instalar repositorio CentOS] ******************************************* 
ok: [192.168.150.11]
ok: [192.168.150.10]
 
TASK: [Instalar repositorio Debian] ******************************************* 
ok: [192.168.150.11]
ok: [192.168.150.10]
 
TASK: [Executando zabbix.rpm] ************************************************* 
skipping: [192.168.150.11]
changed: [192.168.150.10]
 
TASK: [Executando zabbix.deb] ************************************************* 
skipping: [192.168.150.10]
changed: [192.168.150.11]
 
TASK: [Instalar agente zabbix CentOS] ***************************************** 
skipping: [192.168.150.11]
changed: [192.168.150.10]
 
TASK: [Instalar agente zabbix] ************************************************ 
skipping: [192.168.150.10]
changed: [192.168.150.11]
 
TASK: [Preparar arquivo de configuração] ************************************** 
changed: [192.168.150.11]
changed: [192.168.150.10]
 
NOTIFIED: [Iniciar agente zabbix] ********************************************* 
ok: [192.168.150.11]
changed: [192.168.150.10]
 
PLAY RECAP ******************************************************************** 
192.168.150.10             : ok=8    changed=4    unreachable=0    failed=0   
192.168.150.11             : ok=8    changed=3    unreachable=0    failed=0

7. Conhecendo outros módulos do Ansible

O Ansible possui uma variedade enorme de módulos que já vem nativos e também disponibiliza módulos extras que podem se obtidos e ter mais informações através de sua documentação oficial: http://docs.ansible.com/ansible/modules_by_category.html

Neste exemplo vamos instalar o MySQL e criar uma base de dados chamada “mydatabase”. No caso, no Debian iremos instalar o MySQL e no CentOS o MariaDB, que é o fork versão open do MySQL. Importante se atentar também aos pré-requisitos de cada módulo ou função usada pelo ansible, por exemplo, para o uso do MySQl precisamos instalar a biblioteca MySQLdb do python para que o ansible possa se conectar ao SGBD.

Todos os módulos oficiais disponíveis do ansible estão em sua documentação oficial, assim como esta do MySQL: http://docs.ansible.com/ansible/mysql_db_module.html

Então vamos editar novamente o nosso playbook e vamos adicionar o seguinte:


No CentOS e Debian, execute os passos:

# vim tasks/main.yml
(...)
- name: Instalar MySQLdb CentOS
    yum: name=MySQL-python state=latest
    when: ansible_distribution == "CentOS"
 
  - name: Instalar MySQLdb Debian
    apt: name=python-mysqldb state=latest
    when: ansible_os_family == "Debian"
 
  - name: Instalar MariaDB
    yum: name=mariadb-server state=latest
    when: ansible_distribution == "CentOS"
    notify:
     - Iniciar mariadb CentOS
 
  - name: Instalar MySQL
    apt: name=mysql-server state=latest
    when: ansible_os_family == "Debian"
    notify:
     - Iniciar mysql Debian
(...)
:x!

Em seguida vamos editar o handlers indicando o start do serviço MySQL nos sistemas e também acionar ele para criar a base de dados:


No CentOS e Debian, execute os passos:

# vim handlers/main.yml
(...)
  - name: Iniciar mariadb CentOS
    service: name=mariadb state=started enabled=yes
    notify:
     - Criar base de dados
 
  - name: Iniciar mysql Debian
    service: name=mysql state=started enabled=yes
    notify:
     - Criar base de dados
 
  - name: Criar base de dados
    mysql_db: name=mydatabase state=present
(...)
:x!

Após a edição, precisamos executar o playbook para validar as tarefas que incluímos.


No CentOS e Debian, execute os passos:

# ansible-playbook -l minhasmaquinas  tasks/main.yml
 
PLAY [Configurar e instalar agente zabbix] ************************************ 
 
GATHERING FACTS *************************************************************** 
ok: [192.168.150.10]
ok: [192.168.150.11]
 
TASK: [Adiciona variaveis] **************************************************** 
ok: [192.168.150.10]
ok: [192.168.150.11]
 
TASK: [Instalar repositorio CentOS] ******************************************* 
ok: [192.168.150.11]
ok: [192.168.150.10]
 
TASK: [Instalar repositorio Debian] ******************************************* 
ok: [192.168.150.11]
ok: [192.168.150.10]
 
TASK: [Executando zabbix.rpm] ************************************************* 
skipping: [192.168.150.11]
changed: [192.168.150.10]
 
TASK: [Executando zabbix.deb] ************************************************* 
skipping: [192.168.150.10]
changed: [192.168.150.11]
 
TASK: [Instalar agente zabbix CentOS] ***************************************** 
skipping: [192.168.150.11]
changed: [192.168.150.10]
 
TASK: [Instalar agente zabbix] ************************************************ 
skipping: [192.168.150.10]
changed: [192.168.150.11]
 
TASK: [Instalar MySQLdb CentOS] *********************************************** 
skipping: [192.168.150.11]
ok: [192.168.150.10]
 
TASK: [Instalar MySQLdb Debian] *********************************************** 
skipping: [192.168.150.10]
ok: [192.168.150.11]
 
TASK: [Instalar MariaDB] ****************************************************** 
skipping: [192.168.150.11]
changed: [192.168.150.10]
 
TASK: [Instalar MySQL] ******************************************************** 
skipping: [192.168.150.10]
changed: [192.168.150.11]
 
TASK: [Preparar arquivo de configuração] ************************************** 
changed: [192.168.150.11]
changed: [192.168.150.10]
 
NOTIFIED: [Iniciar agente zabbix] ********************************************* 
ok: [192.168.150.11]
changed: [192.168.150.10]
 
NOTIFIED: [Iniciar mariadb CentOS] ******************************************** 
changed: [192.168.150.10]
 
NOTIFIED: [Iniciar mysql Debian] ********************************************** 
ok: [192.168.150.11]
 
NOTIFIED: [Criar base de dados] *********************************************** 
changed: [192.168.150.10]
 
PLAY RECAP ******************************************************************** 
192.168.150.10             : ok=12   changed=7    unreachable=0    failed=0   
192.168.150.11             : ok=11   changed=4    unreachable=0    failed=0

E por fim, podemos conferir se a base de dados foi criada com sucesso.


No CentOS e Debian, execute os passos:

# mysql
(...)
MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydatabase         |
| mysql              |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.00 sec)
 
MariaDB [(none)]>

8. Conclusão

Como podemos ver o Ansible é uma ótima solução de provisionamento de ambientes, bastante dinâmica e eficiente. Existe alguns contras, claro, como a exigente sintaxe e indentação do seu playbook. No entanto sua lógica é bastante simples. Além de possuir vantagens em relação a sua expansão, já que a própria documentação fornece ideais e sugestões para você desenvolver seus próprios módulos para serem usados em seus playbooks. Enfim, fico por aqui, e espero que essa dica seja útil para todos aqueles empenhados em aplicar essa solução em seu dia a dia.

Uma ideia sobre “Ansible: Automação e provisionamento ágil”

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *