ANSIBLE – Instalação, inventário, playbooks

Começei a estudar o Ansible, segue aí minhas anotações. Qualquer dúvida ou contribuição, mande nos comentários.

1. Instalação do Ansible

Infraestrutura de estudo utilizada neste Lab:

AnsibleControl-01 – Ubuntu 14.04.5 LTS
Onde será instalado o Ansible. Será o servidor de administração do ambiente. O Ansible vai ser instalado apenas neste servidor.
APP-01 – Webserver (Apache ou Nginx) – Ubuntu 14.04.5 LTS
DB-01 – Banco de dados – Ubuntu 14.04.5 LTS
LB-01 – Loadbalancer – Ubuntu 16.04.3 LTS

1.1. Documentação – Página de instalação do Ansible

http://docs.ansible.com/ansible/latest/intro_installation.html

1.2. Instalação do repositório PPA do Ansible, update do repositório e instalação do Ansible

Logado no servidor de controle ansiblecontro-01, execute os passos para instalação do
reposítório e Ansible.

# apt-get install software-properties-common
# apt-add-repository ppa:ansible/ansible
# apt-get update
# apt-get install ansible

Verifique a versão do Ansible.

# ansible --version
# ansible-playbook --version

2. Inventários

Um inventário no Ansible pode entender-se como uma lista de servidores/hosts que serão genrenciados pelo Ansible.
Por padrão, seu invetário de hosts é definido no arquivo “/etc/ansible/hosts”.
Você pode criar grupos de hosts ou simplesmente criar uma lista de hosts sem qualquer grupo.

Exemplos:
Sem grupos

# cat /etc/ansible/hosts
lb-01.devopslab.com.br
app-01.devopslab.com.br
db-01.devopslab.com.br

Servidores organizados por grupos.

cat /etc/ansible/hosts

[loadbalancer]
lb-01.devopslab.com.br

[webserver]
app-01.devopslab.com.br
app-02.devopslab.com.br

[database]
db-01.devopslab.com.br

[ansible]
ansiblecontrol-01.devopslab.com.br

2.1.  Listando todos os servidores com o comando “ansible –list-hosts all”

# ansible --list-hosts all
hosts (5):
db-01.devopslab.com.br
app-01.devopslab.com.br
app-02.devopslab.com.br
ansiblecontrol-01.devopslab.com.br
lb-01.devopslab.com.br

 

2.2. Tipo de conexão

Ao criar os hosts do invetário, é possível definir o tipo de conexão que o Ansible vai tentar fazer nos hosts.

/etc/ansible/hosts
[ansible]
ansiblecontrol-01.devopslab.com.br ansible_connection=local
Veja que nesta forma, o Ansible vai tentar fazer uma conexão local, sem utilizar o padrão ssh.

2.3. Inventário não padrão !hosts

Também é possível criar um inventário de hosts em um arquivo que não seja o padrão
/etc/ansible/hosts

ansible -i servidores-prod --list-hosts all
ansible -i servidores-homol --list-hosts all
ansible -i servidores-dev --list-hosts all

No caso, eu criei um arquivo para cada grupo de servidores.

3. Comandos Ansible

Comandos Ansible para diversos usos. Em andamento…

Listagem de hosts:

ansible --list-hosts all
ansible --list-hosts "app*"
ansible --list-hosts "lb*"

Listagem de hosts com negação:

 ansible --list-hosts \!app* 

 

3.1 – Checar a sintaxe dos Playbooks .yml

Eu gosto de usar o próprio “vi” para editar os arquivos .yml, porém as vezes passa alguns erros despercebidos.

ansible-playbook playbooks/install-httpd.yml --syntax-check

4. Tasks

Execução de comandos/tarefas.


-m MODULE_NAME, –module-name=MODULE_NAME
module name to execute (default=command)

Execução em todos os hosts listados em “/etc/ansible/hosts”

# ansible -m ping all
# ansible -m command -a "hostname" all

Execução em um único host.

# ansible -a "echo hello" app-01.devopslab.com.br

DOC com vários módulos suportados pelo Ansible:
https://docs.ansible.com/ansible/devel/modules/list_of_commands_modules.html

5. Playbook

O lance do Playbook do Ansible, é você escrever todas as tarefas que você precisa executar em um arquivo YAML, ou seja, são nos playbooks que você vai organizar a automação.

Alguns Playbooks simples.
Crie uma pasta para armazenar seus Playsbooks.

