Como criar peças e playbooks Ansible - Parte 5
Nesta Parte 5 da série Ansible, explicaremos como criar Ansible Plays e Playbooks usando módulos Ansible.
O Ansible vem com scripts independentes chamados módulos que são usados em manuais para a execução de tarefas especializadas em nós remotos.
Módulos são úteis para automatizar tarefas como gerenciamento de pacotes, arquivamento e cópia de arquivos, para mencionar apenas alguns. Eles permitem que você faça ajustes nos arquivos de configuração e gerencie dispositivos como roteadores, switches, balanceadores de carga, firewalls e uma série de outros dispositivos.
O objetivo deste subtópico é fornecer uma visão geral das diversas tarefas que podem ser realizadas pelos módulos Ansible:
Gerenciamento de pacotes no Linux
O gerenciamento de pacotes é uma das tarefas mais essenciais e frequentes realizadas pelos administradores de sistemas. O Ansible vem com módulos que ajudam você a executar tarefas de gerenciamento de pacotes em sistemas baseados em RedHat e Debian.
Eles são relativamente fáceis de adivinhar. Existe o módulo apt para gerenciamento de pacotes APT para base Debian, o antigo módulo yum para gerenciamento de pacotes YUM e o módulo dnf associado às distribuições RHEL mais recentes .
Abaixo estão alguns exemplos de como os módulos podem ser usados em um manual:
Exemplo 1: Instalando o servidor Web Apache no RHEL 8
---
- name: install Apache webserver
hosts: webservers
tasks:
- name: install httpd
dnf:
name: httpd
State: latest
Exemplo 2: Instalando o servidor Web Apache no Debian 10
---
- name: install Apache webserver
hosts: databases
tasks:
- name: install Apache webserver
apt:
name: apache2
State: latest
Módulo de serviço
O módulo de serviço permite que os administradores do sistema iniciem, parem, atualizem, atualizem e recarreguem serviços no sistema.
Exemplo 1: Iniciando o servidor Web Apache
---
- name: Start service httpd, if not started
service:
name: httpd
state: started
Exemplo 2: Parando o servidor Web Apache
---
- name: Stop service httpd
service:
name: httpd
state: stopped
Exemplo 3: Reiniciando uma interface de rede enp2s0
---
- name: Restart network service for interface eth0
service:
name: network
state: restarted
args: enp2s0
Módulo de cópia
Como o nome sugere, o módulo copy copia arquivos de um local na máquina remota para um local diferente na mesma máquina.
Exemplo 1: Copiando arquivos do Linux local para remoto
---
- name: Copy file with owner and permissions
copy:
src: /etc/files/tecmint.conf
dest: /srv/tecmint.conf
owner: tecmint
group: tecmint
mode: '0644'
O manual copia o arquivo de configuração tecmint.conf do diretório /etc/files/ para o diretório /srv/ como tecmint usuário com permissões 0644.
As permissões também podem ser representadas usando representação simbólica conforme mostrado na última linha.
Exemplo 2: Copiando arquivos do Linux local para remoto
---
- name: Copy file with owner and permissions
copy:
src: /etc/files/tecmint.conf
dest: /srv/tecmint.conf
owner: tecmint
group: tecmint
mode: u=rw, g=r, o=r
As permissões no exemplo anterior podem ser representadas conforme mostrado na última linha. O usuário recebe permissões de leitura e gravação, o grupo recebe permissões de gravação e o restante o mundo recebe permissões de leitura.
Módulo de arquivo
O módulo de arquivo é usado para realizar muitas operações de arquivo, incluindo criação de arquivos e diretórios, atribuição de permissões de arquivo e configuração de links simbólicos.
Exemplo 1: Execute permissões de arquivo Linux
---
- name: Change file ownership, group, and permissions
file:
path: /etc/tecmint.conf
owner: tecmint
group: tecmint
mode: '0644'
A peça acima cria um arquivo chamado tecmint.conf no diretório /etc definindo as permissões para 0644.
Exemplo 2: Excluir arquivo Linux
---
- name: Remove file (delete file)
file:
path: /etc/tecmint.conf
state: absent
Isso remove ou exclui o arquivo tecmint.conf.
Exemplo 3: Crie um diretório
---
- name: create a directory if it doesn’t exist
file:
path: /etc/mydirectory
State: directory
mode: '0777'
Isto criará um diretório no diretório /etc definindo as permissões para 0777.
Exemplo 4: excluir recursivamente um diretório
---
- name: Recursively deleting a directory
file:
path: /etc/tecmint.conf
state: absent
A reprodução acima exclui recursivamente um diretório.
Módulo de arquivo de linha
O módulo lineinfile é útil quando você deseja alterar uma única linha em um arquivo. Ele pode substituir uma linha existente.
Exemplo 1: Manipular arquivos no Linux
---
- name: Ensure SELinux is set to enforcing mode
lineinfile:
path: /etc/selinux/config
regexp: '^SELINUX='
line: SELINUX=disabled
A peça acima define o valor SELINUX como desativado.
SELINUX=disabled
Exemplo 2: Alterar arquivos no Linux
---
- name: Add a line to a file if the file does not exist, without passing regexp
lineinfile:
path: /etc/hosts
line: 10.200.50.51 linux-console.net
create: yes
Isso adiciona a entrada 10.200.50.51 linux-console.net ao arquivo /etc/hosts.
Módulo de arquivo
Um módulo Archive é usado para a criação de um arquivo compactado de um único ou vários arquivos. Ele assume que a fonte de compactação existe e está presente no destino alvo. Após o arquivamento, o arquivo de origem pode ser excluído ou removido posteriormente usando a instrução remove=True
.
Exemplo 1: Crie um arquivo compactado
- name: Compress directory /path/to/tecmint_dir/ into /path/to/tecmint.tgz
archive:
path: /path/to/tecmint_dir
dest: /path/to/tecmint.tgz
This compresses the /path/to/tecmint_dir directory to /path/to/tecmint.tgz
Exemplo 2: Crie um arquivo compactado e remova
- name: Compress regular file /path/to/tecmint into /path/to/foo.gz and remove it
archive:
path: /path/to/tecmint
dest: /path/to/tecmint.tgz
remove: yes
Na reprodução acima, o arquivo fonte /path/to/tecmint é excluído após a conclusão do arquivamento.
Exemplo 3: Crie um arquivo compactado
- name: Create a bz2 archive of /path/to/tecmint
archive:
path: /path/to/tecmint
format: bz2
Isso cria um arquivo compactado no formato bz2 a partir do arquivo /path/to/tecmint.
Módulo Git
O módulo gerencia checkouts git de repositórios de software.
Exemplo 1: verifique os repositórios Git
- git:
repo: 'https://foosball.example.org/path/to/repo.git'
dest: /srv/checkout
version: release-0.22
Módulo de comando
Um dos módulos mais comumente usados, o módulo comando leva o nome do comando e depois é seguido por uma lista de argumentos. O comando é passado da mesma forma que você digitaria em um shell do Linux.
Exemplo 1: execute um comando
- name: Executing a command using the command module
command: cat helloworld.txt
Exemplo 2: Verifique o tempo de atividade do Linux remoto
---
- name: Check the remote host uptime
hosts: servers
tasks:
- name: Execute the Uptime command over Command module
register: uptimeoutput
command: "uptime"
- debug:
var: uptimeoutput.stdout_lines
O módulo de comando recupera o tempo de atividade de servidores remotos.
Variáveis para recuperar os resultados da execução de comandos
Normalmente, os playbooks do Ansible são usados para executar tarefas em hosts gerenciados sem exibir a saída na linha de comando. Há casos, no entanto, em que pode ser necessário capturar a saída ou os resultados. Nesta seção, mostramos como capturar a saída de um playbook em uma variável e exibi-la posteriormente.
Um registro ansible é usado para capturar a saída de uma tarefa e salvá-la como uma variável. A partir de então, a variável conterá o stdout da tarefa.
Por exemplo, vamos supor que você deseja verificar o uso do disco de nós gerenciados nos respectivos diretórios raiz usando o comando df -Th /
. Você usará o módulo ‘command’
para definir o comando e ‘register’
para salvar a saída padrão em uma variável.
Para exibir o comando, você usará o módulo ‘debug’
junto com o valor de retorno stdout.
---
- hosts: all
become: yes
tasks:
- name: Execute /boot usage on Hosts
command: 'df -Th /'
register: df
- debug: var=df.stdout
Agora, vamos executar o manual. Nesse caso, nomeamos nosso manual de check_disk_space.yml.
ansible-playbook check_disk_space.yml
Como você viu, o resultado está todo confuso e dificulta o acompanhamento.
Para alinhar a saída e facilitar a leitura, substitua o valor de retorno stdout por stdout_lines.
---
- hosts: all
become: yes
tasks:
- name: Execute /boot usage on Hosts
command: 'df -Th /'
register: df
- debug: var=df.stdout_lines
Use condicionais para controlar a execução do jogo
Assim como nas linguagens de programação, declarações condicionais são usadas quando mais de um resultado é possível. Vamos dar uma olhada em algumas das instruções condicionais comumente usadas nos manuais do Ansible.
Quando declaração
Às vezes, você pode querer executar tarefas em nós específicos e não em outros. A instrução condicional 'when'
é bastante fácil de usar e implementar em um manual. Ao usar a cláusula 'when'
simplesmente declare a condição adjacente à cláusula conforme mostrado:
when: condition
Quando a condição for satisfeita, a tarefa será executada no sistema remoto.
Vejamos alguns exemplos:
Exemplo 1: Usando o Operador When
---
- hosts: all
tasks:
- name: Install Nginx on Debian
apt: name=nginx state=present
when: ansible_os_family == “Debian”
A peça acima instala o servidor web Nginx em hosts que executam a família de distros Debian.
Você também pode usar os operadores OR
e AND
junto com a instrução condicional.
Exemplo 2: Usando o operador AND com When
---
- hosts: all
tasks:
- name: Install Nginx on Debian
apt: name=nginx state=present
when: ansible_os_family == “Debian” and
ansible_distribution_version == “18.04”
Ao usar o operador AND
, ambas as instruções devem ser satisfeitas para que a tarefa seja executada.
A peça acima instala o Nginx em nós que executam uma família de sistemas operacionais Debian, versão 18.04. Obviamente, este será o Ubuntu 18.04.
Exemplo 3: Usando o operador OR com When
Com o operador OR
, a tarefa é executada se alguma das condições for atendida.
---
- hosts: all
tasks:
- name: Install Nginx on Debian
apt: name=nginx state=present
when: ansible_os_family == “Debian” or
Ansible_os_family == “SUSE”
A peça acima instala servidores web Nginx na família de sistemas operacionais Debian ou SUSE ou em ambos.
NOTA: Sempre certifique-se de usar o sinal de igualdade duplo ==
ao testar uma condição.
Condicionais em loops
Condicionais também podem ser usados em um loop. Digamos, por exemplo, que você tenha uma lista de vários pacotes que precisam ser instalados em nós remotos.
No manual abaixo, temos um array chamado pacotes contendo uma lista de pacotes que precisam ser instalados. Estas tarefas serão realizadas uma após a outra se a cláusula required estiver definida como True.
---
- name: Install Software packages
hosts: all
vars:
packages:
• name: nginx
required: True
• name: mysql
required: True
• name: apache
required: False
tasks:
• name: Install “{{ item.name }}”on Debian
apt:
name: “{{ item.name }}”
state: present
When: item.required == True
loop: “{{ packages }}”
Configurar tratamento de erros
Às vezes, as tarefas falham ao executar manuais. Vamos supor que você esteja executando 5 tarefas em 3 servidores, conforme mostrado no manual abaixo. Se ocorrer um erro na tarefa 3 (Iniciando o MySQL) no servidor 2, o Ansible interromperá a execução das tarefas restantes no servidor 2 e tentará concluir as tarefas restantes nos demais servidores.
---
- name: Install Software packages
hosts: server1, server2, server3
tasks:
- name: Install dependencies
<< some code >>
- name: Install MySQL database
<< some code >>
- name: Start MySQL
<< some code >>
- name: Install Nginx
<< some code >>
- name: Start Nginx
<< some code >>
Se você deseja consistência na execução do playbook, por exemplo, interromper a execução de um playbook, caso um dos servidores falhe, adicione a opção.
---
- name: Install Software packages
hosts: server1, server2, server3
any_errors_fatal: true
tasks:
Dessa forma, se uma tarefa falhar em um servidor, o Ansible interromperá a execução de todo o playbook em todos os servidores e sairá.
Se desejar que o manual ignore os erros e prossiga com a execução do conjunto restante de tarefas, use a opção ignore_errors: True.
---
- name: Install Software packages
hosts: server1, server2, server3
tasks:
- name: Install dependencies
<< some code >>
ignore_errors: True
Crie manuais para configurar sistemas para um estado específico
Nesta seção, veremos algumas opções adicionais disponíveis ao executar um playbook.
Vamos começar com o modo Verificar ou a opção Teste. A opção de simulação ou modo de verificação é usada ao executar um playbook para verificar se algum erro será encontrado e se há alguma alteração que será feita nos hosts gerenciados. No entanto, não faz nenhuma alteração nos nós remotos.
Por exemplo, para executar um playbook chamado httpd.yml
que instala e inicia a execução do servidor web Apache:
ansible-playbook httpd.yml --check
A outra opção que precisamos observar é a opção --start-at-task
. Isso é usado ao especificar o nome da tarefa na qual o playbook deve começar ou começar.
Vejamos um exemplo: O manual abaixo descreve 2 tarefas: a primeira instala o servidor web Apache e a segunda instala o utilitário htop.
---
- name: Install httpd
hosts: all
tasks:
yum:
name: httpd
state: Installed
- name: Install htop
yum:
name: htop
state: started
Se você quiser pular a instalação do servidor web Apache e, em vez disso, instalar o utilitário htop, execute:
ansible-playbook playbook.yml --start-at-task “Install htop”
Por último, você pode marcar suas tarefas ou jogadas adicionando a opção tags ao seu manual, conforme mostrado. Isso é útil quando você tem um manual bastante grande e deseja executar tarefas específicas de todo o manual.
---
- name: Install httpd
tags: Install and start
hosts: all
tasks:
yum:
name: httpd
state: Installed
tags: Install
• service:
name: httpd
state: started
ansible-playbook playbook.yml -tags "Install"
Para omitir as tags use as opções --skip-tags
conforme mostrado.
ansible-playbook playbook.yml --skip-tags "Install"
Conclusão
Neste tópico, mostramos os módulos comumente usados no Ansible, como recuperar stdout da execução de um playbook para análise, usando condicionais no playbook e como gerenciar erros que podem ocorrer durante a execução tarefas. Por fim, recapitulamos a configuração dos playbooks e como você pode usar opções adicionais para decidir quais tarefas executar caso não pretenda executar o playbook inteiro.