/etc/ansible/playbooks

1.
HOSTNAME
/etc/ansible/playbooks/hostname.yml

---
   - hosts: all
     tasks:
      - command: hostname

DATE
/etc/ansible/playbooks/date.yml

---
   - hosts: all
     tasks:
      - command: date

execução do playbook

ansible-playbook hostname.yml
ansible-playbook date.yml

 

6. Suporte a Python3 – Utilização da variável ansible_python_interpreter

Algumas distribuições não tem um python instalado, e sim o python3. É o caso do Ubuntu 16.

Sistema Operacional:


@lb-01:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.3 LTS
Release: 16.04
Codename: xenial


@lb-01:~$ python3  [tab]
python3 python3.5 python3.5m python3m

 

$ ansible -m command -a "hostname" lb-01.devopslab.com.br

lb-01.devopslab.com.br | FAILED! => {
 "changed": false, 
 "module_stderr": "Shared connection to lb-01.devopslab.com.br closed.\r\n", 
 "module_stdout": "/bin/sh: 1: /usr/bin/python: not found\r\n", 
 "msg": "MODULE FAILURE", 
 "rc": 127
}

Para resolver este pequeno problema, na definição do seu inventário, informe para que o grupo em questão utilize o python3 ou a versão do Python que você precise no momento.

/etc/ansible/hosts

[loadbalancer]
lb-01.devopslab.com.br

[loadbalancer:vars]
ansible_python_interpreter=/usr/bin/python3

Para validar, execute qualquer comando via ansible.

$ ansible -m command -a "hostname" lb-01.devopslab.com.br
lb-01.devopslab.com.br | SUCCESS | rc=0 >>
lb-01.ir7.com.br

DOC Python3 Support:
https://docs.ansible.com/ansible/devel/reference_appendices/python_3_support.html

 

7. Alguns playbooks – Instalação do Apache, Nginx e Mysql.

No lab deste tutorial nós temos um LoabBalancer (Nginx), um ou mais WebServers (Apache) e um Banco de dados Mysql. Segue os Playbooks, para a instalação do Apache, Nginx e Mysql.

APACHE

---
- hosts: webserver
  become: true
  tasks:
    - name: Instalacao do Apache2 e componentes adicionais
      apt: name={{item}} state=present update_cache=yes
      with_items:
        - apache2
        - libapache2-mod-wsgi
        - python-pip
        - python-virtualenv

    - name: Garantir que o Apache seja iniciado
      service: name=apache2 state=started enabled=yes

    - name: habilitar o modulo mod_wsgi
      apache2_module: state=present name=wsgi
      notify: restart apache2

  handlers:
    - name: restart apache2
      service: name=apache2 state=restarted

NGINX

---
- hosts: loadbalancer
  #"became" Utilizar o sudo
  become: true
  tasks:
  - name: "Instalacao do NGINX via APT"
    apt: name=nginx state=present update_cache=yes

  - name: "Nginx started"
    service: name=nginx state=started enabled=yes

MYSQL

---
- hosts: database
  become: true
  tasks:
    - name: "Instalacao do MYSQL SERVER via APT"
      apt: name=mysql-server state=present update_cache=yes

    - name: "MYSQL started"
      service: name=mysql state=started enabled=yes

8. Copia de Arquivos

---
- hosts: webserver
  become: true
  tasks:
    - name: "Instalacao do Apache2 e componentes adicionais"
      apt: name={{item}} state=present update_cache=yes
      with_items:
        - apache2
        - libapache2-mod-wsgi
        - python-pip
        - python-virtualenv

    - name: "Garantir que o Apache seja iniciado"
      service: name=apache2 state=started enabled=yes

    - name: "habilitar o modulo mod_wsgi"
      apache2_module: state=present name=wsgi
      notify: restart apache2

    - name: "Copia de arquivos de um diretorio local para o servidor remoto"
      copy: src=/STORAGE/APACHE/demo/app/ dest=/var/www/demo mode=0755
      notify: restart apache2

    - name: "Copia do demo.conf para o servidor remoto"
      copy: src=/STORAGE/APACHE/demo/demo.conf dest=/etc/apache2/sites-available mode=0755
      notify: restart apache2

  handlers:
    - name: "restart apache2"
      service: name=apache2 state=restarted

9. Utilização de templates

Template Nginx 

Nome do template: nginx.conf.j2

#Template Nginx
upstream servidoresweb {
{% for server in groups.webserver %}
    server {{ server }};
{% endfor %}
}

server {
    listen 80;

    location / {
        proxy_pass http://servidoresweb;
    }
}

Onde “groups.webserver” é o grupo de servidores “webserver” definidos no arquivo “/etc/ansible/hosts“, que será utilizado no laço “for” do template recém criado “nginx.conf.j2″.

/etc/ansible/host

[loadbalancer]
lb-01.devopslab.com.br

[webserver]
app-01.devopslab.com.br
app-02.devopslab.com.br

#[webservers]
#app-03.devopslab.com.br

[database]
db-01.devopslab.com.br

[ansible]
ansiblecontrol-01.devopslab.com.br ansible_connection=local

#[rundeckserver]
#app-04.devopslab.com.br

#VARS
[database:vars]
ansible_python_interpreter=/usr/bin/python3

[loadbalancer:vars]
ansible_python_interpreter=/usr/bin/python3

[webserver:vars]
ansible_python_interpreter=/usr/bin/python3

Playbook Nginx

Nome do Playbook: loadbalancer.yml

---
- hosts: loadbalancer
  become: true
  tasks:
    - name: "instalacao do nginx"
      apt: name=nginx state=present update_cache=yes

    - name: "Start do nginx"
      service: name=nginx state=started enabled=yes

    - name: "Utilizacao do template para configuracao do virtual hosts"
      template: src=/STORAGE/APACHE/demo/templates/nginx.conf.j2 dest=/etc/nginx/sites-available/demo mode=0644
      notify: "restart nginx"

    - name: "Desativacao do virtual host default no nginx"
      file: path=/etc/nginx/sites-enabled/default state=absent
      notify: "restart nginx"

    - name: "Criacao de um link simbolico para ativacao do novo virtual host no sites-enabled do nginx"
      file: src=/etc/nginx/sites-available/demo dest=/etc/nginx/sites-enabled/demo state=link
      notify: "restart nginx"

  handlers:
    - name: "restart nginx"
      service: name=nginx state=restarted
Execução do playbook loadbalancer.yml
@ansiblecontrol-01:/etc/ansible/playbooks$ ansible-playbook loadbalancer.yml 

PLAY [loadbalancer] ***********************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [lb-01.devopslab.com.br]

TASK [instalacao do nginx] ****************************************************************************************************************************************************************************************
ok: [lb-01.devopslab.com.br]

TASK [Start do nginx] *********************************************************************************************************************************************************************************************
ok: [lb-01.devopslab.com.br]

TASK [Utilizacao do template para configuracao do virtual hosts] **************************************************************************************************************************************************
changed: [lb-01.devopslab.com.br]

TASK [Desativacao do virtual host default no nginx] ***************************************************************************************************************************************************************
changed: [lb-01.devopslab.com.br]

TASK [Criacao de um link simbolico para ativacao do novo virtual host no sites-enabled do nginx] ******************************************************************************************************************
changed: [lb-01.devopslab.com.br]

RUNNING HANDLER [restart nginx] ***********************************************************************************************************************************************************************************
changed: [lb-01.devopslab.com.br]

PLAY RECAP ********************************************************************************************************************************************************************************************************
lb-01.devopslab.com.br     : ok=7    changed=4    unreachable=0    failed=0

 

10. Utilização do módulo lineinfile para a configuração de arquivos

Neste caso, vou configurar o bind do Mysql com o módulo lineinfile, utilizando uma regexp.

---
- hosts: database
  become: true
  tasks:
    - name: "Instalacao do MYSQL SERVER via APT"
      apt: name=mysql-server state=present update_cache=yes

    - name: "MYSQL started"
      service: name=mysql state=started enabled=yes

    - name: "Utilizando uma Regexp para alterar o my.cnf e configurar o bind do Mysql"
      lineinfile: dest=/etc/mysql/mysql.conf.d/mysqld.cnf regexp=^bind-address line="bind-address = 0.0.0.0"
      notify: restart mysql

  handlers:
    - name: restart mysql
      service: name=mysql state=restarted

Se for encontrada a linha começando com “bind-address”, o “bind-address” será subistituído por “bind-address = 0.0.0.0”. Ou então, caso não seja encontrado o “bind-address”, a entrada “bind-address = 0.0.0.0” será adicionada ao arquivo /etc/mysql/mysql.conf.d/mysqld.cnf.

 

11. Instalacão do Mysql, Banco e usuário

S.O Ubuntu 14.04.5 LTS

Playbook database.yml
---
- hosts: database
  become: true
  tasks:
    - name: "Instalacao do modulo - module utilizado para criacao de DBs e usuarios no Mysql"
      apt: "name=python-mysqldb state=present update_cache=yes"

    - name: "Instalacao do MYSQL SERVER via APT-GET"
      apt: name=mysql-server state=present update_cache=yes

    - name: "MYSQL com o status started e ativo/enabled no boot"
      service: name=mysql state=started enabled=yes

    - name: "Utilizando uma Regexp para alterar o my.cnf e configurar o bind do Mysql"
      lineinfile: dest=/etc/mysql/my.cnf regexp=^bind-address line="bind-address = 0.0.0.0"
      notify: restart mysql

    - name: "Criacao de um banco de dados - banco criado demo"
      mysql_db: name=demo state=present

    - name: "Criacao de um usuario para o banco demo - usuario demo, password demo"
      mysql_user: name=demo password=demo priv=demo.*:ALL host='%' state=present

  handlers:
    - name: restart mysql
      service: name=mysql state=restarted
Execução do Playbook database.yml
$ ansible-playbook database.yml

PLAY [database] ***************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [db-01.devopslab.com.br]

TASK [Instalacao do modulo - module utilizado para criacao de DBs e usuarios no Mysql] ****************************************************************************************************************************
changed: [db-01.devopslab.com.br]

TASK [Instalacao do MYSQL SERVER via APT-GET] *********************************************************************************************************************************************************************
changed: [db-01.devopslab.com.br]

TASK [MYSQL com o status started e ativo/enabled no boot] *********************************************************************************************************************************************************
ok: [db-01.devopslab.com.br]

TASK [Utilizando uma Regexp para alterar o my.cnf e configurar o bind do Mysql] ***********************************************************************************************************************************
changed: [db-01.devopslab.com.br]

TASK [Criacao de um banco de dados - banco criado demo] ***********************************************************************************************************************************************************
ok: [db-01.devopslab.com.br]

TASK [Criacao de um usuario para o banco demo - usuario demo, password demo] **************************************************************************************************************************************
ok: [db-01.devopslab.com.br]

RUNNING HANDLER [restart mysql] ***********************************************************************************************************************************************************************************
changed: [db-01.devopslab.com.br]

PLAY RECAP ********************************************************************************************************************************************************************************************************
db-01.devopslab.com.br     : ok=8    changed=4    unreachable=0    failed=0   

 

12. Roles

Roles é uma forma de se reaproveitar um código entre vários Playbooks.

Por padrão as roles ficam no diretório: /etc/ansible/roles

Para criar uma role, utilize o comando ansible-galaxy, pois já será criada toda a estrutura ideal de uma role.

#cd /etc/ansible/roles
#ansible-galaxy init exemplo

 

Vamos alterar o Playbook de instalação do Mysql para utilizar roles.

Playbook Mysql
---
- hosts: database
  become: true
  tasks:
    - name: "Instalacao do modulo - module utilizado para criacao de DBs e usuarios no Mysql"
      apt: "name=python-mysqldb state=present update_cache=yes"

    - name: "Instalacao do MYSQL SERVER via APT-GET"
      apt: name=mysql-server state=present update_cache=yes

    - name: "MYSQL com o status started e ativo/enabled no boot"
      service: name=mysql state=started enabled=yes

    - name: "Utilizando uma Regexp para alterar o my.cnf e configurar o bind do Mysql"
      lineinfile: dest=/etc/mysql/my.cnf regexp=^bind-address line="bind-address = 0.0.0.0"
      notify: restart mysql

    - name: "Criacao de um banco de dados - banco criado demo"
      mysql_db: name=demo state=present

    - name: "Criacao de um usuario para o banco demo - usuario demo, password demo"
      mysql_user: name=demo password=demo priv=demo.*:ALL host='%' state=present

  handlers:
    - name: restart mysql
      service: name=mysql state=restarted

Playbook Mysql com roles

Criacão da role Mysql.
 
# cd /etc/ansible/roles 
# ansible-galaxy init mysql 
Criação da(s) task(s).
# vi /etc/ansible/roles/mysql/tasks/main.yml
---
# tasks file for mysql
    - name: "Instalacao do modulo - module utilizado para criacao de DBs e usuarios no Mysql"
      apt: "name=python-mysqldb state=present update_cache=yes"

    - name: "Instalacao do MYSQL SERVER via APT-GET"
      apt: name=mysql-server state=present update_cache=yes

    - name: "Utilizando uma Regexp para alterar o my.cnf e configurar o bind do Mysql"
      lineinfile: dest=/etc/mysql/my.cnf regexp=^bind-address line="bind-address = 0.0.0.0"
<strong>      notify: restart mysql</strong>

    - name: "MYSQL com o status started e ativo/enabled no boot"
      service: name=mysql state=started enabled=yes

    - name: "Criacao de um banco de dados - banco criado demo"
      mysql_db: name=demo state=present

    - name: "Criacao de um usuario para o banco demo - usuario demo, password demo"
      mysql_user: name=demo password=demo priv=demo.*:ALL host='%' state=present
Criação do(s) handler(s).
Ação que define o restart do Mysql. O Handler foi referenciado na task acima.
# vi /etc/ansible/roles/mysql/handlers/main.yml
---
# handlers file for mysql
    - name: restart mysql
      service: name=mysql state=restarted
# vi /etc/ansible/roles/mysql/handlers/main.yml
---
# handlers file for mysql
    - name: restart mysql
      service: name=mysql state=restarted

Uma vez criado as tasks e handlers da role, basta executar o playbook.

/etc/ansible/playbooks$ ansible-playbook database.yml 

PLAY [database] ***************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [db-01.devopslab.com.br]

TASK [mysql : Instalacao do modulo - module utilizado para criacao de DBs e usuarios no Mysql] ********************************************************************************************************************
ok: [db-01.devopslab.com.br]

TASK [mysql : Instalacao do MYSQL SERVER via APT-GET] *************************************************************************************************************************************************************
ok: [db-01.devopslab.com.br]

TASK [mysql : Utilizando uma Regexp para alterar o my.cnf e configurar o bind do Mysql] ***************************************************************************************************************************
changed: [db-01.devopslab.com.br]

TASK [mysql : MYSQL com o status started e ativo/enabled no boot] *************************************************************************************************************************************************
ok: [db-01.devopslab.com.br]

TASK [mysql : Criacao de um banco de dados - banco criado demo] ***************************************************************************************************************************************************
ok: [db-01.devopslab.com.br]

TASK [mysql : Criacao de um usuario para o banco demo - usuario demo, password demo] ******************************************************************************************************************************
ok: [db-01.devopslab.com.br]

RUNNING HANDLER [mysql : restart mysql] ***************************************************************************************************************************************************************************
changed: [db-01.devopslab.com.br]

PLAY RECAP ********************************************************************************************************************************************************************************************************
db-01.devopslab.com.br     : ok=8    changed=2    unreachable=0    failed=0   

13. Includes

Você pode fazer a inclusão de Playbooks dentro de outros Playbooks.

Playbook exemplo lb-webserver-db.yml
---
- name: "Importacao do Playbook database.yml"
  import_playbook: database.yml

- name: "Importacao do Playbook webserver.yml"
  import_playbook: webserver.yml

- name: "Importacao do Playbook loadbalancer.yml"
  import_playbook: loadbalancer.yml

#Restante do Playbook.
#
#

14. Variáveis – Facts

Consulte todas as informações dos hosts, como CPU, memória, interfaces de rede, detalhes do kernel, OS family, e muito mais.
ansible -m setup db-01.devopslab.com.br

Como utilizar uma informação “fact” como variável de um playbook.

Verifique as informações relativas a interface eth0

ansible -m setup db-01.devopslab.com.br

...
 "<strong>ansible_eth0</strong>": {
"active": true,
"device": "eth0",
...
...
...
"<strong>ipv4</strong>": {
"<strong>address</strong>": "10.0.2.26",
"broadcast": "10.0.2.255",
"netmask": "255.255.255.0",
"network": "10.0.2.0"
},


Defina a utilização do fact entre<strong> {{ }}</strong>.
- name: "Utilizando uma Regexp para alterar o my.cnf e configurar o bind do Mysql"
lineinfile: dest=/etc/mysql/my.cnf regexp=^bind-address line="bind-address = <strong>{{ ansible_eth0.ipv4.address }}</strong>"
notify: restart mysql

Último update: 23/07/2018

Continua.
Anotações em andamento.
; )
Leonardo