Open britho opened 3 years ago
Neste exercício, você explorará como usar padrões de host para especificar hosts do inventário para ações ou comandos ad hoc. Você receberá diversos inventários de exemplo para explorar os padrões de host.
Resultados
Você deverá ser capaz de usar diferentes padrões de host para acessar vários hosts em um inventário.
Faça login na workstation como student usando a senha student.
Na workstation, execute o comando lab projects-host start. O script cria o diretório do projeto projects-host e, em seguida, faz o download dos arquivos de configuração e inventário de host do Ansible necessários para este exercício.
[student@workstation ~]$ lab projects-host start
Na workstation, mude para o diretório de trabalho deste exercício, /home/student/projects-host, e revise o conteúdo do diretório.
[student@workstation ~]$ cd ~/projects-host
[student@workstation projects-host]$
Liste os conteúdos do diretório.
[student@workstation projects-host]$ ls
ansible.cfg inventory1 inventory2 playbook.yml
Inspecione o arquivo de inventário de exemplo, inventory1. Veja como o inventário é organizado. Explore quais hosts e grupos estão no inventário, além de quais domínios são usados.
srv1.example.com
srv2.example.com
s1.lab.example.com
s2.lab.example.com
[web]
jupiter.lab.example.com
saturn.example.com
[db]
db1.example.com
db2.example.com
db3.example.com
[lb]
lb1.lab.example.com
lb2.lab.example.com
[boston]
db1.example.com
jupiter.lab.example.com
lb2.lab.example.com
[london]
db2.example.com
db3.example.com
file1.lab.example.com
lb1.lab.example.com
[dev]
web1.lab.example.com
db3.example.com
[stage]
file2.example.com
db2.example.com
[prod]
lb2.lab.example.com
db1.example.com
jupiter.lab.example.com
[function:children]
web
db
lb
city
[city:children]
boston
london
environments
[environments:children]
dev
stage
prod
new
[new]
172.25.252.23
172.25.252.44
172.25.252.32
Inspecione o arquivo de inventário de exemplo, inventory2. Veja como o inventário é organizado. Explore quais hosts e grupos estão no inventário, além de quais domínios são usados.
workstation.lab.example.com
[london]
servera.lab.example.com
[berlin]
serverb.lab.example.com
[tokyo]
serverc.lab.example.com
[atlanta]
serverd.lab.example.com
[europe:children]
london
berlin
Por fim, inspecione o conteúdo do playbook, playbook.yml. Observe como o manual usa o módulo debug para exibir o nome de cada host gerenciado.
---
- name: Resolve host patterns
hosts:
tasks:
- name: Display managed host name
debug:
msg: "{{ inventory_hostname }}"
Usando um comando ad hoc, determine se o servidor db1.example.com está presente no arquivo de inventário inventory1.
[student@workstation projects-host]$ ansible db1.example.com -i inventory1 \
> --list-hosts
hosts (1):
db1.example.com
Usando um comando ad hoc, faça referencia a um endereço IP contido no inventário inventory1 com um padrão de host.
[student@workstation projects-host]$ ansible 172.25.252.44 -i inventory1 \
> --list-hosts
hosts (1):
172.25.252.44
Com um comando ad hoc, use o grupo all para listar todos os hosts gerenciados no arquivo de inventário inventory1.
[student@workstation projects-host]$ ansible all -i inventory1 --list-hosts
hosts (17):
srv1.example.com
srv2.example.com
s1.lab.example.com
s2.lab.example.com
jupiter.lab.example.com
saturn.example.com
db1.example.com
db2.example.com
db3.example.com
lb1.lab.example.com
lb2.lab.example.com
file1.lab.example.com
web1.lab.example.com
file2.example.com
172.25.252.23
172.25.252.44
172.25.252.32
Com um comando ad hoc, use o caractere de asterisco (*) para listar todos os hosts que terminam em .example.com no arquivo de inventário inventory1.
[student@workstation projects-host]$ ansible '*.example.com' -i inventory1 \
> --list-hosts
hosts (14):
jupiter.lab.example.com
saturn.example.com
db1.example.com
db2.example.com
db3.example.com
lb1.lab.example.com
lb2.lab.example.com
file1.lab.example.com
web1.lab.example.com
file2.example.com
srv1.example.com
srv2.example.com
s1.lab.example.com
s2.lab.example.com
Como você pode ver na saída do comando anterior, há 14 hosts no domínio *.example.com. Modifique o padrão de host no comando ad hoc anterior para que os hosts no domínio *.lab.example.com sejam ignorados.
[student@workstation projects-host]$ ansible '*.example.com, !*.lab.example.com' \
> -i inventory1 --list-hosts
hosts (7):
saturn.example.com
db1.example.com
db2.example.com
db3.example.com
file2.example.com
srv1.example.com
srv2.example.com
Sem acessar os grupos no arquivo de inventário inventory1, use um comando ad hoc para listar estes três hosts: lb1.lab.example.com, s1.lab.example.com e db1.example.com.
[student@workstation projects-host]$ ansible \
> lb1.lab.example.com,s1.lab.example.com,db1.example.com -i inventory1 \
> --list-hosts
hosts (3):
lb1.lab.example.com
s1.lab.example.com
db1.example.com
Use um padrão de host de curinga em um comando ad hoc para listar os hosts que começam com 172.25. Endereço IP no arquivo de inventário inventory1.
[student@workstation projects-host]$ ansible '172.25.*' -i inventory1 --list-hosts
hosts (3):
172.25.252.23
172.25.252.44
172.25.252.32
Use um padrão de host em um comando ad hoc para listar todos os hosts no arquivo de inventário inventory1 que começam com a letra "s".
[student@workstation projects-host]$ ansible 's*' -i inventory1 --list-hosts
hosts (7):
saturn.example.com
srv1.example.com
srv2.example.com
s1.lab.example.com
s2.lab.example.com
file2.example.com
db2.example.com
Observe os hosts file2.example.com e db2.example.com na saída no comando anterior. Eles aparecem na lista porque são membros de um grupo chamado stage, que também começa com a letra "s".
Usando uma lista e padrões de host de curinga em um comando ad hoc, liste todos os hosts no inventário inventory1 no grupo prod, os hosts com um endereço IP que comece com 172 e os hosts que contenham lab no nome.
[student@workstation projects-host]$ ansible 'prod,172*,*lab*' -i inventory1 \
> --list-hosts
hosts (11):
lb2.lab.example.com
db1.example.com
jupiter.lab.example.com
172.25.252.23
172.25.252.44
172.25.252.32
lb1.lab.example.com
file1.lab.example.com
web1.lab.example.com
s1.lab.example.com
s2.lab.example.com
Use um comando ad hoc para listar todos os hosts que pertencem aos grupos db e london.
[student@workstation projects-host]$ ansible 'db,&london' -i inventory1 \
> --list-hosts
hosts (2):
db2.example.com
db3.example.com
Modifique o valor de hosts no arquivo playbook.yml para que todos os servidores no grupo London sejam usados como destino. Execute o playbook usando o arquivo de inventário inventory2.
...output omitted...
hosts: london
...output omitted...
[student@workstation projects-host]$ ansible-playbook -i inventory2 playbook.yml
...output omitted...
TASK [Gathering Facts] ************************************************
ok: [servera.lab.example.com]
...output omitted...
Modifique o valor de hosts no arquivo playbook.yml para que todos os servidores no grupo aninhado europe sejam definidos como destino. Execute o playbook usando o arquivo de inventário inventory2.
...output omitted...
hosts: europe
...output omitted...
[student@workstation projects-host]$ ansible-playbook -i inventory2 playbook.yml
...output omitted...
TASK [Gathering Facts] ************************************************
ok: [servera.lab.example.com]
ok: [serverb.lab.example.com]
...output omitted...
Modifique o valor de hosts no arquivo playbook.yml para que todos os servidores que não pertençam a algum grupo sejam definidos como destino. Execute o playbook usando o arquivo de inventário inventory2.
...output omitted...
hosts: ungrouped
...output omitted...
[student@workstation projects-hosts]$ ansible-playbook -i inventory2 playbook.yml
...output omitted...
TASK [Gathering Facts] ************************************************
ok: [workstation.lab.example.com]
...output omitted...
Encerramento
Na workstation, execute o script lab projects-host finish para limpar este exercício.
[student@workstation ~]$ lab projects-host finish
Isso conclui o exercício orientado.
Objetivos
Depois de concluir esta seção, você deverá ser capaz de descrever o que são inventários dinâmicos, bem como instalar e usar um script existente como uma fonte de inventário dinâmico do Ansible. Geração de inventários de modo dinâmico
Os arquivos de inventário estático com os quais você trabalhou até agora são fáceis de escrever e são convenientes para gerenciar infraestruturas pequenas. Contudo, ao trabalhar com várias máquinas ou em um ambiente em que haja alta rotatividade de máquinas, pode ser difícil manter os arquivos de inventário estático atualizados.
A maioria dos grandes ambientes de TI tem sistemas que controlam quais hosts estão disponíveis e como eles são organizados. Por exemplo, pode haver um serviço de diretório externo mantido por um sistema de monitoramento, como o Zabbix ou em servidores FreeIPA ou Active Directory. Servidores de instalação como o Cobbler ou serviços de gerenciamento como o RedHat Satellite podem monitorar sistemas bare-metal implantados. Do modo semelhante, serviços em nuvem como o Amazon Web Services EC2 ou uma implantação do OpenStack ou infraestruturas de máquina virtual baseada em VMware ou RedHat Virtualization podem ser fontes de informação sobre as instâncias e máquinas virtuais temporárias.
O Ansible é compatível com scripts dynamic inventory que recuperam as informações atuais desses tipos de fontes sempre que o Ansible for executado, permitindo que o inventário seja atualizado em tempo real. Esses scripts são programas executáveis que coletam informações de algumas fontes externas e geram o inventário em formato JSON.
Os scripts de inventário dinâmico são usados exatamente como arquivos de texto de inventário estático. A localização do inventário é especificada diretamente no arquivo ansible.cfg atual ou por meio da opção -i. Se o arquivo do inventário for executável, ele será tratado como um programa de inventário dinâmico e o Ansible tentará executá-lo para gerar o inventário. Se o arquivo não for executável, ele será tratado como um inventário estático.
A localização do inventário pode ser configurada no arquivo de configuração ansible.cfg com o parâmetro inventory. Por padrão, ela está configurada como /etc/ansible/hosts. Disponibilização de scripts
A comunidade de open source contribuiu com vários scripts de inventário dinâmico existentes para o projeto do Ansible. Eles não estão incluídos no pacote ansible nem têm suporte oficial da RedHat. Esses scripts estão disponíveis na página do GitHub do Ansible em https://github.com/ansible/ansible/tree/devel/contrib/inventory.
Algumas fontes de dados ou plataformas que são destino de scripts de inventário dinâmico disponibilizados incluem:
Plataformas de nuvem privada, como RedHat OpenStack Platform.
Plataformas de nuvem pública, como Rackspace Cloud, Amazon Web Services EC2 e Google Compute Engine.
Plataformas de virtualização, como RedHat Virtualization (oVirt) e VMware vSphere.
Soluções de plataforma como serviço, como a OpenShift Container Platform.
Ferramentas de gerenciamento de ciclo de vida, como a Foreman (com RedHat Satellite6 ou independente) e a Spacewalk (upstream do RedHat Satellite5).
Provedores de hospedagem, como Digital Ocean e Linode.
Cada script pode ter suas próprias dependências e requisitos de funcionamento. Os scripts disponibilizados são, em sua maioria, escritos em Python, mas isso não é um requisito de scripts de inventário dinâmico. Escrever programas de inventário dinâmico
Se não existir um script de inventário dinâmico no sistema de diretórios ou na infraestrutura em uso, você poderá escrever um programa de inventário dinâmico personalizado. O programa personalizado pode ser escrito em qualquer linguagem de programação, mas deve retornar informações de inventário no formato JSON ao receber as opções apropriadas.
O comando ansible-inventory pode ser uma ferramenta útil para aprender como criar inventários do Ansible no formato JSON. Você pode usar o comando ansible-inventory, disponível desde o Ansible2.4, para visualizar um arquivo de inventário no formato JSON.
Para exibir o conteúdo do arquivo de inventário no formato JSON, execute o comando ansible-inventory --list. Você pode usar a opção -i para especificar o local do arquivo de inventário a ser processado ou usar o inventário padrão definido pela configuração atual do Ansible.
O exemplo a seguir demonstra o uso do comando ansible-inventory para processar um arquivo de inventário em estilo INI e gerá-lo no formato JSON.
[student@workstation projects-host]$ cat inventory workstation1.lab.example.com
[webservers] web1.lab.example.com web2.lab.example.com
[databases] db1.lab.example.com db2.lab.example.com
[student@workstation projects-host]$ ansible-inventory -i inventory --list { "_meta": { "hostvars": { "db1.lab.example.com": {}, "db2.lab.example.com": {}, "web1.lab.example.com": {}, "web2.lab.example.com": {}, "workstation1.lab.example.com": {} } }, "all": { "children": [ "databases", "ungrouped", "webservers" ] }, "databases": { "hosts": [ "db1.lab.example.com", "db2.lab.example.com" ] }, "ungrouped": { "hosts": [ "workstation1.lab.example.com" ] }, "webservers": { "hosts": [ "web1.lab.example.com", "web2.lab.example.com" ] } }
Se desejar escrever seu próprio script de inventário dinâmico, você encontrará informações mais detalhadas na seção Desenvolvimento de fontes de inventário dinâmico do Ansible Developer Guide. Veja a seguir uma breve visão geral.
Inicie o script com uma linha de interpretador adequada (por exemplo, #!/usr/bin/python). Além disso, ele deve ser executável para funcionar com o Ansible.
Quando a opção --list for passada, o script deve imprimir um hash/dicionário em código JSON de todos os hosts e grupos no inventário.
Em sua forma mais simples, um grupo pode ser uma lista de hosts gerenciados. Neste exemplo de saída em código JSON de um script de inventário, webservers é um grupo de hosts que tem web1.lab.example.com e web2.lab.example.com como hosts gerenciados no grupo. O grupo de hosts databases inclui os hosts db1.lab.example.com e db2.lab.example.com como membros.
[student@workstation ~]$ ./inventoryscript --list { "webservers" : [ "web1.lab.example.com", "web2.lab.example.com" ], "databases" : [ "db1.lab.example.com", "db2.lab.example.com" ] }
Como alternativa, o valor de cada grupo pode ser um hash/dicionário JSON contendo uma lista de cada host gerenciado, grupos filho e qualquer variável de grupo que possa estar definida. O próximo exemplo mostra a saída em código JSON de um inventário dinâmico mais complexo. O grupo boston tem dois grupos filho (backup e ipa), três hosts gerenciados próprios e uma variável de grupo definida (example_host: false).
{ "webservers" : [ "web1.demo.example.com", "web2.demo.example.com" ], "boston" : { "children" : [ "backup", "ipa" ], "vars" : { "example_host" : false }, "hosts" : [ "server1.demo.example.com", "server2.demo.example.com", "server3.demo.example.com" ] }, "backup" : [ "server4.demo.example.com" ], "ipa" : [ "server5.demo.example.com" ], "_meta" : { "hostvars" : { "server5.demo.example.com": { "ntpserver": "ntp.demo.example.com", "dnsserver": "dns.demo.example.com" } } } }
O script também deverá ser compatível com a opção --host managed-host. Essa opção deve imprimir um hash/dicionário JSON que consista em variáveis associadas a esse host, ou um hash/dicionário JSON vazio.
[student@workstation ~]$ ./inventoryscript --host server5.demo.example.com { "ntpserver" : "ntp.demo.example.com", "dnsserver" : "dns.demo.example.com" }
Quando chamado com a opção --host hostname, o script deve imprimir um hash/dicionário JSON das variáveis do host especificado. Um hash ou dicionário JSON vazio pode ser impresso se nenhuma variável for fornecida.
Opcionalmente, se a primeira opção --list retornar um elemento de nível superior denominado _meta, será possível retornar todas as variáveis de host em uma chamada de script, o que melhora o desempenho do script. Nesse caso, chamadas --host não são feitas.
Consulte Desenvolvimento de fontes de inventário dinâmico para obter mais informações. Gerenciamento de múltiplos inventários
O Ansible aceita o uso de vários inventários na mesma execução. Se o local do inventário for um diretório (seja ele definido pela opção -i, pelo valor do parâmetro inventory ou de alguma outra maneira), todos os arquivos de inventário incluídos no diretório, estáticos ou dinâmicos, serão combinados para determinar o inventário. Os arquivos executáveis dentro de cada diretório são usados para recuperar inventários dinâmicos, e os outros arquivos são usados como inventários estáticos.
Os arquivos de inventário não devem depender de outros arquivos ou scripts de inventário para serem resolvidos. Por exemplo, se um arquivo de inventário estático especificar que um grupo específico deve ser secundário de outro grupo, ele também precisará ter uma entrada de espaço reservado para esse grupo, mesmo se todos os membros desse grupo venham do inventário dinâmico. Considere o grupo cloud-east no seguinte exemplo:
[cloud-east]
[servers] test.demo.example.com
[servers:children] cloud-east
Isso garante que todos os arquivos de inventário sejam internamente consistentes, independentemente da ordem na qual forem analisados.
A ordem na qual os arquivos de inventário são analisados não é especificada pela documentação. Atualmente, quando existem vários arquivos de inventário, eles são analisados em ordem alfabética. Se uma fonte de inventário depender de informações de outra fonte de inventário, a ordem na qual elas são carregadas poderá determinar se o arquivo de inventário funciona como esperado ou se gera um erro. Portanto, é importante garantir que todos os arquivos sejam consistentes para evitar erros inesperados.
O Ansible ignora arquivos em um diretório de inventários se eles terminarem com determinados sufixos. Isso pode ser controlado com a diretiva inventory_ignore_extensions no arquivo de configuração do Ansible. Mais informações estão disponíveis na documentação do Ansible.
Working With Dynamic Inventory: Ansible Documentation
Developing Dynamic Inventory: Ansible Documentation
Neste exercício, você instalará scripts personalizados que geram de modo dinâmico uma lista de hosts de inventário.
Resultados
Você será capaz de instalar e usar scripts de inventário dinâmico existentes.
Faça login na workstation como student usando a senha student.
Na workstation, execute o comando lab projects-inventory start. Ele garante que o Ansible esteja instalado na workstation e também cria o diretório de trabalho /home/student/projects-inventory para este exercício.
[student@workstation ~]$ lab projects-inventory start
Na workstation, mude para o diretório de trabalho do exercício, /home/student/projects-inventory. Veja o conteúdo do arquivo de configuração do Ansible ansible.cfg. O arquivo de configuração define o local do inventário como inventory.
[defaults]
inventory = inventory
Crie o diretório /home/student/projects-inventory/inventory.
[student@workstation projects-inventory]$ mkdir inventory
Em http://materials.example.com/labs/projects-inventory/, faça download dos arquivos inventorya.py, inventoryw.py e hosts para o diretório /home/student/projects-inventory/inventory. Ambos os arquivos que terminam com .py são scripts que geram inventários dinâmicos, e o terceiro arquivo é um inventário estático.
O script inventorya.py fornece o grupo webservers, que inclui o host servera.lab.example.com.
O script inventoryw.py fornece o host workstation.lab.example.com.
O arquivo de inventário estático hosts define o grupo servers, que é um grupo pai do grupo webservers.
[student@workstation projects-inventory]$ wget \
> http://materials.example.com/labs/projects-inventory/inventorya.py \
> -O inventory/inventorya.py
[student@workstation projects-inventory]$ wget \
> http://materials.example.com/labs/projects-inventory/inventoryw.py \
> -O inventory/inventoryw.py
[student@workstation projects-inventory]$ wget \
> http://materials.example.com/labs/projects-inventory/hosts \
> -O inventory/hosts
Usando o comando ansible com o script inventorya.py como inventário, liste os hosts gerenciados associados ao grupo webservers. Um erro relacionado às permissões de inventorya.py é gerado.
[student@workstation projects-inventory]$ ansible -i inventory/inventorya.py \
> webservers --list-hosts
[WARNING]: * Failed to parse /home/student/projects-inventory/inventory/inventorya.py with script plugin: problem running /home/student/projects-inventory/inventory/inventorya.py --list ([Errno 13] Permission denied)
[WARNING]: * Failed to parse /home/student/projects-inventory/inventory/inventorya.py with ini plugin: /home/student/projects-inventory/inventory/inventorya.py:3: Expected key=value host variable assignment, got: subprocess
[WARNING]: Unable to parse /home/student/projects-inventory/inventory/inventorya.py as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
[WARNING]: Could not match supplied host pattern, ignoring: webservers
hosts (0):
Verifique as permissões atuais do script inventorya.py e altere-as para 755.
[student@workstation projects-inventory]$ ls -la inventory/inventorya.py
-rw-rw-r--. 1 student student 639 Apr 29 14:20 inventory/inventorya.py
[student@workstation projects-inventory]$ chmod 755 inventory/inventorya.py
Altere as permissões do script inventoryw.py para 755.
[student@workstation projects-inventory]$ chmod 755 inventory/inventoryw.py
Verifique a saída atual do script inventorya.py usando o parâmetro --list. Os hosts associados ao grupo webservers serão exibidos.
[student@workstation projects-inventory]$ inventory/inventorya.py --list
{"webservers": {"hosts": ["servera.lab.example.com"], "vars": { }}}
Verifique a saída atual do script inventoryw.py usando o parâmetro --list. O host workstation.lab.example.com será exibido.
[student@workstation projects-inventory]$ inventory/inventoryw.py --list
{"all": {"hosts": ["workstation.lab.example.com"], "vars": { }}}
Verifique a definição do grupo servers no arquivo /home/student/projects-inventory/inventory/hosts. O grupo webservers definido no inventário dinâmico é configurado como secundário do grupo servers.
[student@workstation projects-inventory]$ cat inventory/hosts
[servers:children]
webservers
Execute o comando a seguir para verificar a lista de hosts do grupo webservers. É exibido um erro informando que o grupo webservers não está definido.
[student@workstation projects-inventory]$ ansible webservers --list-hosts
[WARNING]: * Failed to parse /home/student/projects-inventory/inventory/hosts with yaml plugin: Syntax Error while loading YAML. found unexpected ':' The error appears to have been in '/home/student/projects-inventory/inventory/hosts': line 1, column 9, but may be elsewhere in the file depending on the exact syntax problem. The offending line appears to be: [servers:children] ^ here
[WARNING]: * Failed to parse /home/student/projects-inventory/inventory/hosts with ini plugin: /home/student/projects-inventory/inventory/hosts:2: Section [servers:children] includes undefined group: webservers
[WARNING]: Unable to parse /home/student/projects-inventory/inventory/hosts as an inventory source
hosts (1):
servera.lab.example.com
Para evitar esse problema, o inventário estático deve ter uma entrada de espaço reservado definindo um grupo de hosts webservers vazio. É importante que o inventário estático defina todos os grupos de hosts referenciados por ele, já que ele pode desaparecer de modo dinâmico da fonte externa, provocando esse erro.
Edite o arquivo /home/student/projects-inventory/inventory/hosts para que contenha o seguinte conteúdo:
[webservers]
[servers:children]
webservers
Se o script de inventário dinâmico que fornece o grupo de hosts for nomeado de forma que seja classificado antes de o inventário estático referenciá-lo, você não verá esse erro. Entretanto, se o grupo de hosts desaparecer do inventário dinâmico e você não tiver um espaço reservado, o inventário estático fará referência a um grupo de hosts ausente e o erro interromperá a análise do inventário.
Execute novamente o comando a seguir para verificar a lista de hosts do grupo webservers. Deverá funcionar sem erros.
[student@workstation projects-inventory]$ ansible webservers --list-hosts
hosts (1):
servera.lab.example.com
Encerramento
Na workstation, execute o comando lab projects-inventory finish para limpar este exercício.
[student@workstation ~]$ lab projects-inventory finish
Isso conclui o exercício orientado.
Objetivos
Depois de concluir esta seção, você deverá ser capaz de ajustar o número de conexões simultâneas abertas pelo Ansible para hosts gerenciados e como o Ansible processa grupos de hosts gerenciados por meio das tarefas da ação. Configuração de paralelismo no Ansible usando forks
Quando o Ansible processa um playbook, ele executa cada ação em ordem. Depois de determinar a lista de hosts da ação, o Ansible executa cada tarefa em ordem. Normalmente, todos os hosts devem concluir com êxito uma tarefa antes que qualquer host inicie a próxima tarefa da ação.
Em teoria, o Ansible poderia se conectar simultaneamente a todos os hosts da ação para cada tarefa. Isso funciona bem para listas de hosts pequenas. Mas se a ação tiver como destino centenas de hosts, isso pode sobrecarregar o nó de controle.
O número máximo de conexões simultâneas que o Ansible faz é controlado pelo parâmetro forks no arquivo de configuração do Ansible. Por padrão, ele está definido como 5, o que pode ser verificado usando uma das opções a seguir.
[student@demo ~]$ grep forks ansible.cfg forks = 5
[student@demo ~]$ ansible-config dump |grep -i forks DEFAULT_FORKS(default) = 5
[student@demo ~]$ ansible-config list |grep -i forks DEFAULT_FORKS: description: Maximum number of forks Ansible will use to execute tasks on target
Por exemplo, suponha que um nó de controle do Ansible esteja configurado com o valor padrão de cinco forks e a ação tenha dez hosts gerenciados. O Ansible executará a primeira tarefa da ação nos primeiros cinco hosts gerenciados. Em seguida, realizará uma segunda rodada de execução da primeira tarefa nos outros cinco hosts gerenciados. Depois que a primeira tarefa tiver sido executada em todos os hosts gerenciados, o Ansible prosseguirá com a execução da próxima tarefa em todos os hosts gerenciados, em grupos de cinco hosts por vez. O Ansible fará isso com cada tarefa até que a ação termine.
O padrão para forks está definido de modo muito conservador. Se o nó de controle estiver gerenciando hosts Linux, a maioria das tarefas será executada nos hosts gerenciados e o nó de controle terá menos carga. Nesse caso, você geralmente pode definir forks com um valor muito mais alto, possivelmente mais próximo de 100, e observar melhorias no desempenho.
Se os playbooks executarem muitos códigos no nó de controle, você deve aumentar o limite de forks de maneira moderada. Se você usar o Ansible para gerenciar roteadores e switches de rede, a maioria desses módulos é executada no nó de controle e não no dispositivo de rede. Devido à carga mais alta que isso coloca no nó de controle, sua capacidade de suporte a aumentos no número de forks será significativamente menor do que em um nó de controle que gerencia somente hosts Linux.
Você pode substituir a configuração padrão de forks na linha de comando do arquivo de configuração do Ansible. Ambos os comandos ansible e ansible-playbook oferecem as opções -f ou --forks para especificar o número de forks a serem usados. Gerenciamento de atualizações em cascata
Normalmente, quando o Ansible executa uma ação, ele garante que todos os hosts gerenciados tenham concluído cada tarefa antes de iniciar a próxima tarefa. Depois que todos os hosts gerenciados tiverem concluído todas as tarefas, os manipuladores notificados são executados.
No entanto, executar todas as tarefas em todos os hosts pode levar a um comportamento indesejável. Por exemplo, se uma ação atualiza um cluster de servidores web com carga balanceada, talvez seja necessário desativar cada servidor web durante a atualização. Se todos os servidores forem atualizados na mesma ação, é possível que todos eles fiquem fora de serviço ao mesmo tempo.
Uma maneira de evitar esse problema é usar a palavra-chave serial para executar a ação nos hosts em lotes. A ação completa será executada em cada lote de hosts antes que o próximo lote seja iniciado.
No exemplo abaixo, o Ansible executa a ação em dois hosts gerenciados por vez, até que todos os hosts gerenciados tenham sido atualizados. O Ansible começa executando as tarefas da ação nos dois primeiros hosts gerenciados. Se um ou ambos os hosts notificarem o manipulador, o Ansible executará o manipulador conforme necessário para esses dois hosts. Quando a execução da ação é concluída nesses dois hosts gerenciados, o Ansible repete o processo nos próximos dois hosts gerenciados. O Ansible continua executando a ação dessa maneira até que todos os hosts gerenciados tenham sido atualizados.
name: Rolling update hosts: webservers serial: 2 tasks:
handlers:
Suponha que o grupo webservers no exemplo anterior contenha cinco servidores web que residem atrás de um balanceador de carga. Com o parâmetro serial definido como 2, a ação executará até dois servidores web por vez. Assim, a maioria dos cinco servidores web estará sempre disponível.
Em contrapartida, na ausência da palavra-chave serial, a execução da ação e a execução resultante do manipulador ocorreriam em todos os cinco servidores web ao mesmo tempo. Isso provavelmente levaria a uma interrupção do serviço, pois os serviços web em todos os servidores web seriam reiniciados ao mesmo tempo.
Para determinadas finalidades, cada lote de hosts conta como se fosse uma ação completa em execução em um subconjunto de hosts. Isso significa que, se um lote inteiro falhar, a ação falha, o que faz com que todo o playbook falhe.
No cenário anterior com a definição serial: 2, se algo estiver errado e a ação falhar para os dois primeiros hosts processados, o playbook será anulado e a ação não será executada nos três hosts restantes. Esse é um recurso útil porque apenas um subconjunto dos servidores estaria indisponível, deixando o serviço degradado em vez de inativo.
A palavra-chave serial também pode ser especificada como uma porcentagem. Essa porcentagem é aplicada ao número total de hosts na ação para determinar o tamanho do lote de atualização em cascata. Independentemente da porcentagem, o número de hosts por aprovação sempre será 1 ou mais.
Rolling Update Batch Size — Delegation, Rolling Updates, and Local Actions — Ansible Documentation
Ansible Performance Tuning (For Fun and Profit)
Neste exercício, você explorará os efeitos de diferentes diretivas de forks e em série na maneira com que uma ação é processada pelo Ansible.
Resultados
Você será capaz de ajustar execuções paralelas e seriais de um playbook em vários hosts gerenciados.
Faça login na workstation como student usando a senha student.
Na workstation, execute o comando lab projects-parallelism start. O script verifica se o Ansible está instalado na workstation e cria uma estrutura de diretório e arquivos associados para o ambiente de laboratório.
[student@workstation ~]$ lab projects-parallelism start
Mude para o diretório /home/student/projects-parallelism. Examine o conteúdo do diretório do projeto para se familiarizar com os arquivos do projeto.
Examine o conteúdo do arquivo ansible.cfg. Observe que o arquivo de inventário está definido como inventory. Observe também que o parâmetro forks está definido como 4.
[defaults]
inventory=inventory
remote_user=devops
forks=4
...output omitted...
Examine o conteúdo do arquivo inventory. Observe que ele contém um grupo de hosts, webservers, que contém quatro hosts.
[webservers]
servera.lab.example.com
serverb.lab.example.com
serverc.lab.example.com
serverd.lab.example.com
Examine o conteúdo do arquivo playbook.yml. O playbook é executado no grupo de hosts webservers e garante que o pacote httpd mais recente esteja instalado e que o serviço httpd esteja ativado e iniciado.
---
- name: Update web server
hosts: webservers
tasks:
- name: Lastest httpd package installed
yum:
name: httpd
state: latest
notify:
- Restart httpd
handlers:
- name: Restart httpd
service:
name: httpd
enabled: yes
state: restarted
Por fim, examine o conteúdo do arquivo remove_apache.yml. O playbook é executado no grupo de hosts webservers, garante que o serviço httpd esteja desativado e interrompido e, em seguida, garante que o pacote httpd não esteja instalado.
---
- hosts: webservers
tasks:
- service:
name: httpd
enabled: no
state: stopped
- yum:
name: httpd
state: absent
Execute o playbook playbook.yml, usando o comando time para determinar quanto tempo leva para o playbook ser executado. Observe o manual enquanto ele é executado. Observe como o Ansible realiza cada tarefa em todos os quatro hosts ao mesmo tempo.
[student@workstation projects-parallelism]$ time ansible-playbook playbook.yml
PLAY [Update apache] *******************************************************
TASK [Gathering Facts] *****************************************************
ok: [servera.lab.example.com]
ok: [serverd.lab.example.com]
ok: [serverb.lab.example.com]
ok: [serverc.lab.example.com]
...output omitted...
real 0m22.701s
user 0m23.275s
sys 0m2.637s
Execute o playbook remove_apache.yml para interromper e desativar o serviço httpd, além de remover o pacote httpd.
[student@workstation projects-parallelism]$ ansible-playbook remove_apache.yml
Altere o valor do parâmetro forks para 1 em ansible.cfg.
[defaults]
inventory=inventory
remote_user=devops
forks=1
...output omitted...
Execute novamente o playbook playbook.yml, usando o comando time para determinar quanto tempo leva para o playbook ser executado. Observe o playbook enquanto ele é executado. Observe que, desta vez, o Ansible realiza cada tarefa em um host de cada vez. Observe também como a redução do número de forks causou uma demora na execução do playbook.
[student@workstation projects-parallelism]$ time ansible-playbook playbook.yml
PLAY [Update apache] *******************************************************
TASK [Gathering Facts] *****************************************************
ok: [serverb.lab.example.com]
ok: [servera.lab.example.com]
ok: [serverc.lab.example.com]
ok: [serverd.lab.example.com]
...output omitted...
real 0m37.853s
user 0m22.414s
sys 0m4.749s
Execute o playbook remove_apache.yml para interromper e desativar o serviço httpd, além de remover o pacote httpd.
[student@workstation projects-parallelism]$ ansible-playbook remove_apache.yml
Defina o valor do parâmetro forks como 2 em ansible.cfg.
[defaults]
inventory=inventory
remote_user=devops
forks=2
...output omitted...
Adicione o parâmetro serial a seguir à ação no playbook playbook.yml para que a ação só seja executada em dois hosts por vez. O início do playbook deve ser exibido da seguinte maneira:
---
- name: Update web server
hosts: webservers
serial: 2
Execute o playbook playbook.yml novamente. Observe o manual enquanto ele é executado. Observe como o Ansible executa toda a ação em apenas dois hosts antes executá-la novamente nos dois hosts restantes.
[student@workstation projects-parallelism]$ ansible-playbook playbook.yml
PLAY [Update apache] *******************************************************
TASK [Gathering Facts] *****************************************************
ok: [servera.lab.example.com]
ok: [serverb.lab.example.com]
TASK [Latest version of apache installed] **********************************
changed: [servera.lab.example.com]
changed: [serverb.lab.example.com]
...output omitted...
PLAY [Update apache] *******************************************************
TASK [Gathering Facts] *****************************************************
ok: [serverc.lab.example.com]
ok: [serverd.lab.example.com]
TASK [Latest version of apache installed] **********************************
changed: [serverd.lab.example.com]
changed: [serverc.lab.example.com]
...output omitted...
Execute o playbook remove_apache.yml para interromper e desativar o serviço httpd, além de remover o pacote httpd.
[student@workstation projects-parallelism]$ ansible-playbook remove_apache.yml
Defina o valor do parâmetro forks como 4 novamente em ansible.cfg.
[defaults]
inventory=inventory
remote_user=devops
forks=4
...output omitted...
Defina o parâmetro serial no playbook playbook.yml como 3. O início do playbook deve ser exibido da seguinte maneira:
---
- name: Update web server
hosts: webservers
serial: 3
Execute o playbook playbook.yml novamente. Observe o manual enquanto ele é executado. Observe como o Ansible executa toda a ação em apenas três hosts e, depois, a executa novamente no host restante.
[student@workstation projects-parallelism]$ ansible-playbook playbook.yml
PLAY [Update apache] *******************************************************
TASK [Gathering Facts] *****************************************************
ok: [servera.lab.example.com]
ok: [serverb.lab.example.com]
ok: [serverc.lab.example.com]
TASK [Latest version of apache installed] **********************************
changed: [servera.lab.example.com]
changed: [serverb.lab.example.com]
changed: [serverc.lab.example.com]
...output omitted...
PLAY [Update apache] *******************************************************
TASK [Gathering Facts] *****************************************************
ok: [serverd.lab.example.com]
TASK [Latest version of apache installed] **********************************
changed: [serverd.lab.example.com]
...output omitted...
Encerramento
Na workstation, execute o comando lab projects-parallelism finish para limpar este exercício.
[student@workstation ~]$ lab projects-parallelism finish
Isso conclui o exercício orientado.
Objetivos
Depois de concluir esta seção, você deverá ser capaz de gerenciar playbooks grandes importando ou incluindo outros playbooks ou tarefas de arquivos externos, seja incondicionalmente ou com base em um teste condicional. Gerenciamento de playbooks grandes
Quando um playbook fica longo ou complexo, você pode dividi-lo em arquivos menores para facilitar o gerenciamento. Você pode combinar vários playbooks em um playbook principal de maneira modular ou inserir listas de tarefas de um arquivo em uma ação. Isso pode facilitar a reutilização de ações ou sequências de tarefas em projetos diferentes. Inclusão ou importação de arquivos
Há duas operações que o Ansible pode usar para trazer conteúdo para um playbook. Você pode incluir conteúdo, ou você pode importar conteúdo.
Quando você inclui conteúdo, isso é uma operação dinâmica. Os processos com problemas incluíram conteúdo durante a execução do playbook, conforme o conteúdo é acessado.
Quando você importa conteúdo, isso é uma operação estática. O Ansible realiza o pré-processamento do conteúdo importado quando o playbook é inicialmente analisado, antes de a execução ser iniciada. Importação de playbooks
A diretiva import_playbook permite importar arquivos externos contendo listas de ações em um playbook. Em outras palavras, você pode ter um playbook mestre que importe um ou mais playbooks adicionais.
Como o conteúdo que está sendo importado é um playbook completo, o recurso import_playbook só pode ser usado no nível superior de um playbook e não pode ser usado dentro de uma ação. Se você importar vários playbooks, eles serão importados e executados em ordem.
Um exemplo simples de um playbook mestre que importa dois playbooks adicionais é mostrado abaixo:
name: Prepare the web server import_playbook: web.yml
name: Prepare the database server import_playbook: db.yml
Você também pode intercalar ações no seu playbook mestre com playbooks importados.
name: Play 1 hosts: localhost tasks:
name: Import Playbook import_playbook: play2.yml
No exemplo anterior, a ação Play 1 é executada primeiro, seguida pelas ações importadas do playbook play2.yml. Importação e inclusão de tarefas
Você pode importar ou incluir uma lista de tarefas de um arquivo de tarefas em uma ação. Um arquivo de tarefas é um arquivo que contém uma lista simples de tarefas:
[admin@node ~]$ cat webserver_tasks.yml
name: Installs the httpd package yum: name: httpd state: latest
name: Starts the httpd service service: name: httpd state: started
Importação de arquivos de tarefas
Você pode importar estaticamente um arquivo de tarefas para uma ação dentro de um playbook usando o recurso import_tasks. Quando você importa um arquivo de tarefas, as tarefas desse arquivo são inseridas diretamente quando o playbook é analisado. A localização de import_tasks no playbook controla onde as tarefas são inseridas e a ordem na qual várias importações são executadas.
Quando você importa um arquivo de tarefas, as tarefas desse arquivo são inseridas diretamente quando o playbook é analisado. Como import_tasks importa estaticamente as tarefas quando o playbook é analisado, são observados alguns efeitos na maneira como ele funciona.
Ao usar o recurso import_tasks, instruções condicionais definidas na importação, como when, são aplicadas a cada uma das tarefas que são importadas.
Não é possível usar loops com o recurso import_tasks.
Se você usar uma variável para especificar o nome do arquivo a ser importado, não poderá usar uma variável de inventário de grupo ou host.
Inclusão de arquivos de tarefas
Você também pode incluir dinamicamente um arquivo de tarefas para uma ação dentro de um playbook usando o recurso include_tasks.
O recurso include_tasks não processa conteúdo no playbook até que a ação esteja em execução e que parte dela seja realizada. A ordem em que o conteúdo do playbook é processado afeta o funcionamento do recurso de inclusão de tarefas.
Ao usar o recurso include_tasks, instruções condicionais como when definidas na inclusão determinam se as tarefas estão ou não incluídas na ação.
Se você executar ansible-playbook --list-tasks para listar as tarefas no playbook, as tarefas nos arquivos de tarefas incluídos não serão exibidas. As tarefas que incluem os arquivos de tarefas são exibidas. Em comparação, o recurso import_tasks não listaria tarefas que importam arquivos de tarefas, mas sim tarefas individuais dos arquivos de tarefas importados.
Você não pode usar ansible-playbook --start-at-task para iniciar a execução de playbook a partir de uma tarefa que esteja em um arquivo de tarefas incluído.
Você não pode usar uma instrução notify para acionar um nome de manipulador que está em um arquivo de tarefas incluído. Você pode acionar um manipulador no playbook principal que inclui um arquivo de tarefas inteiro, caso em que todas as tarefas no arquivo incluído serão executadas.
Você encontra uma discussão mais detalhada sobre as diferenças de comportamento entre import_tasks e include_tasks quando condicionais são usados em "Condicionais" no Ansible User Guide.
Casos de uso para arquivos de tarefas
Considere os seguintes exemplos em que pode ser útil gerenciar conjuntos de tarefas como arquivos externos separados do playbook:
Se servidores novos exigirem configuração completa, os administradores poderão criar vários conjuntos de tarefas para criar usuários, instalar pacotes, configurar serviços, configurar privilégios, configurar acesso a um sistema de arquivos compartilhado, fortalecer os servidores, instalar atualizações de segurança e instalar um agente de monitoramento. Cada um desses conjuntos de tarefas poderia ser gerenciado por meio de um arquivo de tarefa separado e autocontido.
Se os servidores forem gerenciados coletivamente pelos desenvolvedores, os administradores de sistema e os administradores de banco de dados, então cada organização poderá gravar seu próprio arquivo de tarefas que poderá ser revisado e integrado pelo gerente do sistema.
Se um servidor exigir uma configuração específica, ele poderá ser integrado como um conjunto de tarefas que são executadas com base em uma condicional. Em outras palavras, as tarefas só serão incluídas se critérios específicos forem atendidos.
Se um grupo de servidores precisar executar uma tarefa ou conjunto de tarefas específico, as tarefas poderão ser executadas em um servidor somente se ele fizer parte de um grupo de hosts específico.
Gerenciamento de arquivos de tarefas
Você pode criar um diretório dedicado para arquivos de tarefa e salvar todos os arquivos de tarefa nesse diretório. Depois, seu playbook pode simplesmente incluir ou importar arquivos de tarefas desse diretório. Isso permite a construção de um playbook complexo e facilita o gerenciamento de sua estrutura e componentes. Definição de variáveis para ações e tarefas externas
A incorporação de ações ou tarefas de arquivos externos em playbooks usando a importação do Ansible e incluindo recursos aumenta muito a capacidade de reutilizar tarefas e playbooks em um ambiente do Ansible. Para maximizar a possibilidade de reutilização, esses arquivos de tarefa e ação devem ser o mais genéricos possível. Variáveis podem ser usadas para parametrizar elementos de ação e tarefa a fim de expandir a aplicação de tarefas e ações.
Por exemplo, o arquivo de tarefas a seguir instala o pacote necessário para um serviço web e, depois, ativa e inicia o serviço necessário.
Se você parametrizar o pacote e os elementos de serviço conforme mostrado no exemplo a seguir, o arquivo de tarefas também poderá ser usado para instalação e administração de outro software e de seus serviços, em vez de ser útil somente para serviços web.
Posteriormente, ao incorporar o arquivo de tarefas em um playbook, defina as variáveis a serem usadas para a execução da tarefa da seguinte maneira:
...output omitted... tasks:
O Ansible disponibiliza as variáveis transmitidas para as tarefas importadas do arquivo externo.
Você pode usar a mesma técnica para tornar os arquivos de ação mais reutilizáveis. Ao incorporar um arquivo de ação em um playbook, transmita as variáveis a serem usadas para a execução da ação da seguinte maneira:
...output omitted...
Versões anteriores do Ansible usavam o recurso include para incluir playbooks e arquivos de tarefas, dependendo do contexto. Essa funcionalidade está se tornando obsoleta por vários motivos.
Antes do Ansible2.0, o recurso include operava como uma importação estática. No Ansible2.0, ela foi alterada para operar dinamicamente, mas isso causou algumas limitações. No Ansible2.1, tornou-se possível que o recurso include fosse dinâmico ou estático, dependendo das configurações da tarefa, o que era confuso e sujeito a erros. Houve também problemas em garantir que o recurso include funcionasse corretamente em todos os contextos.
Assim, include foi substituído no Ansible2.4 por novas diretivas, como include_tasks, import_tasks e import_playbook. Você pode encontrar exemplos de include em playbooks mais antigos, mas você deve evitar usá-lo em playbooks novos.
Including and Importing — Ansible Documentation
Creating Reusable Playbooks — Ansible Documentation
Conditionals — Ansible Documentation
Neste exercício, você incluirá e importará playbooks e tarefas em um playbook do Ansible de nível superior.
Resultados
Você será capaz de incluir playbooks e arquivos de tarefas em playbooks.
Faça login na workstation como student usando a senha student.
Na workstation, execute o comando lab projects-file start. O script cria o diretório de trabalho, /home/student/projects-file, e arquivos de projeto associados.
[student@workstation ~]$ lab projects-file start
Na workstation, com o usuário student, acesse o diretório /home/student/projects-file.
[student@workstation ~]$ cd ~/projects-file
[student@workstation projects-file]$
Revise o conteúdo dos três arquivos no subdiretório tasks.
Revise o conteúdo do arquivo tasks/environment.yml. O arquivo contém tarefas para instalação de pacotes e administração de serviços.
[student@workstation projects-file]$ cat tasks/environment.yml
---
- name: Install the {{ package }} package
yum:
name: "{{ package }}"
state: latest
- name: Start the {{ service }} service
service:
name: "{{ service }}"
enabled: true
state: started
Revise o conteúdo do arquivo tasks/firewall.yml. O arquivo contém tarefas para instalação, administração e configuração de software de firewall.
[student@workstation projects-file]$ cat tasks/firewall.yml
---
- name: Install the firewall
yum:
name: "{{ firewall_pkg }}"
state: latest
- name: Start the firewall
service:
name: "{{ firewall_svc }}"
enabled: true
state: started
- name: Open the port for {{ rule }}
firewalld:
service: "{{ item }}"
immediate: true
permanent: true
state: enabled
loop: "{{ rule }}"
Revise o conteúdo do arquivo tasks/placeholder.yml. Esse arquivo contém uma tarefa para preencher um arquivo de conteúdo da web de espaço reservado.
[student@workstation projects-file]$ cat tasks/placeholder.yml
---
- name: Create placeholder file
copy:
content: "{{ ansible_facts['fqdn'] }} has been customized using Ansible.\n"
dest: "{{ file }}"
Revise o conteúdo do arquivo test.yml no subdiretório plays. Esse arquivo contém uma ação que testa conexões com um serviço web.
---
- name: Test web service
hosts: localhost
become: no
tasks:
- name: connect to internet web server
uri:
url: "{{ url }}"
status_code: 200
Crie um playbook chamado playbook.yml. Defina a primeira ação com o nome Configure web server. A ação deve ser executada no host gerenciado servera.lab.example.com definido no arquivo inventory. O início do arquivo deve se parecer com o seguinte:
---
- name: Configure web server
hosts: servera.lab.example.com
No playbook playbook.yml, defina a seção de tarefas com três conjuntos de tarefas. Inclua o primeiro conjunto de tarefas do arquivo de tarefas tasks/environment.yml. Defina as variáveis necessárias para instalar o pacote httpd e para ativar e iniciar o serviço httpd. Importe o segundo conjunto de tarefas do arquivo de tarefas tasks/firewall.yml. Defina as variáveis necessárias para instalar o pacote firewalld para ativar e iniciar o serviço firewalld e permitir conexões http. Importe o terceiro conjunto de tarefas do arquivo de tarefas tasks/placeholder.yml.
Crie a seção de tarefas na primeira ação adicionando a seguinte entrada ao playbook playbook.yml.
tasks:
Inclua o primeiro conjunto de tarefas de tasks/environment.yml usando o recurso include_tasks. Defina as variáveis package e service como httpd . Defina a variável svc_state como started.
- name: Include the environment task file and set the variables
include_tasks: tasks/environment.yml
vars:
package: httpd
service: httpd
when: ansible_facts['os_family'] == 'RedHat'
Importe o segundo conjunto de tarefas de tasks/firewall.yml usando o recurso import_tasks. Defina as variáveis firewall_pkg e firewall_svc como firewalld. Defina a variável rule como http.
- name: Import the firewall task file and set the variables
import_tasks: tasks/firewall.yml
vars:
firewall_pkg: firewalld
firewall_svc: firewalld
rule:
- http
- https
Importe o último conjunto de tarefas de tasks/placeholder.yml usando o recurso import_tasks. Defina a variável file como /var/www/html/index.html .
- name: Import the placeholder task file and set the variable
import_tasks: tasks/placeholder.yml
vars:
file: /var/www/html/index.html
Adicione uma segunda e última ação ao playbook playbook.yml usando o conteúdo do playbook plays/test.yml.
Adicione uma segunda ação ao playbook playbook.yml para validar a instalação do servidor web. Importe a ação de plays/test.yml. Defina a variável url como http://servera.lab.example.com.
- name: Import test play file and set the variable
import_playbook: plays/test.yml
vars:
url: 'http://servera.lab.example.com'
Após a conclusão das alterações, seu playbook deve se parecer com o seguinte:
---
- name: Configure web server
hosts: servera.lab.example.com
tasks:
- name: Include the environment task file and set the variables
include_tasks: tasks/environment.yml
vars:
package: httpd
service: httpd
when: ansible_facts['os_family'] == 'RedHat'
- name: Import the firewall task file and set the variables
import_tasks: tasks/firewall.yml
vars:
firewall_pkg: firewalld
firewall_svc: firewalld
rule:
- http
- https
- name: Import the placeholder task file and set the variable
import_tasks: tasks/placeholder.yml
vars:
file: /var/www/html/index.html
- name: Import test play file and set the variable
import_playbook: plays/test.yml
vars:
url: 'http://servera.lab.example.com'
Salve as alterações no playbook playbook.yml.
Antes de executar o playbook, verifique se a sintaxe está correta executando ansible-playbook --syntax-check. Se forem relatados erros, corrija-os antes de ir para a próxima etapa.
[student@workstation projects-file]$ ansible-playbook playbook.yml --syntax-check
playbook: playbook.yml
Execute o playbook playbook.yml. A saída do playbook mostra a importação da tarefa e os arquivos de ação.
[student@workstation projects-file]$ ansible-playbook playbook.yml
PLAY [Configure web server] ***********************************************
TASK [Gathering Facts] ****************************************************
ok: [servera.lab.example.com]
TASK [Install the httpd package] ******************************************
changed: [servera.lab.example.com]
TASK [Start the httpd service] ********************************************
changed: [servera.lab.example.com]
TASK [Install the firewall] ***********************************************
ok: [servera.lab.example.com]
TASK [Start the firewall] *************************************************
ok: [servera.lab.example.com]
TASK [Open the port for http] *********************************************
changed: [servera.lab.example.com]
TASK [Create placeholder file] ********************************************
changed: [servera.lab.example.com]
PLAY [Test web service] ***************************************************
TASK [Gathering Facts] ****************************************************
ok: [localhost]
TASK [connect to internet web server] *************************************
ok: [localhost]
PLAY RECAP ****************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0
servera.lab.example.com : ok=8 changed=4 unreachable=0 failed=0
Encerramento
Na workstation, execute o script lab projects-file finish para limpar este exercício.
[student@workstation ~]$ lab projects-file finish
Isso conclui o exercício orientado.
Lista de verificação de desempenho
Neste laboratório, você modificará um playbook grande para que seja mais fácil de gerenciar usando padrões de host, inclusões, importações e um inventário dinâmico. Além disso, você ajustará a maneira com que o playbook é processado pelo Ansible.
Resultados
Você pode simplificar as referências de host gerenciados em um playbook especificando padrões de host em um inventário dinâmico. Você também deve ser capaz de reestruturar um playbook para que as tarefas sejam importadas de arquivos de tarefas externos e ajustar o playbook para atualizações em cascata.
Instruções
Você herdou um playbook do administrador anterior. O playbook é usado para configurar um serviço web em servera.lab.example.com, serverb.lab.example.com, serverc.lab.example.com e serverd.lab.example.com. O playbook também configura o firewall nos quatro hosts gerenciados para que o tráfego da web seja permitido.
Faça login na workstation como student usando a senha student.
Na workstation, execute o comando lab projects-review start. Este script de configuração garante que os hosts gerenciados sejam acessíveis na rede. Ele também garante que o arquivo de configuração, o arquivo de inventário e o playbook corretos do Ansible estejam instalados no nó de controle.
[student@workstation ~]$ lab projects-review start
Faça as alterações a seguir no arquivo do playbook playbook.yml para que seja mais fácil gerenciá-lo e ajustá-lo para que futuras execuções utilizem atualizações em cascata, a fim de impedir que todos os quatro servidores web fiquem indisponíveis ao mesmo tempo.
Simplifique a lista de hosts gerenciados no playbook usando um padrão de host curinga. Use o script de inventário dinâmico inventory/inventory.py para verificar o padrão de host curinga.
Altere o diretório para o diretório de trabalho /home/student/projects-review. Revise o arquivo de configuração ansible.cfg para determinar o local do arquivo de inventário. O inventário é definido como o subdiretório inventory, e esse subdiretório contém um script de inventário dinâmico inventory.py.
[student@workstation ~]$ cd ~/projects-review
[student@workstation projects-review]$ cat ansible.cfg
[defaults]
inventory = inventory
...output omitted...
[student@workstation projects-review]$ ll
total 16
-rw-rw-r--. 1 student student 33 Dec 19 00:48 ansible.cfg
drwxrwxr-x. 2 student student 4096 Dec 18 22:35 files
drwxrwxr-x. 2 student student 4096 Dec 19 01:18 inventory
-rw-rw-r--. 1 student student 959 Dec 18 23:48 playbook.yml
[student@workstation projects-review]$ ll inventory/
total 4
-rwxrwxr-x. 1 student student 612 Dec 19 01:18 inventory.py
Torne o script de inventário dinâmico inventory/inventory.py executável e, em seguida, execute o script de inventário dinâmico com a opção --list para exibir uma lista completa de hosts no inventário.
[student@workstation projects-review]$ chmod 755 inventory/inventory.py
[student@workstation projects-review]$ inventory/inventory.py --list
{"all": {"hosts": ["servera.lab.example.com", "serverb.lab.example.com", "serverc.lab.example.com", "serverd.lab.example.com", "workstation.lab.example.com"], "vars": { }}}
Verifique se o padrão de host server*.lab.example.com identifica corretamente os quatro hosts gerenciados que são direcionados pelo playbook playbook.yml.
[student@workstation projects-review]$ ansible server*.lab.example.com \
> --list-hosts
hosts (4):
serverb.lab.example.com
serverd.lab.example.com
servera.lab.example.com
serverc.lab.example.com
Substitua a lista de hosts no playbook playbook.yml com o padrão de host server*.lab.example.com.
---
- name: Install and configure web service
hosts: server*.lab.example.com
...output omitted...
Reestruture o playbook de modo que as três primeiras tarefas dele sejam mantidas em um arquivo de tarefas externo localizado em tasks/web_tasks.yml. Use o recurso import_tasks para incorporar esse arquivo de tarefas no playbook.
Crie o subdiretório tasks.
[student@workstation projects-review]$ mkdir tasks
Coloque o conteúdo das três primeiras tarefas do playbook playbook.yml no arquivo tasks/web_tasks.yml. O arquivo de tarefas deve ter o seguinte conteúdo:
---
- name: Install httpd
yum:
name: httpd
state: latest
- name: Enable and start httpd
service:
name: httpd
enabled: true
state: started
- name: Tuning configuration installed
copy:
src: files/tune.conf
dest: /etc/httpd/conf.d/tune.conf
owner: root
group: root
mode: 0644
notify:
- restart httpd
Remova as três primeiras tarefas do playbook playbook.yml e insira as linhas a seguir no lugar delas, a fim de importar o arquivo de tarefas tasks/web_tasks.yml.
- name: Import the web_tasks.yml task file
import_tasks: tasks/web_tasks.yml
Reestruture o playbook de modo que a quarta, quinta e sexta tarefas dele sejam mantidas em um arquivo de tarefas externo localizado em tasks/firewall_tasks.yml. Use o recurso import_tasks para incorporar esse arquivo de tarefas no playbook.
Coloque o conteúdo das três tarefas restantes no playbook playbook.yml para o arquivo tasks/firewall_tasks.yml. O arquivo de tarefas deve conter o conteúdo a seguir.
---
- name: Install firewalld
yum:
name: firewalld
state: latest
- name: Enable and start the firewall
service:
name: firewalld
enabled: true
state: started
- name: Open the port for http
firewalld:
service: http
immediate: true
permanent: true
state: enabled
Remova as três tarefas restantes do playbook playbook.yml e insira as linhas a seguir no lugar delas, a fim de importar o arquivo de tarefas tasks/firewall_tasks.yml.
- name: Import the firewall_tasks.yml task file
import_tasks: tasks/firewall_tasks.yml
Há duplicação de tarefas entre os arquivos tasks/web_tasks.yml e tasks/firewall_tasks.yml. Mova as tarefas que instalam pacotes e ativam serviços para um novo arquivo chamado tasks/install_and_enable.yml e atualize-as para que usem variáveis. Substitua as tarefas originais por instruções import_tasks, passando valores de variáveis adequados.
Copie as tarefas do yum e de serviço de tasks/web_tasks.yml para um novo arquivo chamado tasks/install_and_enable.yml.
---
- name: Install httpd
yum:
name: httpd
state: latest
- name: Enable and start httpd
service:
name: httpd
enabled: true
state: started
Substitua os nomes do pacote e do serviço em tasks/install_and_enable.yml pelas variáveis package e service.
---
- name: Install {{ package }}
yum:
name: "{{ package }}"
state: latest
- name: Enable and start {{ service }}
service:
name: "{{ service }}"
enabled: true
state: started
Substitua as tarefas do yum e de serviço em tasks/web_tasks.yml e tasks/firewall_tasks.yml por instruções import_tasks.
---
- name: Install and start httpd
import_tasks: install_and_enable.yml
vars:
package: httpd
service: httpd
---
- name: Install and start firewalld
import_tasks: install_and_enable.yml
vars:
package: firewalld
service: firewalld
Como o manipulador para reiniciar o serviço httpd pode ser acionado se houver mudanças futuras no arquivo files/tune.conf, implemente o recurso de atualização em cascata no playbook playbook.yml e defina o tamanho do lote da atualização em cascata para dois hosts.
Adicione o parâmetro serial ao playbook playbook.yml.
---
- name: Install and configure web service
hosts: server*.lab.example.com
serial: 2
...output omitted...
Verifique se as alterações no playbook playbook.yml foram feitas corretamente e, em seguida, execute o playbook.
Verifique se o playbook playbook.yml contém o conteúdo a seguir.
---
- name: Install and configure web service
hosts: server*.lab.example.com
serial: 2
tasks:
- name: Import the web_tasks.yml task file
import_tasks: tasks/web_tasks.yml
- name: Import the firewall_tasks.yml task file
import_tasks: tasks/firewall_tasks.yml
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
Execute o playbook com ansible-playbook --syntax-check para verificar se ele não contém erros de sintaxe. Se houver erros, corrija-os antes de continuar.
[student@workstation projects-review]$ ansible-playbook playbook.yml \
> --syntax-check
playbook: playbook.yml
Execute o playbook. O playbook deve executar o host como uma atualização em cascata com um tamanho de lote de dois hosts gerenciados.
[student@workstation projects-review]$ ansible-playbook playbook.yml
PLAY [Install and configure web service] ***********************************
TASK [Gathering Facts] *****************************************************
ok: [serverd.lab.example.com]
ok: [serverb.lab.example.com]
TASK [Install httpd] *******************************************************
changed: [serverd.lab.example.com]
changed: [serverb.lab.example.com]
TASK [Enable and start httpd] **********************************************
changed: [serverd.lab.example.com]
changed: [serverb.lab.example.com]
TASK [Tuning configuration installed] **************************************
changed: [serverb.lab.example.com]
changed: [serverd.lab.example.com]
TASK [Install firewalld] ***************************************************
ok: [serverb.lab.example.com]
ok: [serverd.lab.example.com]
TASK [Enable and start firewalld] ******************************************
ok: [serverd.lab.example.com]
ok: [serverb.lab.example.com]
TASK [Open the port for http] **********************************************
changed: [serverd.lab.example.com]
changed: [serverb.lab.example.com]
RUNNING HANDLER [restart httpd] ********************************************
changed: [serverb.lab.example.com]
changed: [serverd.lab.example.com]
PLAY [Install and configure web service] ***********************************
TASK [Gathering Facts] *****************************************************
ok: [serverc.lab.example.com]
ok: [servera.lab.example.com]
TASK [Install httpd] *******************************************************
changed: [serverc.lab.example.com]
changed: [servera.lab.example.com]
TASK [Enable and start httpd] **********************************************
changed: [serverc.lab.example.com]
changed: [servera.lab.example.com]
TASK [Tuning configuration installed] **************************************
changed: [servera.lab.example.com]
changed: [serverc.lab.example.com]
TASK [Install firewalld] ***************************************************
ok: [servera.lab.example.com]
ok: [serverc.lab.example.com]
TASK [Enable and start firewalld] ******************************************
ok: [servera.lab.example.com]
ok: [serverc.lab.example.com]
TASK [Open the port for http] **********************************************
changed: [servera.lab.example.com]
changed: [serverc.lab.example.com]
RUNNING HANDLER [restart httpd] ********************************************
changed: [serverc.lab.example.com]
changed: [servera.lab.example.com]
PLAY RECAP *****************************************************************
servera.lab.example.com : ok=8 changed=2 unreachable=0 failed=0
serverb.lab.example.com : ok=8 changed=5 unreachable=0 failed=0
serverc.lab.example.com : ok=8 changed=5 unreachable=0 failed=0
serverd.lab.example.com : ok=8 changed=5 unreachable=0 failed=0
Avaliação
Execute o comando lab projects-review grade em workstation para confirmar o êxito deste exercício. Corrija todas as falhas relatadas e execute novamente o script até que ele seja concluído com êxito.
[student@workstation ~]$ lab projects-review grade
Encerramento
Na workstation, execute o script lab projects-review finish para limpar os recursos criados neste laboratório.
[student@workstation ~]$ lab projects-review finish
Isso conclui o laboratório.
Neste capítulo, você aprendeu que:
Os padrões de host são usados para especificar os hosts gerenciados que devem ser o alvo das ações ou comandos ad hoc.
Scripts dinâmicos de inventário podem ser usados para gerar listas dinâmicas de hosts gerenciados a partir de serviços de diretório ou outras fontes externas ao Ansible.
O parâmetro forks no arquivo de configuração do Ansible define o número máximo de conexões paralelas a hosts gerenciados.
O parâmetro serial pode ser usado para implementar atualizações em cascata em hosts gerenciados definindo o número de hosts gerenciados em cada lote de atualização em cascata
Você pode usar o recurso import_playbook para incorporar arquivos de ação externos em playbooks.
Você pode usar os recursos include_tasks ou import_tasks para incorporar arquivos de tarefas externos em playbooks.
Depois de concluir esta seção, você deverá ser capaz de descrever o que é uma função, como ela é estruturada e como usá-la em um playbook.
À medida que você desenvolve mais playbooks, provavelmente descobrirá que tem muitas oportunidades de reutilizar códigos de playbooks já escritos. Talvez uma ação para configurar um banco de dados MySQL para um aplicativo possa ser reutilizada, com diferentes nomes de host, senhas e usuários, para configurar um banco de dados MySQL para outro aplicativo.
Porém, no mundo real, essa ação pode ser longa e complexa, com muitos arquivos incluídos ou importados, e com tarefas e manipuladores para gerenciar várias situações. Copiar todo esse código para outro playbook pode ser uma tarefa demorada.
As funções do Ansible são uma maneira de facilitar a reutilização do código do Ansible de maneira genérica. Você pode empacotar, em uma estrutura de diretório padronizada, todas as tarefas, variáveis, arquivos, templates e outros recursos necessários para provisionar a infraestrutura ou implantar aplicativos. Copie essa função de projeto para projeto simplesmente copiando o diretório. Você pode simplesmente chamar essa função a partir de uma ação para executá-la.
Uma função bem escrita permitirá que você transmita variáveis para a função do playbook que se ajusta ao seu comportamento, definindo todos os nomes de host específicos do site, endereços IP, nomes de usuário, segredos ou outros detalhes específicos do local que você precisa. Por exemplo, uma função para implementar um servidor de banco de dados pode ter sido escrita para suportar variáveis que configuram o nome do host, o usuário administrador e a senha do banco de dados e outros parâmetros que precisam de personalização para sua instalação. O autor da função também pode garantir que valores padrão razoáveis sejam definidos para essas variáveis se você optar por não configurá-los na ação.
As funções do Ansible têm os seguintes benefícios:
As funções agrupam o conteúdo, permitindo fácil compartilhamento de código entre os usuários
As funções podem ser gravadas para definirem os elementos essenciais de um tipo de sistema: servidor web, servidor de banco de dados, repositório Git ou outro propósito
As funções tornam os projetos grandes mais gerenciáveis
As funções podem ser desenvolvidas em paralelo por diferentes administradores
Além de escrever, usar, reutilizar e compartilhar suas próprias funções, você pode obter funções de outras fontes. Algumas funções são incluídas como parte do RedHat EnterpriseLinux, no pacote rhel-system-roles. Você também pode obter diversas funções com suporte da comunidade no site do Ansible Galaxy. Mais adiante neste capítulo, você aprenderá mais sobre essas funções.
Uma função do Ansible é definida por uma estrutura padronizada de
subdiretórios e arquivos. O diretório do nível superior define o
nome da função em si. Os arquivos são organizados em subdiretórios
que são nomeados de acordo com a finalidade de cada arquivo na função,
como tasks
e handlers
. Os subdiretórios files
e templates
contêm arquivos referenciados por tarefas em outros arquivos YAML.
O comando tree a seguir exibe a estrutura de diretórios da função user.example
.
[user@host roles]$
tree user.example
user.example/ ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── README.md ├── tasks │ └── main.yml ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars └── main.yml
Nem toda função terá todos esses diretórios.
As variáveis de função são definidas criando um arquivo vars/main.yml
com pareschave-valor na hierarquia de diretórios da função. Elas
são referenciadas no arquivo YAML da função como qualquer outra
variável: {{
.
Essas variáveis têm alta precedência e não podem ser substituídas
por variáveis de inventário. Essas variáveis destinam-se a serem
usadas pelo funcionamento interno da função. VAR_NAME
}}
As variáveis padrão
permitem que os valores padrão sejam definidos para variáveis que podem
ser usadas em uma ação para configurar a função ou personalizar seu
comportamento. Elas são definidas ao criar um arquivo defaults/main.yml
com pares key:value na hierarquia de diretórios de função. As
variáveis padrão têm a precedência mais baixa entre as variáveis
disponíveis. Elas podem ser facilmente substituídas por outra
variável, incluindo variáveis de inventário. Essas variáveis
destinam-se a fornecer à pessoa que está escrevendo uma ação que usa a
função uma maneira de personalizar ou controlar exatamente o que vai
fazer. Elas podem ser usadas para fornecer informações para a função
necessária para configurar ou implantar algo adequadamente.
Defina uma variável específica em vars/main.yml
ou defaults/main.yml
, mas não em ambos. As variáveis padrão deverão ser usadas quando a intenção for que seus valores sejam substituídos.
As funções não devem conter dados específicos de site. Elas definitivamente não devem conter nenhum segredo, como senhas ou chaves privadas.
Isso porque as funções devem ser genéricas, reutilizáveis e livremente compartilháveis. Detalhes específicos de sites não devem ser codificados para eles.
Segredos devem ser fornecidos para a função através de outros meios. Esse é um dos motivos pelos quais talvez você queira definir variáveis de função ao chamar uma função. As variáveis de função definidas na ação podem fornecer o segredo ou apontar para um arquivo criptografado no Ansible Vault que contém o segredo.
O uso de funções em um playbook é simples. O exemplo a seguir mostra uma maneira de chamar as funções do Ansible.
--- - hosts: remote.example.com roles: - role1 - role2
Para cada função específica, as tarefas, os
manipuladores, as variáveis e as dependências da função serão importados
no playbook nessa ordem. As tarefas copy
, script
, template
ou include_tasks
/import_tasks
na função podem fazer referência aos arquivos, modelos ou arquivos de
tarefas relevantes na função sem nomes de caminhos absolutos ou
relativos. O Ansible as procura nos subdiretórios files
, templates
ou tasks
da função, respectivamente.
Quando você usa uma seção roles
para importar as funções para uma ação, as funções serão executadas
primeiro, antes de quaisquer tarefas que você definir para essa ação.
O exemplo a seguir define valores para duas variáveis de função de role2
, var1
e var2
. Os valores das variáveis defaults
e vars
são substituídos quando role2
é usada.
--- - hosts: remote.example.com roles: - role: role1 - role: role2 var1: val1 var2: val2
Outra sintaxe YAML equivalente que você pode ver nesse caso é:
--- - hosts: remote.example.com roles: - role: role1 - { role: role2, var1: val1, var2: val2 }
Há situações em que isso pode ser mais difícil de ler, mesmo sendo mais compacto.
As variáveis de função definidas em linha (parâmetros de função), como nos exemplos anteriores, tem precedência muito alta. Elas substituirão a maioria das outras variáveis.
Tenha muito
cuidado para não reutilizar os nomes de variáveis de função que você
definir em linha em qualquer outro lugar da sua ação, já que os valores
das variáveis de função substituirão as variáveis de inventário e
qualquer vars
de ação.
Para cada ação em um playbook, as tarefas são executadas conforme ordenadas na lista de tarefas. Depois que todas as tarefas são executadas, os manipuladores notificados são executados.
Quando uma função é adicionada a uma ação, as tarefas da função são adicionadas ao início da lista de tarefas. Se uma segunda função for incluída em uma ação, sua lista de tarefas é adicionada após a primeira função.
Os manipuladores de função são adicionados às
execuções da mesma maneira que as tarefas de função são adicionadas às
ações. Cada ação define uma lista de manipuladores. Os
manipuladores de função são adicionados à lista de manipuladores
primeiro, seguidos de todos os manipuladores definidos na seção handlers
da ação.
Em determinados cenários, pode ser necessário executar algumas
tarefas de ação antes das funções. Para suportar esses cenários, as
ações podem ser configuradas com uma seção pre_tasks
.
Qualquer tarefa listada nessa seção é executada antes que quaisquer
funções sejam executadas. Se qualquer uma dessas tarefas notificar
um manipulador, essas tarefas do manipulador serão executadas antes das
funções ou tarefas normais.
As ações também suportam uma palavra-chave post_tasks
. Essas tarefas são executadas após as tarefas normais da ação e todos os manipuladores que elas notificam são executados.
A ação a seguir mostra um exemplo com pre_tasks
, roles
, tasks
, post_tasks
e handlers
. É incomum que uma ação contenha todas essas seções.
- name: Play to illustrate order of execution hosts: remote.example.com pre_tasks: - debug: msg: 'pre-task' notify: my handler roles: - role1 tasks: - debug: msg: 'first task' notify: my handler post_tasks: - debug: msg: 'post-task' notify: my handler handlers: - name: my handler debug: msg: Running my handler
No exemplo acima, uma tarefa debug
é executada em cada seção para notificar o manipulador handler
. A tarefa my handler
é executada três vezes:
depois que todas as tarefas pre_tasks
são executadas
depois que todas as tarefas de função e tarefas da seção tasks
forem executadas
depois que todas as post_tasks
são executadas
As funções podem ser adicionadas a uma ação usando uma tarefa comum, não apenas incluindo-as na seção roles
de uma ação. Use o módulo include_role
para incluir dinamicamente uma função e use o módulo import_role
para importar estaticamente uma função.
O manual a seguir demonstra como uma função pode ser incluída usando uma tarefa com o módulo include_role
.
- name: Execute a role as a task hosts: remote.example.com tasks: - name: A normal task debug: msg: 'first task' - name: A task to include role2 here include_role: role2
O módulo include_role
foi adicionado ao Ansible 2.3, e o módulo import_role
ao Ansible 2.4.
Escolha a resposta correta para as seguintes perguntas:
Quando concluir o teste, clique em
. Se quiser tentar novamente, clique em . Clique em para ver todas as respostas corretas.Depois de concluir esta seção, você deverá ser capaz de escrever playbooks que aproveitem as funções do sistema do RedHat EnterpriseLinux para realizar operações padrão.
A partir do RedHat EnterpriseLinux 7.4, várias funções do Ansible foram fornecidas com o sistema operacional como parte do pacote rhel-system-roles. No RedHat Enterprise Linux8, o pacote está disponível no canal AppStream. Uma breve descrição de cada função:
As funções do sistema têm a finalidade de padronizar a configuração dos subsistemas do RedHat Enterprise Linux em várias versões. Use as funções do sistema para configurar qualquer RedHat Enterprise Linux, na versão 6.10 e posteriores.
Gerenciamento de configuração simplificado
Como exemplo, o serviço de sincronização de horário recomendado para o RedHat Enterprise Linux7 é o serviço chronyd
. No entanto, no Red Hat Enterprise Linux 6, o serviço recomendado é o ntpd
.
Em um ambiente com uma mistura de hosts Red Hat Enterprise Linux 6
e 7, um administrador deve gerenciar os arquivos de configuração para
ambos os serviços.
Com as funções do sistema do RHEL, os
administradores não precisam mais manter os arquivos de configuração
para ambos os serviços. Os administradores podem usar a função rhel-system-roles.timesync
para configurar a sincronização de horário para ambos os hosts Red Hat
Enterprise Linux 6 e 7. Um arquivo YAML simplificado contendo
variáveis de função define a configuração da sincronização de horário
para os dois tipos de hosts.
Suporte para funções do sistema RHEL
As funções do sistema do RHEL são derivadas do projeto de funções do sistema do Linux open source, encontrado no Ansible Galaxy. Diferentemente das funções do sistema do Linux, as funções do sistema do RHEL têm suporte da Red Hat como parte de uma subscrição padrão do Red Hat Enterprise Linux. As funções do sistema do RHEL têm os mesmos benefícios de suporte do ciclo de vida que vêm com uma subscrição do RedHat Enterprise Linux.
Todas as funções do sistema são testadas e estáveis. As funções Fully Supported
do sistema também têm interfaces estáveis. Para qualquer função de sistema Fully Supported
,
a Red Hat fará o possível para garantir que as variáveis de função não
sejam alteradas em versões futuras. A refatoração do playbook devido
a mudanças de função do sistema deve ser mínima.
As funções de prévia de tecnologia
do sistema podem utilizar diferentes variáveis de função em versões
futuras. O teste de integração é recomendado para playbooks que
incorporam qualquer função de prévia de tecnologia
. Os playbooks podem exigir refatoração se as variáveis de função forem alteradas em uma versão futura da função.
Outras funções estão em desenvolvimento no projeto de funções de sistema do Linux upstream, mas ainda não estão disponíveis por meio de uma subscrição do RHEL. Essas funções estão disponíveis no Ansible Galaxy.
As funções do sistema do RHEL são fornecidas pelo pacote rhel-system-roles, que está disponível no canal AppStream
. Instale esse pacote no nó de controle do Ansible.
Use o procedimento a seguir para instalar o pacote rhel-system-roles. O procedimento pressupõe que o nó de controle está registrado em uma subscrição do RedHat Enterprise Linux e que o Ansible Engine está instalado. Consulte a seção em Instalação do Ansible para obter mais informações.
Instale as funções do sistema do RHEL.
[root@host ~]#
yum install rhel-system-roles
Após a instalação, as funções do sistema RHEL estão localizadas no diretório /usr/share/ansible/roles
:
[root@host ~]#
ls -l /usr/share/ansible/roles/
total 20 ...output omitted... linux-system-roles.kdump -> rhel-system-roles.kdump ...output omitted... linux-system-roles.network -> rhel-system-roles.network ...output omitted... linux-system-roles.postfix -> rhel-system-roles.postfix ...output omitted... linux-system-roles.selinux -> rhel-system-roles.selinux ...output omitted... linux-system-roles.timesync -> rhel-system-roles.timesync ...output omitted... rhel-system-roles.kdump ...output omitted... rhel-system-roles.network ...output omitted... rhel-system-roles.postfix ...output omitted... rhel-system-roles.selinux ...output omitted... rhel-system-roles.timesync
O nome upstream correspondente de cada função é vinculado à função do sistema RHEL. Isso permite que uma função seja referenciada em um playbook por qualquer nome.
O padrão roles_path
no RedHat Enterprise Linux inclui /usr/share/ansible/roles
no caminho; portanto, o Ansible deve encontrar automaticamente essas funções quando referenciadas por um playbook.
O Ansible pode não encontrar as funções do sistema se roles_path
tiver sido substituído no arquivo de configuração atual do Ansible, se a variável de ambiente ANSIBLE_ROLES_PATH
estiver definida ou se houver outra função de mesmo nome em um diretório listado anteriormente em roles_path
.
Acesso à documentação para funções do sistema RHEL
Após a instalação, a documentação das funções do sistema RHEL é encontrada no diretório /usr/share/doc/rhel-system-roles-
. A documentação é organizada em subdiretórios por subsistema: <version>
/
[root@host ~]#
ls -l /usr/share/doc/rhel-system-roles/
total 4 drwxr-xr-x. ...output omitted... kdump drwxr-xr-x. ...output omitted... network drwxr-xr-x. ...output omitted... postfix drwxr-xr-x. ...output omitted... selinux drwxr-xr-x. ...output omitted... timesync
O diretório de documentação de cada função contém um arquivo README.md
. O arquivo README.md
contém uma descrição da função, juntamente com informações de uso da função.
O arquivo README.md
também descreve variáveis de função que afetam o comportamento da função. Muitas vezes, o arquivo README.md
contém um trecho de playbook que demonstra as configurações da variável para um cenário de configuração comum.
Alguns diretórios de documentação de função contêm exemplos de playbooks. Ao usar uma função pela primeira vez, revise os playbooks de exemplo adicionais no diretório da documentação.
A
documentação das funções do sistema RHEL corresponde à documentação das
funções do sistema Linux. Use um navegador da web para acessar a
documentação das funções upstream no site do Ansible Galaxy, https://galaxy.ansible.com
.
Suponhamos que você precise configurar a sincronização de horário
NTP nos seus servidores. Você poderia gravar a automação para
executar cada uma das tarefas necessárias. Mas as funções do sistema
RHEL incluem uma função que faz isso, rhel-system-roles.timesync
.
A função é documentada em README.md
no diretório /usr/share/doc/rhel-system-roles/timesync
.
O arquivo descreve todas as variáveis que afetam o comportamento da
função e contém três trechos de playbook que ilustram diferentes
configurações de sincronização de horário.
Para configurar manualmente os servidores NTP, a função tem uma variável chamada timesync_ntp_servers
.
Ela recebe uma lista de servidores NTP. Cada item na lista é
composto por um ou mais atributos. Os dois atributos principais são:
Dada essa informação, o exemplo a seguir é uma ação que usa a função rhel-system-roles.timesync
para configurar hosts gerenciados a fim de obter o horário de três
servidores NTP usando a sincronização inicial rápida. Além disso,
foi adicionada uma tarefa que usa o módulo fuso horário
para definir o fuso horário dos hosts para UTC.
- name: Time Synchronization Play hosts: servers vars: timesync_ntp_servers: - hostname: 0.rhel.pool.ntp.org iburst: yes - hostname: 1.rhel.pool.ntp.org iburst: yes - hostname: 2.rhel.pool.ntp.org iburst: yes timezone: UTC roles: - rhel-system-roles.timesync tasks: - name: Set timezone timezone: name: "{{ timezone }}"
Se você quiser definir um fuso horário diferente, poderá usar o comando tzselect para procurar outros valores válidos. Você também pode usar o comando timedatectl para verificar as configurações atuais do relógio.
Este exemplo define as variáveis de função em uma seção vars
da ação, mas uma prática mais recomendada pode ser configurá-los como variáveis de inventário para hosts ou grupos de hosts.
Considere um projeto de playbook com a seguinte estrutura:
[root@host playbook-project]#
tree
. ├── ansible.cfg ├── group_vars │ └── servers │ └── timesync.yml├── inventory └── timesync_playbook.yml
Essa estrutura separa corretamente a função, o código do playbook e as configurações. O código do playbook é simples, fácil de ler e não deve exigir refatoração complexa. O conteúdo da função é mantido e suportado pela RedHat. Todas as configurações são tratadas como variáveis de inventário.
Essa estrutura também é compatível
com um ambiente dinâmico e heterogêneo. Hosts com novos requisitos
de sincronização de horário podem ser colocados em um novo grupo de
hosts. Variáveis apropriadas são definidas em um arquivo YAML e
colocadas no subdiretório group_vars
(ou host_vars
) apropriado.
Como outro exemplo, a função rhel-system-roles.selinux
simplifica o gerenciamento das configurações do SELinux. Ela é
implementada usando os módulos do Ansible relacionados ao SELinux. A
vantagem de usar essa função é que em vez de gravar suas próprias
tarefas, você fica livre da responsabilidade de gravá-las. Em vez
disso, você fornece variáveis para a função a fim de configurá-la, e o
código mantido na função garantirá que sua configuração desejada do
SELinux seja aplicada.
Entre as tarefas que essa função pode executar estão:
Definir o modo de imposição ou permissivo
Executar restorecon em partes da hierarquia do sistema de arquivos
Definir valores booleanos SELinux
Definir contextos de arquivos SELinux persistentemente
Definir mapeamentos de usuários do SELinux
Chamado da função do SELinux
Às vezes, a função do SELinux deve garantir que os hosts gerenciados sejam reinicializados para aplicar completamente suas alterações. No entanto, ele não reinicia os hosts. Isso é feito para que você possa controlar como a reinicialização é tratada. Porém, isso significa que é um pouco mais complicado do que o normal usar corretamente essa função em uma ação.
A maneira como isso funciona é que a função definirá uma variável booleana, selinux_reboot_required
, como verdadeira
e apresentará falha se for necessário reiniciar. Você pode usar uma estrutura block
/rescue
para se recuperar da falha por meio da geração de uma falha na ação se essa variável não estiver configurada como verdadeira
ou reinicializando o host gerenciado e executando novamente a função se ela for verdadeira
. O bloco em sua ação deve se parecer com isto:
- name: Apply SELinux role block: - include_role: name: rhel-system-roles.selinux rescue: - name: Check for failure for other reasons than required reboot fail: when: not selinux_reboot_required - name: Restart managed host reboot: - name: Reapply SELinux role to complete changes include_role: name: rhel-system-roles.selinux
Configuração da função do SELinux
As variáveis usadas para configurar a função rhel-system-roles.selinux
são documentadas em seu arquivo README.md
. Os exemplos a seguir mostram algumas maneiras de usar essa função.
A variável selinux_state
define o modo no qual o SELinux é executado. Ela pode ser definida para os modos de imposição
, permissivo
ou desativado
. Se não estiver definida, o modo não é alterado.
selinux_state: enforcing
A variável selinux_booleans
recebe uma lista de valores booleanos do SELinux para ajustar. Cada item na lista é um hash/dicionário de variáveis: o name
do booleano, o state
(se deveria ser on
ou off
), e se a configuração deve ser persistent
nas reinicializações.
Este exemplo define httpd_enable_homedirs
como on
persistentemente:
selinux_booleans: - name: 'httpd_enable_homedirs' state: 'on' persistent: 'yes'
A variável selinux_fcontext
recebe uma lista de contextos de arquivos para definir (ou remover)
persistentemente. Ele funciona de forma muito semelhante ao comando selinux fcontext.
O exemplo a seguir garante que a política tenha uma regra para definir o tipo padrão do SELinux para todos os arquivos em /srv/www
para httpd_sys_content_t
.
selinux_fcontexts: - target: '/srv/www(/.*)?' setype: 'httpd_sys_content_t' state: 'present'
A variável selinux_restore_dirs
especifica uma lista de diretórios nos quais executar restorecon:
selinux_restore_dirs: - /srv/www
A variável selinux_ports
recebe uma lista de portas que devem ter um tipo de SELinux específico.
selinux_ports: - ports: '82' setype: 'http_port_t' proto: 'tcp' state: 'present'
Há outras variáveis e opções para essa função. Consulte seu arquivo README.md
para obter mais informações.
Neste exercício, você usará uma das funções do RedHat Enterprise Linux em conjunto com uma tarefa normal para configurar a sincronização de horário e o fuso horário em seus hosts gerenciados.
Resultados
Você deverá ser capaz de:
Instalar as funções do sistema RedHat Enterprise Linux.
Encontrar e usar a documentação das funções do sistema RHEL.
Usar a função rhel-system-roles.timesync em um playbook para configurar a sincronização de horário em hosts remotos.
Visão geral do cenário
Sua organização mantém dois data centers: um nos Estados Unidos (Chicago) e um na Finlândia (Helsinki). Para ajudar na análise de log de servidores de banco de dados em data centers, certifique-se de que o relógio do sistema de cada host esteja sincronizado usando o Network Time Protocol. Para ajudar na análise da atividade de hora do dia nos data centers, certifique-se de que cada servidor de banco de dados tenha uma definição de fuso horário que corresponda ao local do data center do host.
A sincronização de horário tem os seguintes requisitos:
Usar o servidor NTP localizado em classroom.example.com. Ative a opção iburst para acelerar a sincronização de horário inicial.
Use o pacote chrony para a sincronização de horário.
Faça login na workstation como student usando a senha student.
Na workstation, execute o comando lab role-system start. Isso cria o diretório de trabalho, /home/student/role-system, e o preenche com um arquivo de configuração e um inventário de host do Ansible.
[student@workstation ~]$ lab role-system start
Mude para o diretório de trabalho /home/student/role-system.
[student@workstation ~]$ cd ~/role-system
[student@workstation role-system]$
Instale as funções do sistema RedHat EnterpriseLinux no nó de controle, workstation.lab.example.com. Verifique o local da instalação das funções no nó de controle.
Use o comando ansible-galaxy para verificar se nenhuma função está inicialmente disponível para uso no projeto do playbook.
[student@workstation role-system]$ ansible-galaxy list
# /home/student/role-system/roles
# /usr/share/ansible/roles
# /etc/ansible/roles
[student@workstation role-system]$
O comando ansible-galaxy procura três diretórios para funções, conforme indicado pela entrada roles_path no arquivo ansible.cfg:
./roles
/usr/share/ansible/roles
/etc/ansible/roles
A saída acima indica que não há funções em nenhum desses diretórios.
Instale o pacote rhel-system-roles.
[student@workstation role-system]$ sudo yum install rhel-system-roles
Digite y quando solicitado para instalar o pacote.
Use o comando ansible-galaxy para verificar se as funções do sistema estão disponíveis agora.
[student@workstation role-system]$ ansible-galaxy list
# /home/student/role-system/roles
# /usr/share/ansible/roles
- linux-system-roles.kdump, (unknown version)
- linux-system-roles.network, (unknown version)
- linux-system-roles.postfix, (unknown version)
- linux-system-roles.selinux, (unknown version)
- linux-system-roles.timesync, (unknown version)
- rhel-system-roles.kdump, (unknown version)
- rhel-system-roles.network, (unknown version)
- rhel-system-roles.postfix, (unknown version)
- rhel-system-roles.selinux, (unknown version)
- rhel-system-roles.timesync, (unknown version)
# /etc/ansible/roles
As funções estão localizadas no diretório /usr/share/ansible/roles. Qualquer função que comece com linux-system-roles é, na verdade, um symlink para a função rhel-system-roles correspondente.
Crie um playbook, configure_time.yml, com uma ação que tenha como destino o grupo de hosts database_servers. Inclua a função rhel-system-roles.timesync na seção roles da ação.
---
- name: Time Synchronization
hosts: database_servers
roles:
- rhel-system-roles.timesync
A documentação de funções contém uma descrição de cada variável de função, incluindo o valor padrão da variável. Determine as variáveis de função a serem substituídas para atender aos requisitos de sincronização de horário.
Coloque os valores das variáveis de função em um arquivo chamado timesync.yml. Como esses valores de variáveis se aplicam a todos os hosts no inventário, coloque o arquivo timesync.yml no subdiretório group_vars/all.
Revise a seção Variáveis de função do arquivo README.md para a função rhel-system-roles.timesync.
[student@workstation role-system]$ cat \
> /usr/share/doc/rhel-system-roles/timesync/README.md
...output omitted...
Role Variables
--------------
...output omitted...
# List of NTP servers
timesync_ntp_servers:
- hostname: foo.example.com # Hostname or address of the server
minpoll: 4 # Minimum polling interval (default 6)
maxpoll: 8 # Maximum polling interval (default 10)
iburst: yes # Flag enabling fast initial synchronization
# (default no)
pool: no # Flag indicating that each resolved address
# of the hostname is a separate NTP server
# (default no)
...output omitted...
# Name of the package which should be installed and configured for NTP.
# Possible values are "chrony" and "ntp". If not defined, the currently active
# or enabled service will be configured. If no service is active or enabled, a
# package specific to the system and its version will be selected.
timesync_ntp_provider: chrony
...output omitted...
Crie o subdiretório group_vars/all.
[student@workstation role-system]$ mkdir -pv group_vars/all
mkdir: created directory 'group_vars'
mkdir: created directory 'group_vars/all'
Crie um novo arquivo group_vars/all/timesync.yml usando um editor de texto. Adicione definições de variáveis para satisfazer os requisitos de sincronização de horário. O arquivo agora contém:
---
#rhel-system-roles.timesync variables for all hosts
timesync_ntp_provider: chrony
timesync_ntp_servers:
- hostname: classroom.example.com
iburst: yes
Adicione uma tarefa a configure_time.yml para definir o fuso horário de cada host. Certifique-se de que a tarefa usa o módulo timezone e é executada após a função rhel-system-roles.timesync.
Como os hosts não pertencem ao mesmo fuso horário, use uma variável (host_timezone) para o nome do fuso horário.
Revise a seção Exemplos da documentação do módulo timezone.
[student@workstation role-system]$ ansible-doc timezone | grep -A 4 "EXAMPLES"
EXAMPLES:
- name: set timezone to Asia/Tokyo
timezone:
name: Asia/Tokyo
Adicione uma tarefa à seção post_tasks da ação no playbook configure_time.yml. Configure a tarefa com base no exemplo da documentação, mas use a variável host_timezone para o nome do fuso horário.
A documentação em ansible-doc timezone recomenda a reinicialização do serviço Cron se o módulo alterar o fuso horário, a fim de garantir que as tarefas do Cron sejam executadas nos horários certos. Adicione uma palavra-chave notify à tarefa, com o valor restart crond associado. A seção post_tasks da ação deve ser:
post_tasks:
- name: Set timezone
timezone:
name: "{{ host_timezone }}"
notify: restart crond
Adicione o manipulador restart crond à ação Time Synchronization. O playbook completo agora contém:
---
- name: Time Synchronization
hosts: database_servers
roles:
- rhel-system-roles.timesync
post_tasks:
- name: Set timezone
timezone:
name: "{{ host_timezone }}"
notify: restart crond
handlers:
- name: restart crond
service:
name: crond
state: restarted
Para cada data center, crie um arquivo chamado timezone.yml que contenha um valor apropriado para a variável host_timezone. Use o comando timedatectl list-timezones para encontrar a string de fuso horário válida para cada data center.
Crie os subdiretórios group_vars para os grupos de hosts na_datacenter e europe_datacenter.
[student@workstation role-system]$ mkdir -pv \
> group_vars/{na_datacenter,europe_datacenter}
mkdir: created directory 'group_vars/na_datacenter'
mkdir: created directory 'group_vars/europe_datacenter'
Use o comando timedatectl list-timezones para determinar o fuso horário para os data centers dos EUA e da Europa:
[student@workstation role-system]$ timedatectl list-timezones | grep Chicago
America/Chicago
[student@workstation role-system]$ timedatectl list-timezones | grep Helsinki
Europe/Helsinki
Crie timezone.yml para ambos os data centers:
[student@workstation role-system]$ echo "host_timezone: America/Chicago" > \
> group_vars/na_datacenter/timezone.yml
[student@workstation role-system]$ echo "host_timezone: Europe/Helsinki" > \
> group_vars/europe_datacenter/timezone.yml
Execute o playbook.
[student@workstation role-system]$ ansible-playbook configure_time.yml
PLAY [Time Synchronization] **************************************************
TASK [Gathering Facts] *******************************************************
ok: [serverb.lab.example.com]
ok: [servera.lab.example.com]
TASK [rhel-system-roles.timesync : Check if only NTP is needed] **************
ok: [servera.lab.example.com]
ok: [serverb.lab.example.com]
...output omitted...
TASK [rhel-system-roles.timesync : Enable timemaster] ************************
skipping: [servera.lab.example.com]
skipping: [serverb.lab.example.com]
RUNNING HANDLER [rhel-system-roles.timesync : restart chronyd] ***************
changed: [servera.lab.example.com]
changed: [serverb.lab.example.com]
TASK [Set timezone] **********************************************************
changed: [serverb.lab.example.com]
changed: [servera.lab.example.com]
RUNNING HANDLER [restart crond] **********************************************
changed: [serverb.lab.example.com]
changed: [servera.lab.example.com]
PLAY RECAP *******************************************************************
servera.lab.example.com : ok=17 changed=6 unreachable=0 failed=0
skipped=20 rescued=0 ignored=6
serverb.lab.example.com : ok=17 changed=6 unreachable=0 failed=0
skipped=20 rescued=0 ignored=6
Verifique as configurações de fuso horário de cada servidor. Use um comando ad hoc do Ansible para ver a saída do comando date em todos os servidores de bancos de dados.
Os fusos horários reais listados variarão dependendo da época do ano e se o horário de verão estiver ativo.
[student@workstation role-system]$ ansible database_servers -m shell -a date
serverb.lab.example.com | CHANGED | rc=0 >>
Wed Apr 3 06:27:01 EEST 2019
servera.lab.example.com | CHANGED | rc=0 >>
Tue Apr 2 22:27:01 CDT 2019
Cada servidor tem uma configuração de fuso horário com base em sua localização geográfica.
Encerramento
Execute o comando lab role-system finish para limpar o host gerenciado.
[student@workstation ~]$ lab role-system finish
Isso conclui o exercício orientado
Objetivos
Depois de concluir esta seção, você deverá ser capaz de criar uma função no diretório de projeto de um playbook e executá-la como parte de uma das ações do playbook. O processo de criação de função
A criação de funções no Ansible não requer ferramentas especiais de desenvolvimento. A criação e o uso de uma função é um processo em três etapas:
Crie a estrutura de diretórios de funções.
Defina o conteúdo da função.
Use a função em um playbook.
Criação da estrutura de diretório de função
Por padrão, o Ansible procura funções em um subdiretório chamado roles no diretório que contém seu playbook do Ansible. Isso permite que você armazene funções com o playbook e outros arquivos de suporte.
Se o Ansible não puder encontrar a função lá, ele busca nos diretórios especificados pelos roles_path de configuração do Ansible, em ordem. Essa variável contém uma lista separada por vírgulas de diretórios para pesquisa. O valor padrão dessa variável é:
~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
Isso permite que você instale funções em seu sistema que sejam compartilhadas por vários projetos. Por exemplo, você pode ter suas próprias funções instaladas em seu diretório pessoal no subdiretório ~/.ansible/roles e o sistema pode ter funções instaladas para todos os usuários no diretório /usr/share/ansible/roles.
Cada função tem seu próprio diretório com uma estrutura de diretórios padronizada. Por exemplo, a estrutura de diretório a seguir contém os arquivos que definem a função motd.
[user@host ~]$ tree roles/ roles/ └── motd ├── defaults │ └── main.yml ├── files ├── handlers ├── meta │ └── main.yml ├── README.md ├── tasks │ └── main.yml └── templates └── motd.j2
O README.md fornece uma descrição básica legível da função, documentação e exemplos de como usá-la, e todos os possíveis requisitos não relacionados ao Ansible que ela precisa para funcionar. O subdiretório meta contém um arquivo main.yml que especifica informações sobre o autor, licença, compatibilidade e dependências do módulo. O subdiretório files contém arquivos com conteúdo fixo; já o subdiretório templates contém modelos que poderão ser implantados pela função quando esta for usada. Os outros subdiretórios podem conter arquivos main.yml que definem valores de variáveis, manipuladores, tarefas, metadados de função ou variáveis padrão, dependendo do subdiretório em que estiverem.
Se um subdiretório existir mas estiver vazio, como handlers neste exemplo, ele é ignorado. Se uma função não usar um recurso, o subdiretório pode ser omitido por completo. Por exemplo, o subdiretório vars foi omitido deste exemplo.
Criação de um esqueleto de função
Você pode criar todos os subdiretórios e arquivos necessários para uma nova função usando os comandos padrão do Linux. Como alternativa, há utilitários de linha de comando para automatizar o processo de criação de novas funções.
A ferramenta de linha de comando ansible-galaxy (abordada com mais detalhes posteriormente neste curso) é usada para gerenciar funções do Ansible, incluindo a criação de novas funções. Você pode executar ansible-galaxy init para criar a estrutura de diretórios para uma nova função. Especifique o nome da função como um argumento para o comando, que cria um subdiretório para a nova função no diretório de trabalho atual.
[user@host playbook-project]$ cd roles [user@host roles]$ ansible-galaxy init my_new_role
Definição do conteúdo da função
Depois de criar a estrutura de diretório, você deve escrever o conteúdo da função. Um bom lugar para começar é o arquivo de tarefas ROLENAME/tasks/main.yml, a lista principal de tarefas executadas pela função.
O arquivo tasks/main.yml a seguir gerencia o arquivo /etc/motd em hosts gerenciados. Ele usa o módulo template para implantar o nome do modelo chamado motd.j2 para o host gerenciado. Como o módulo template é configurado em uma tarefa de função, em vez de uma tarefa de playbook, o modelo motd.j2 é recuperado do subdiretório templates da função.
O comando a seguir exibe os conteúdos do modelo motd.j2 da função motd. Ele referencia fatos do Ansible e uma variável system_owner.
[user@host ~]$ cat roles/motd/templates/motd.j2 This is the system {{ ansible_facts['hostname'] }}.
Today's date is: {{ ansible_facts['date_time']['date'] }}.
Only use this system with permission. You can ask {{ system_owner }} for access.
A função define um valor padrão para a variável system_owner. O arquivo defaults/main.yml na estrutura do diretório da função é onde o valor está definido.
O arquivo defaults/main.yml a seguir define a variável system_owner para user@host.example.com. Esse será o endereço de e-mail escrito no arquivo /etc/motd dos hosts gerenciados ao qual essa função é aplicada.
system_owner: user@host.example.com
Práticas recomendadas para o desenvolvimento de conteúdo de função
As funções permitem que os playbooks sejam escritos de forma modular. Para maximizar a eficácia das funções recentemente desenvolvidas, considere implementar as seguintes práticas recomendadas no desenvolvimento da função:
Mantenha cada função em seu próprio repositório de controle da versão. O Ansible funciona bem com repositórios baseados em git.
Informações confidenciais, como senhas ou chaves SSH, não devem ser armazenadas no repositório de funções. Valores confidenciais devem ser parametrizados como variáveis com valores padrão que não são confidenciais. Playbooks que usam a função são responsáveis por definir variáveis confidenciais através de arquivos de variáveis do Ansible Vault, variáveis de ambiente ou outras opções ansible-playbook.
Use ansible-galaxy init para iniciar sua função e, em seguida, remova todos os diretórios e arquivos desnecessários.
Crie e mantenha os arquivos README.md e meta/main.yml para documentar para que serve sua função, quem a escreveu e como usá-la.
Mantenha sua função focada em um propósito ou função específicos. Em vez de fazer com que uma função sirva para muitas coisas, você pode escrever mais de uma função.
Reutilize e realize a refatoração das funções com frequência. Resista à criação de novas funções para configurações de borda. Se uma função existente realizar a maioria das configurações necessárias, refatore a função existente para que integre o novo cenário de configuração. Use técnicas de integração e teste de regressão para garantir que a função forneça a nova funcionalidade necessária e também não cause problemas para os playbooks existentes.
Definição das dependências da função
As dependências da função permitem que uma função inclua outras como dependências. Por exemplo, uma função que define um servidor de documentação pode depender de outra função que instala e configura um servidor web. As dependências são definidas no arquivo meta/main.yml na hierarquia de diretórios da função.
Veja a seguir um arquivo meta/main.yml de amostra.
dependencies:
Por padrão, as funções são adicionadas apenas uma vez como uma dependência para um playbook. Se outra função listar a mesma dependência, ela não será executada novamente. Esse comportamento pode ser substituído pela definição da variável allow_duplicates como yes no arquivo meta/main.yml.
Limite as dependências da sua função em outras funções. As dependências dificultam a manutenção da sua função, especialmente se ela tiver muitas dependências complexas. Uso da função em um playbook
Para acessar uma função, referencie-a na seção roles: de uma ação. O playbook a seguir refere-se à função motd. Como nenhuma variável é especificada, a função é aplicada com seus valores de variáveis padrão.
Quando o playbook é executado, as tarefas realizadas por causa de uma função podem ser identificadas pelo prefixo do nome da função. O exemplo de saída a seguir ilustra isso com o prefixo motd : no nome da tarefa:
[user@host ~]$ ansible-playbook -i inventory use-motd-role.yml
PLAY [use motd role playbook] **
TASK [setup] *** ok: [remote.example.com]
TASK [motd : deliver motd file] **** changed: [remote.example.com]
PLAY RECAP ***** remote.example.com : ok=2 changed=1 unreachable=0 failed=0
O cenário acima pressupõe que a função motd está localizada no diretório roles. Posteriormente no curso, você verá como usar uma função que está localizada remotamente em um repositório de controle de versão.
Alteração do comportamento de uma função com variáveis
Uma função bem escrita usa variáveis padrão para alterar o comportamento da função a fim de corresponder a um cenário de configuração relacionado. Isso ajuda a tornar a função mais genérica e reutilizável em vários contextos.
O valor de qualquer variável definida no diretório defaults de uma função será substituído se essa mesma variável for definida:
em um arquivo de inventário, como uma variável de host ou uma variável de grupo.
em um arquivo YAML nos diretórios group_vars ou host_vars de um projeto de playbook
como uma variável aninhada na palavra-chave vars de uma ação
como uma variável ao incluir a função na palavra-chave roles de uma ação
O exemplo a seguir mostra como usar a função motd com um valor diferente para a variável da função system_owner. O valor especificado, someone@host.example.com, substituirá a referência da variável quando a função for aplicada a um host gerenciado.
Quando definido dessa forma, a variável system_owner substitui o valor da variável padrão de mesmo nome. Nenhuma definição de variável aninhada na palavra-chave vars substituirá o valor da mesma variável, se definido no diretório vars de uma função.
O exemplo a seguir também mostra como usar a função motd com um valor diferente para a variável da função system_owner. O valor especificado, someone@host.example.com, substituirá a referência da variável, independentemente de estar definido no diretório vars ou defaults da função.
A precedência da variável pode ser confusa ao trabalhar com variáveis de função em uma ação.
Quase qualquer outra variável substituirá as variáveis padrão de uma função: variáveis de inventário, ação vars, role parameters em linha, e assim por diante.
Menos variáveis podem substituir variáveis definidas no diretório vars de uma função. Fatos, variáveis carregadas com include_vars, variáveis registradas e parâmetros de função são algumas variáveis que podem fazer isso. As variáveis de inventário e vars de ação não podem. Isso é importante porque ajuda a evitar que sua ação altere acidentalmente o funcionamento interno da função.
No entanto, as variáveis declaradas em linha como parâmetros de função, como o último dos exemplos anteriores, tem precedência muito alta. Elas podem substituir variáveis definidas no diretório vars de uma função. Se um parâmetro de função tiver o mesmo nome que uma variável definida em vars de ação, vars de uma função ou uma variável de inventário ou de playbook, o parâmetro de função substituirá a outra variável.
Using Roles — Ansible Documentation
Using Variables — Ansible Documentation
Neste exercício, você criará uma função do Ansible que usa variáveis, arquivos, templates, tarefas e manipuladores para implantar um serviço de rede.
Resultados
Você deverá ser capaz de criar uma função que usa variáveis e parâmetros.
A função myvhost instala e configura o serviço Apache em um host. É fornecido um template chamado vhost.conf.j2 que será usado para gerar /etc/httpd/conf.d/vhost.conf.
Faça login na workstation como student usando a senha student.
Na workstation, execute o comando lab role-create start. Isso cria o diretório de trabalho, /home/student/role-create, e o preenche com um arquivo de configuração e um inventário de host do Ansible.
[student@workstation ~]$ lab role-create start
Mude para o diretório de trabalho /home/student/role-create.
[student@workstation ~]$ cd ~/role-create
[student@workstation role-create]$
Crie a estrutura de diretórios para uma função chamada myvhost. A função inclui arquivos, modelos, tarefas e manipuladores fixos.
[student@workstation role-create]$ mkdir -v roles; cd roles
mkdir: created directory 'roles'
[student@workstation roles]$ ansible-galaxy init myvhost
- myvhost was created successfully
[student@workstation roles]$ rm -rvf myvhost/{defaults,vars,tests}
removed 'myvhost/defaults/main.yml'
removed directory: 'myvhost/defaults'
removed 'myvhost/vars/main.yml'
removed directory: 'myvhost/vars'
removed 'myvhost/tests/inventory'
removed 'myvhost/tests/test.yml'
removed directory: 'myvhost/tests'
[student@workstation roles]$ cd ..
[student@workstation role-create]$
Edite o arquivo main.yml no subdiretório tasks da função. A função deverá realizar as seguintes tarefas:
O pacote httpd é instalado
O serviço httpd foi iniciado e está habilitado.
O arquivo de configuração do servidor web é instalado, usando um template fornecido pela função
Edite o arquivo roles/myvhost/tasks/main.yml. Inclua código para usar o módulo yum a fim de instalar o pacote httpd. O conteúdo do arquivo deve parecer-se com o seguinte:
---
# tasks file for myvhost
- name: Ensure httpd is installed
yum:
name: httpd
state: latest
Inclua um código adicional ao arquivo roles/myvhost/tasks/main.yml para usar o módulo service a fim de iniciar e habilitar o serviço httpd.
- name: Ensure httpd is started and enabled
service:
name: httpd
state: started
enabled: true
Adicione outra estrofe para usar o módulo template a fim criar /etc/httpd/conf.d/vhost.conf no host gerenciado. Ela deverá chamar um manipulador para reiniciar o daemon httpd quando o arquivo estiver atualizado.
- name: vhost file is installed
template:
src: vhost.conf.j2
dest: /etc/httpd/conf.d/vhost.conf
owner: root
group: root
mode: 0644
notify:
- restart httpd
Salve suas alterações e saia do arquivo roles/myvhost/tasks/main.yml.
Crie o manipulador para reiniciar o serviço httpd. Edite o arquivo roles/myvhost/handlers/main.yml e inclua o código a para usar o módulo service. Salve e saia. O conteúdo do arquivo deve ter a seguinte aparência:
---
# handlers file for myvhost
- name: restart httpd
service:
name: httpd
state: restarted
Mova o template vhost.conf.j2 do diretório do projeto para o subdiretório templates da função.
[student@workstation role-create]$ mv -v vhost.conf.j2 roles/myvhost/templates/
renamed 'vhost.conf.j2' -> 'roles/myvhost/templates/vhost.conf.j2'
Crie o conteúdo HTML a ser fornecido pelo servidor web.
Crie o diretório files/html/ para armazenar o conteúdo.
[student@workstation role-create]$ mkdir -pv files/html
mkdir: created directory 'files/html'
Crie um arquivo index.html abaixo desse diretório com o conteúdo: simple index.
[student@workstation role-create]$ echo \
> 'simple index' > files/html/index.html
Teste a função myvhost para verificar se ela funciona corretamente.
Escreva um playbook que use a função use-vhost-role.yml. Inclua uma tarefa para copiar o conteúdo HTML de files/html/ . Use o módulo copy e inclua uma barra à direita após o nome do diretório de origem. Ele deverá ter o seguinte conteúdo:
---
- name: Use myvhost role playbook
hosts: webservers
pre_tasks:
- name: pre_tasks message
debug:
msg: 'Ensure web server configuration.'
roles:
- myvhost
post_tasks:
- name: HTML content is installed
copy:
src: files/html/
dest: "/var/www/vhosts/{{ ansible_hostname }}"
- name: post_tasks message
debug:
msg: 'Web server is configured.'
Antes de executar o playbook, verifique se a sintaxe está correta executando ansible-playbook com --syntax-check. Se ela relatar algum erro, corrija-o antes de ir para a próxima etapa. Você verá uma saída semelhante à seguinte:
[student@workstation role-create]$ ansible-playbook use-vhost-role.yml \
> --syntax-check
playbook: use-vhost-role.yml
Execute o playbook. Revise a saída para confirmar que o Ansible realizou as ações no servidor web, servera.
[student@workstation role-create]$ ansible-playbook use-vhost-role.yml
PLAY [Use myvhost role playbook] *********************************************
TASK [Gathering Facts] *******************************************************
ok: [servera.lab.example.com]
TASK [pre_tasks message] *****************************************************
ok: [servera.lab.example.com] => {
"msg": "Ensure web server configuration."
}
TASK [myvhost : Ensure httpd is installed] ***********************************
changed: [servera.lab.example.com]
TASK [myvhost : Ensure httpd is started and enabled] *************************
changed: [servera.lab.example.com]
TASK [myvhost : vhost file is installed] *************************************
changed: [servera.lab.example.com]
RUNNING HANDLER [myvhost : restart httpd] ************************************
changed: [servera.lab.example.com]
TASK [HTML content is installed] ***********************************
changed: [servera.lab.example.com]
TASK [post_tasks message] ****************************************************
ok: [servera.lab.example.com] => {
"msg": "Web server is configured."
}
PLAY RECAP *******************************************************************
servera.lab.example.com : ok=8 changed=5 unreachable=0 failed=0
Execute comandos ad hoc para confirmar que a função teve o desempenho esperado. O pacote httpd deve estar instalado, e o serviço httpd deve estar em execução.
[student@workstation role-create]$ ansible webservers -a \
> 'systemctl is-active httpd'
servera.lab.example.com | CHANGED | rc=0 >>
active
[student@workstation role-create]$ ansible webservers -a \
> 'systemctl is-enabled httpd'
servera.lab.example.com | CHANGED | rc=0 >>
enabled
A configuração do Apache deve estar instalada com as variáveis do modelo expandidas.
[student@workstation role-create]$ ansible webservers -a \
> 'cat /etc/httpd/conf.d/vhost.conf'
servera.lab.example.com | CHANGED | rc=0 >>
# Ansible managed:
<VirtualHost *:80>
ServerAdmin webmaster@servera.lab.example.com
ServerName servera.lab.example.com
ErrorLog logs/servera-error.log
CustomLog logs/servera-common.log common
DocumentRoot /var/www/vhosts/servera/
<Directory /var/www/vhosts/servera/>
Options +Indexes +FollowSymlinks +Includes
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
O conteúdo em HTML deve ser encontrado em um diretório chamado /var/www/vhosts/servera. O arquivo index.html deve conter a string simple index.
[student@workstation role-create]$ ansible webservers -a \
> 'cat /var/www/vhosts/servera/index.html'
servera.lab.example.com | CHANGED | rc=0 >>
simple index
Use o módulo uri em um comando ad hoc para verificar se o conteúdo da web está disponível localmente. Defina o parâmetro return_content como true para que o conteúdo da resposta do servidor seja adicionado à saída. O conteúdo do servidor deve ser a string "simple index\n".
[student@workstation role-create]$ ansible webservers -m uri \
> -a 'url=http://localhost return_content=true'
servera.lab.example.com | SUCCESS => {
"accept_ranges": "bytes",
"changed": false,
"connection": "close",
"content": "simple index\n",
...output omitted...
"status": 200,
"url": "http://localhost"
}
Confirme se o conteúdo do servidor web está disponível para clientes remotos.
[student@workstation role-create]$ curl http://servera.lab.example.com
simple index
Encerramento
Execute o comando lab role-create finish para limpar o host gerenciado.
[student@workstation ~]$ lab role-create finish
Isso conclui o exercício orientado.
Depois de concluir esta seção, você deverá ser capaz de selecionar e recuperar funções do Ansible Galaxy ou de outras fontes, como um repositório Git, e usá-las em playbooks.
O Ansible Galaxy é uma biblioteca pública de conteúdo do Ansible escrito por diversos administradores e usuários do Ansible. Contém milhares de funções do Ansible e um banco de dados pesquisável que ajuda os usuários do Ansible a identificar funções que podem ajudá-los a realizar uma tarefa administrativa. O Ansible Galaxy inclui links para documentos e vídeos de novos usuários e desenvolvedores de funções do Ansible.
Além disso, o comando ansible-galaxy que você usa para obter e gerenciar funções do Ansible Galaxy também pode ser usado para obter e gerenciar funções que seus projetos precisam a partir dos seus próprios repositórios Git.
Ajuda com o Ansible Galaxy
A guia Documentation na página inicial do site do Ansible Galaxy leva a uma página que descreve como se usa o Ansible Galaxy. Há conteúdo sobre como baixar as funções do Ansible Galaxy e como usá-las. As instruções de como desenvolver funções e fazer upload delas para o Ansible Galaxy também estão nessa página.
Navegação de funções no Ansible Galaxy
A guia Search
na lateral esquerda do site do Ansible Galaxy dá aos usuários acesso às
informações sobre as funções publicadas no Ansible Galaxy. Você
pode pesquisar por uma função do Ansible pelo nome, usando tags ou por
outros atributos. Os resultados são apresentados em ordem
decrescente de Melhor correspondência
, que é uma pontuação calculada com base na qualidade da função, na popularidade da função e nos critérios de pesquisa.
Content Scoring na documentação tem mais informações sobre como funcionam as pontuações das funções de acordo com o Ansible Galaxy.
O Ansible Galaxy reporta o número de vezes que cada função foi baixada do Ansible Galaxy. Além disso, o Ansible Galaxy também relata o número de observadores, forks e estrelas que o repositório GitHub da função tem. Os usuários podem usar essas informações para ajudar a determinar como o desenvolvimento ativo é para uma função e o quão popular ela é na comunidade.
A figura a seguir mostra os resultados de pesquisa que o Ansible Galaxy exibe após uma pesquisa pela palavra-chave redis
foi realizada. Observe que o primeiro resultado tem uma Melhor correspondência
de 0.9009
.
O menu suspenso Filters
à direita da caixa de pesquisa permite que sejam realizadas pesquisas
em palavras-chave, IDs de autores, plataforma e tags. Os possíveis
valores da plataforma incluem EL
para RedHat EnterpriseLinux (e distribuições estreitamente relacionadas, como o CentOS) e Fedora
, entre outros.
As tags são strings arbitrárias de uma única palavra definidas pelo
autor da função que descrevem e categorizam a função. Os usuários
podem usar tags para encontrar funções relevantes. Os possíveis
valores de tag incluem system
, development
, web
, monitoring
e outros. Uma função pode ter até 20 tags no Ansible Galaxy.
Na interface de pesquisa do Ansible Galaxy, as pesquisas por palavra-chave combinam palavras ou frases no arquivo README
,
no nome do conteúdo ou na descrição do conteúdo. As pesquisas por
tags, por outro lado, correspondem especificamente aos valores da tag
definidos pelo autor para a função.
A ferramenta de linha de comando ansible-galaxy pode ser usada para pesquisar, instalar, listar, remover, inicializar ou exibir informações sobre funções.
Busca por funções da linha de comando
O subcomando ansible-galaxy search
pesquisa funções no Ansible Galaxy. Se você especificar uma
string como um argumento, ela será usada para pesquisar funções por
palavra-chave no Ansible Galaxy. Você pode usar as opções --author
, --platforms
e --galaxy-tags
para refinar os resultados de pesquisa. Você também pode usar
essas opções como chave de pesquisa principal. Por exemplo, o
comando ansible-galaxy search --author geerlingguy exibirá todas as funções enviadas pelo usuário geerlingguy
.
Os resultados são exibidos em ordem alfabética, não por pontuação decrescente de Melhor correspondência
. O exemplo a seguir exibe os nomes das funções que incluem redis
e estão disponíveis para a plataforma Enterprise Linux (EL
).
[user@host ~]$
ansible-galaxy search 'redis' --platforms EL
Found 124 roles matching your search: Name Description ---- ----------- 1it.sudo Ansible role for managing sudoers AerisCloud.librato Install and configure the Librato Agent AerisCloud.redis Installs redis on a server AlbanAndrieu.java Manage Java installation andrewrothstein.redis builds Redis from src and installs ...output omitted... geerlingguy.php-redis PhpRedis support for Linuxgeerlingguy.redis Redis for Linux
gikoluo.filebeat Filebeat for Linux. ...output omitted...
O subcomando ansible-galaxy info
exibe informações mais detalhadas sobre uma função. O Ansible
Galaxy obtém essa informação a partir de vários lugares, incluindo a
função do arquivo meta/main.yml
e seu repositório GitHub. O comando a seguir exibe informações sobre a função geerlingguy.redis
, disponível no Ansible Galaxy.
[user@host ~]$
ansible-galaxy info geerlingguy.redis
Role: geerlingguy.redis description: Redis for Linux active: True ...output omitted... download_count: 146209 forks_count: 82 github_branch: master github_repo: ansible-role-redis github_user: geerlingguy ...output omitted... license: license (BSD, MIT) min_ansible_version: 2.4 modified: 2018-11-19T14:53:29.722718Z open_issues_count: 11 path: [u'/etc/ansible/roles', u'/usr/share/ansible/roles'] role_type: ANS stargazers_count: 98 ...output omitted...
Instalação de funções do Ansible Galaxy
O subcomando ansible-galaxy install faz download de uma função do Ansible Galaxy e faz sua instalação localmente no nó de controle.
Por padrão, as funções são instaladas no primeiro diretório que é gravável no roles_path
do usuário. Baseado no padrão roles_path
definido para o Ansible, normalmente a função será instalada no diretório ~/.ansible/roles
. O padrão roles_path
pode ser substituído por seu arquivo de configuração atual do Ansible ou pela variável de ambiente ANSIBLE_ROLES_PATH
, que afeta o comportamento de ansible-galaxy.
Você também pode especificar um diretório específico no qual instalar a função usando a opção -p
. DIRECTORY
No exemplo a seguir, ansible-galaxy instala a função geerlingguy.redis
no diretório roles
de um projeto de playbook. O diretório de trabalho atual do comando é /opt/project
.
[user@host project]$
ansible-galaxy install geerlingguy.redis -p roles/
- downloading role 'redis', owned by geerlingguy - downloading role from https://github.com/geerlingguy/...output omitted... - extracting geerlingguy.redis to /opt/project/roles/geerlingguy.redis - geerlingguy.redis (1.6.0) was installed successfully[user@host project]$
ls roles/
geerlingguy.redis
Instalação de funções usando um arquivo de requisitos
Você também pode usar ansible-galaxy
para instalar uma lista de funções com base em definições em um arquivo
de texto. Por exemplo, se você tiver um playbook que precisa ter
funções específicas instaladas, poderá criar um arquivoroles/requirements.yml
no diretório do projeto que especifica quais funções são necessárias.
Esse arquivo funciona como um manifesto de dependência para o
projeto do playbook, que permite que os playbooks sejam desenvolvidos e
testados separadamente de qualquer função de suporte.
Por exemplo, um simples requirements.yml
para instalar geerlingguy.redis
pode ser assim:
- src: geerlingguy.redis version: "1.5.0"
O atributo src
especifica a origem da função, nesse caso, a função geerlingguy.redis
do Ansible Galaxy. O atributo version
é opcional e especifica a versão da função a ser instalada, nesse caso, a 1.5.0
.
Você deve especificar a versão da função em seu arquivo requirements.yml
, especialmente para playbooks em produção.
Se você não especificar uma versão, receberá a versão mais recente da função. Se o autor do upstream fizer alterações na função que são sejam incompatíveis com seu playbook, isso pode causar uma falha de automação ou outros problemas.
Para instalar as funções usando um arquivo de função, use a opção -r
: REQUIREMENTS-FILE
[user@host project]$
ansible-galaxy install -r roles/requirements.yml \
>
-p roles
- downloading role 'redis', owned by geerlingguy - downloading role from https://github.com/geerlingguy/ansible-role-redis/archive/1.6.0.tar.gz - extracting geerlingguy.redis to /opt/project/roles/geerlingguy.redis - geerlingguy.redis (1.6.0) was installed successfully
Você pode usar ansible-galaxy para instalar funções que não estão no Ansible Galaxy. Você pode hospedar suas próprias funções proprietárias ou internas em um repositório Git privado ou em um servidor web. O exemplo a seguir mostra como configurar um arquivo de requisitos usando várias fontes remotas.
[user@host project]$
cat roles/requirements.yml
# from Ansible Galaxy, using the latest version - src: geerlingguy.redis # from Ansible Galaxy, overriding the name and using a specific version - src: geerlingguy.redis version: "1.5.0" name: redis_prod # from any Git-based repository, using HTTPS - src: https://gitlab.com/guardianproject-ops/ansible-nginx-acme.git scm: git version: 56e00a54 name: nginx-acme # from any Git-based repository, using SSH - src: git@gitlab.com:guardianproject-ops/ansible-nginx-acme.git scm: git version: master name: nginx-acme-ssh # from a role tar ball, given a URL; # supports 'http', 'https', or 'file' protocols - src: file:///opt/local/roles/myrole.tar name: myrole
A palavra-chave src
especifica o nome da função do Ansible Galaxy. Se a função não estiver hospedada no Ansible Galaxy, a palavra-chave src
indica o URL da função.
Se a função estiver hospedada em um repositório de controle de fonte, o atributo scm
é obrigatório. O comando ansible-galaxy
é capaz de baixar e instalar funções de repositórios de software
baseados em Git ou Mercurial. Um repositório baseado em Git exige um
valor scm
de git
, enquanto uma função hospedada em um repositório Mercurial exige um valor hg
. Se a função estiver hospedada no Ansible Galaxy ou como um arquivo TAR em um servidor web, a palavra-chave scm
é omitida.
A palavra-chave name
é usada para substituir o nome local da função. A palavra-chave version
é usada para especificar a versão de uma função. A palavra-chave version
pode ser qualquer valor que corresponda a um branch, tag ou commit hash do repositório de software da função.
Para instalar as funções associadas a um projeto de playbook, execute o comando ansible-galaxy install:
[user@host project]$
ansible-galaxy install -r roles/requirements.yml \
- downloading role 'redis', owned by geerlingguy - downloading role from https://github.com/geerlingguy/ansible-role-redis/archive/1.6.0.tar.gz - extracting geerlingguy.redis to /opt/project/roles/geerlingguy.redis - geerlingguy.redis (1.6.0) was installed successfully - downloading role 'redis', owned by geerlingguy - downloading role from https://github.com/geerlingguy/ansible-role-redis/archive/1.5.0.tar.gz - extracting redis_prod to /opt/project/roles/redis_prod - redis_prod (1.5.0) was installed successfully - extracting nginx-acme to /opt/project/roles/nginx-acme - nginx-acme (56e00a54) was installed successfully - extracting nginx-acme-ssh to /opt/project/roles/nginx-acme-ssh - nginx-acme-ssh (master) was installed successfully - downloading role from file:///opt/local/roles/myrole.tar - extracting myrole to /opt/project/roles/myrole - myrole was installed successfully-p roles
>
Gerenciamento de funções baixadas
O comando ansible-galaxy também pode gerenciar funções locais, como as funções encontradas no diretório roles
de um projeto de playbook. O subcomando ansible-galaxy list lista as funções que são encontradas localmente.
[user@host project]$
ansible-galaxy list
- geerlingguy.redis, 1.6.0 - myrole, (unknown version) - nginx-acme, 56e00a54 - nginx-acme-ssh, master - redis_prod, 1.5.0
Uma função pode ser removida localmente com o subcomando ansible-galaxy remove.
[user@host ~]$
ansible-galaxy remove nginx-acme-ssh
- successfully removed nginx-acme-ssh[user@host ~]$
ansible-galaxy list
- geerlingguy.redis, 1.6.0 - myrole, (unknown version) - nginx-acme, 56e00a54 - redis_prod, 1.5.0
Use as funções transferidas e instaladas a em playbooks como qualquer outra função. Elas são referenciadas na seção roles
usando seu nome de função transferido. Se uma função não estiver no diretório roles
do projeto, roles_path
será verificado para ver se a função está instalada em um desses
diretórios, sendo usada a primeira correspondência. O playbook use-role.yml
a seguir faz referência às funções redis_prod
e geerlingguy.redis
.
[user@host project]$
cat use-role.yml
--- - name: use redis_prod for Prod machines hosts: redis_prod_servers remote_user: devops become: true roles: - redis_prod - name: use geerlingguy.redis for Dev machines hosts: redis_dev_servers remote_user: devops become: true roles: - geerlingguy.redis
Este playbook faz com que diferentes versões da função geerlingguy.redis
sejam aplicadas aos servidores de produção e desenvolvimento. Dessa
maneira, alterações na função podem ser sistematicamente testadas e
integradas antes da implantação nos servidores de produção. Se uma
alteração recente em uma função causar problemas, o uso do controle de
versão para desenvolver a função permitirá reverter para uma versão
anterior e estável da função.
Neste exercício, você usará o Ansible Galaxy para baixar uma função do Ansible e instalá-la.
Resultados
Você deverá ser capaz de:
criar um arquivo de funções para especificar dependências de função para um playbook
instalar funções especificadas em um arquivo de funções
listar funções usando o comando ansible-galaxy
Visão geral do cenário
Sua organização coloca arquivos personalizados no diretório /etc/skel em todos os hosts. Como resultado, novas contas de usuário são configuradas com um ambiente de bash específico da organização.
Você testará a versão de desenvolvimento da função do Ansible responsável por implantar os arquivos de esqueleto do ambiente de bash.
Faça login na workstation como student usando a senha student.
Na workstation, execute o comando lab role-galaxy start. Isso cria o diretório de trabalho, /home/student/role-galaxy, e o preenche com um arquivo de configuração e um inventário de host do Ansible.
[student@workstation ~]$ lab role-galaxy start
Mude para o diretório de trabalho role-galaxy.
[student@workstation ~]$ cd ~/role-galaxy
[student@workstation role-galaxy]$
Para testar a função do Ansible que configura os arquivos de esqueleto, adicione a especificação de função a um arquivo de funções.
Inicie seu editor de texto favorito e crie um arquivo chamado requirements.yml no subdiretório roles. O URL do repositório Git da função é: git@workstation. lab.example.com:student/bash_env. Para ver como a função afeta o comportamento dos hosts de produção, use o branch master do repositório. Defina o nome local da função como student. bash_env.
roles/requirements.yml agora tem o seguinte conteúdo:
---
# requirements.yml
- src: git@workstation.lab.example.com:student/bash_env
scm: git
version: master
name: student.bash_env
Use o comando ansible-galaxy para processar o arquivo de funções que você criou e instale a função student.bash_env.
Para comparar, exiba o conteúdo do subdiretório roles antes da instalação da função.
[student@workstation role-galaxy]$ ls roles/
requirements.yml
Use o Ansible Galaxy para baixar e instalar as funções listada no arquivo roles/requirements.yml. Certifique-se de que todas as funções baixadas sejam armazenadas no subdiretório roles.
[student@workstation role-galaxy]$ ansible-galaxy install -r \
> roles/requirements.yml -p roles
- extracting student.bash_env to /home/student/role-galaxy/roles/student.bash_env
- student.bash_env (master) was installed successfully
Exiba o subdiretório roles após instalar a função. Confirme se ele tem um novo subdiretório, chamado student.bash_env, que corresponda ao valor name especificado no arquivo YAML.
[student@workstation role-galaxy]$ ls roles/
requirements.yml student.bash_env
Tente usar o comando ansible-galaxy, sem opções, para listar as funções do projeto:
[student@workstation role-galaxy]$ ansible-galaxy list
# /usr/share/ansible/roles
- linux-system-roles.kdump, (unknown version)
- linux-system-roles.network, (unknown version)
- linux-system-roles.postfix, (unknown version)
- linux-system-roles.selinux, (unknown version)
- linux-system-roles.timesync, (unknown version)
- rhel-system-roles.kdump, (unknown version)
- rhel-system-roles.network, (unknown version)
- rhel-system-roles.postfix, (unknown version)
- rhel-system-roles.selinux, (unknown version)
- rhel-system-roles.timesync, (unknown version)
# /etc/ansible/roles
[WARNING]: - the configured path /home/student/.ansible/roles does not exist.
Como você usou a opção -p com o comando ansible-galaxy install, a função student.bash_env não foi instalada no local padrão. Use a opção -p com o comando ansible-galaxy list para listar as funções baixadas:
[student@workstation role-galaxy]$ ansible-galaxy list -p roles
# /home/student/role-galaxy/roles
- student.bash_env, master
...output omitted...
[WARNING]: - the configured path /home/student/.ansible/roles does not exist.
O diretório /home/student/.ansible/roles está no seu roles_path padrão, mas como você não tentou instalar uma função sem usar a opção -p, ansible-galaxy ainda não criou o diretório.
Crie um playbook, chamado use-bash_env-role.yml, que use a função student.bash_env. O conteúdo do playbook deve corresponder ao seguinte:
---
- name: use student.bash_env role playbook
hosts: devservers
vars:
default_prompt: '[\u on \h in \W dir]\$ '
pre_tasks:
- name: Ensure test user does not exist
user:
name: student2
state: absent
force: yes
remove: yes
roles:
- student.bash_env
post_tasks:
- name: Create the test user
user:
name: student2
state: present
password: "{{ 'redhat' | password_hash('sha512', 'mysecretsalt') }}"
Para ver os efeitos da alteração de configuração, uma nova conta de usuário deve ser criada. As seções pre_tasks e post_tasks do playbook garantem que a conta de usuário student2 seja criada sempre que o playbook for executado. Após a execução do playbook, a conta student2 é acessada com a senha redhat.
A senha user2 é gerada usando um filtro. Filtros obtêm dados e os modificam; aqui, a string redhat é modificada ao passá-la para o módulo password_hash. Filtros são um tópico avançado não abordado neste curso.
Execute o playbook. A função student.bash_env cria arquivos de configuração padrão em /etc/skel no host gerenciado. Os arquivos criados incluem .bashrc, .bash_profile e .vimrc.
[student@workstation role-galaxy]$ ansible-playbook use-bash_env-role.yml
PLAY [use student.bash_env role playbook] ************************************
TASK [Gathering Facts] *******************************************************
ok: [servera.lab.example.com]
TASK [Ensure test user does not exist] ***************************************
ok: [servera.lab.example.com]
TASK [student.bash_env : put away .bashrc] ***********************************
changed: [servera.lab.example.com]
TASK [student.bash_env : put away .bash_profile] *****************************
ok: [servera.lab.example.com]
TASK [student.bash_env : put away .vimrc] ************************************
changed: [servera.lab.example.com]
TASK [Create the test user] **************************************************
changed: [servera.lab.example.com]
PLAY RECAP *******************************************************************
servera.lab.example.com : ok=6 changed=4 unreachable=0 failed=0
Conecte-se a servera como usuário student2 usando SSH. Observe o prompt personalizado para o usuário student2 e, em seguida, desconecte-se de servera.
[student@workstation role-galaxy]$ ssh student2@servera
Activate the web console with: systemctl enable --now cockpit.socket
[student2 on servera in ~ dir]$ exit
logout
Connection to servera closed.
[student@workstation role-galaxy]$
Execute o playbook usando a versão de desenvolvimento da função student.bash_env.
A versão de desenvolvimento da função está localizada no branch dev do repositório Git. A versão de desenvolvimento da função usa uma nova variável, prompt_color. Antes de executar o playbook, adicione a variável prompt_color à seção vars do playbook e defina seu valor como azul.
Atualize o arquivo roles/requirements.yml e defina o valor version como dev. O arquivo roles/requirements.yml agora contém:
---
# requirements.yml
- src: git@workstation.lab.example.com:student/bash_env
scm: git
version: dev
name: student.bash_env
Use o comando ansible-galaxy install para instalar a função usando o arquivo de funções atualizado. Use a opção --force para substituir a versão existente do master da função pela versão dev da função.
[student@workstation role-galaxy]$ ansible-galaxy install \
> -r roles/requirements.yml --force -p roles
- changing role student.bash_env from master to dev
- extracting student.bash_env to /home/student/role-galaxy/roles/student.bash_env
- student.bash_env (dev) was installed successfully
Edite o arquivo use-bash_env-role.yml. Adicione a variável prompt_color com o valor blue para a seção vars do playbook. O arquivo agora contém:
---
- name: use student.bash_env role playbook
hosts: devservers
vars:
prompt_color: blue
default_prompt: '[\u on \h in \W dir]\$ '
pre_tasks:
...output omitted...
Execute o playbook use-bash_env-role.yml.
[student@workstation role-galaxy]$ ansible-playbook use-bash_env-role.yml
PLAY [use student.bash_env role playbook] ************************************
TASK [Gathering Facts] *******************************************************
ok: [servera.lab.example.com]
TASK [Ensure test user does not exist] ***************************************
changed: [servera.lab.example.com]
TASK [student.bash_env : put away .bashrc] ***********************************
changed: [servera.lab.example.com]
TASK [student.bash_env : put away .bash_profile] *****************************
changed: [servera.lab.example.com]
TASK [student.bash_env : put away .vimrc] ************************************
okay: [servera.lab.example.com]
TASK [Create the test user] **************************************************
changed: [servera.lab.example.com]
PLAY RECAP *******************************************************************
servera.lab.example.com : ok=6 changed=4 unreachable=0 failed=0
Conecte-se novamente a servera como student2 usando SSH. Observe o erro para o usuário student2 e, em seguida, desconecte-se de servera.
[student@workstation role-galaxy]$ ssh student2@servera
Activate the web console with: systemctl enable --now cockpit.socket
-bash: [: missing `]'
[student2@servera ~]$ exit
logout
Connection to servera closed.
[student@workstation role-galaxy]$
Ocorreu um erro de bash durante a análise do arquivo .bash_profile do usuário student2.
Corrija o erro na versão de desenvolvimento da função student.bash_env e execute o playbook novamente.
Edite o arquivo roles/student.bash_env/templates/_bash_profile.j2. Adicione o caractere ] ausente à linha 4 e salve o arquivo. A parte superior do arquivo agora é:
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/.local/bin:$HOME/bin
export PATH
Salve o arquivo.
Execute o playbook use-bash_env-role.yml.
[student@workstation role-galaxy]$ ansible-playbook use-bash_env-role.yml
PLAY [use student.bash_env role playbook] ************************************
TASK [Gathering Facts] *******************************************************
ok: [servera.lab.example.com]
TASK [Ensure test user does not exist] ***************************************
changed: [servera.lab.example.com]
TASK [student.bash_env : put away .bashrc] ***********************************
ok: [servera.lab.example.com]
TASK [student.bash_env : put away .bash_profile] *****************************
changed: [servera.lab.example.com]
TASK [student.bash_env : put away .vimrc] ************************************
ok: [servera.lab.example.com]
TASK [Create the test user] **************************************************
changed: [servera.lab.example.com]
PLAY RECAP *******************************************************************
servera.lab.example.com : ok=6 changed=3 unreachable=0 failed=0
Conecte-se novamente a servera como student2 usando SSH.
[student@workstation role-galaxy]$ ssh student2@servera
Activate the web console with: systemctl enable --now cockpit.socket
[student2 on servera in ~ dir]$ exit
logout
Connection to servera closed.
[student@workstation role-galaxy]$
A mensagem de erro não está mais presente. O prompt personalizado para o usuário student2 agora é exibido com caracteres azuis.
As etapas acima demonstram que a versão de desenvolvimento da função student.bash_env está com defeito. Com base nos resultados dos testes, os desenvolvedores confirmarão as correções necessárias no branch de desenvolvimento da função. Quando o branch de desenvolvimento passa pelas verificações de qualidade exigidas, os desenvolvedores mesclam os recursos do branch de desenvolvimento com o branch master.
Confirmar as mudanças de função em um repositório Git está além do escopo deste curso.
Ao controlar a versão mais recente de uma função em um projeto, reinstale periodicamente a função para atualizá-la. Isso garante que a cópia local permaneça atualizada com correções de bugs, patches e outros recursos.
Entretanto, se você estiver usando uma função de terceiros na produção, especifique a versão a ser usada para evitar interrupções devido a alterações inesperadas. Atualize periodicamente para a versão mais recente da função em seu ambiente de teste a fim de adotar melhorias e alterações de maneira controlada.
Encerramento
Execute o comando lab role-galaxy finish para limpar o host gerenciado.
[student@workstation ~]$ lab role-galaxy finish
Isso conclui o exercício orientado.
Lista de verificação de desempenho
Neste laboratório, você criará funções do Ansible que usam variáveis, arquivos, modelos, tarefas e manipuladores.
Resultados
Você deverá ser capaz de:
Criar funções do Ansible que usam variáveis, arquivos, modelos, tarefas e manipuladores para configurar um servidor web de desenvolvimento.
Usar uma função hospedada em um repositório remoto em um playbook.
Usar um RedHat EnterpriseLinux em um playbook.
Visão geral do cenário
Sua organização deve fornecer um único servidor web para hospedar o código de desenvolvimento para todos os desenvolvedores da web. Você está encarregado de escrever um playbook para configurar esse servidor web de desenvolvimento.
O servidor web de desenvolvimento deve atender a vários requisitos:
A configuração do servidor de desenvolvimento corresponde à configuração do servidor de produção. O servidor de produção é configurado usando uma função do Ansible, desenvolvida pela equipe de infraestrutura da organização.
Cada desenvolvedor recebe um diretório no servidor de desenvolvimento para hospedar código e conteúdo. O conteúdo de cada desenvolvedor é acessado usando uma porta designada e não padrão.
O SELinux é configurado para ser de imposição e direcionado.
Seu playbook irá:
Usar uma função para configurar diretórios e portas para cada desenvolvedor no servidor web. Você deve gravar essa função.
Essa função depende de uma função gravada pela organização para configurar o Apache. Você deve definir a dependência usando a versão v1.4 da função organizacional. O URL do repositório de dependência é: git@workstation.lab.example.com:infra/apache
Use a função rhel-system-roles.selinux para configurar o SELinux para as portas HTTP não padrão usadas pelo seu servidor web. Você receberá um arquivo de variável selinux.yml que pode ser instalado como um arquivo group_vars para transmitir as configurações corretas para a função.
Faça login na workstation como student usando a senha student.
Na workstation, execute o comando lab role-review start. O script cria o diretório de trabalho, /home/student/role-review, e o preenche com um arquivo de configuração e inventário de host do Ansible e outros arquivos do laboratório.
[student@workstation ~]$ lab role-review start
Mude para o diretório de trabalho /home/student/role-review.
[student@workstation ~]$ cd ~/role-review
[student@workstation role-review]$
Crie um playbook chamado web_dev_server.yml com uma única ação chamada Configure Dev Web Server. Configure a ação para ter como destino o grupo de hosts dev_webserver. Ainda não adicione funções ou tarefas à ação.
Certifique-se de que a ação força os manipuladores à execução, porque você pode encontrar um erro ao desenvolver o playbook.
Depois de concluído, o playbook /home/student/role-review/web_dev_server.yml conterá:
Verifique a sintaxe do playbook. Execute o playbook. A verificação de sintaxe deve ser transmitida e o playbook deve ser executado com sucesso.
[student@workstation role-review]$ ansible-playbook \
--syntax-check web_dev_server.yml
playbook: web_dev_server.yml [student@workstation role-review]$ ansible-playbook web_dev_server.yml PLAY [Configure Dev Web Server] **
TASK [Gathering Facts] *** ok: [servera.lab.example.com]
PLAY RECAP *** servera.lab.example.com : ok=1 changed=0 unreachable=0 failed=0
Certifique-se de que as dependências de função do playbook estejam instaladas.
A função apache.developer_configs que você criará depende da função infra.apache. Crie um arquivo roles/requirements.yml. Ele deve instalar a função do repositório Git em git@workstation.lab.example.com:infra/apache; use a versão v1.4 e nomeie-a infra.apache localmente. Você pode supor que suas chaves SSH estão configuradas para poder obter funções desse repositório automaticamente. Instale a função com o comando ansible-galaxy.
Além disso, instale o pacote rhel-system-roles se não estiver presente.
Crie um subdiretório roles para o projeto do playbook.
[student@workstation role-review]$ mkdir -v roles
mkdir: created directory 'roles'
Crie um arquivo roles/requirements.yml e adicione uma entrada para a função infra.apache. Use a versão v1.4 do repositório git da função.
Depois de concluído, o arquivo roles/requirements.yml conterá:
- name: infra.apache
src: git@workstation.lab.example.com:infra/apache
scm: git
version: v1.4
Instale as dependências do projeto.
[student@workstation role-review]$ ansible-galaxy install \
> -r roles/requirements.yml -p roles
- extracting infra.apache to /home/student/role-review/roles/infra.apache
- infra.apache (v1.4) was installed successfully
Instale o pacote de funções do sistema RHEL se não estiver presente. Ele foi instalado durante um exercício anterior.
[student@workstation role-review]$ sudo yum install rhel-system-roles
Inicialize uma nova função chamada apache.developer_configs no subdiretório roles.
Adicione a função infra.apache como uma dependência para a nova função; faça isso usando as mesmas informações para nome, origem, versão e sistema de controle da versão como o arquivo roles/requirements.yml.
O arquivo developer_tasks.yml no diretório do projeto contém tarefas para a função. Mova esse arquivo para o local correto para que seja o arquivo de tarefas dessa função e substitua o arquivo existente no local.
O arquivo developer.conf.j2 no diretório do projeto é um template Jinja2 usado pelo arquivo de tarefas. Mova-o para o local correto para os arquivos de modelo usados por essa função.
Use o ansible-galaxy init para criar um esqueleto de função para a função apache.developer_configs.
[student@workstation role-review]$ cd roles
[student@workstation roles]$ ansible-galaxy init apache.developer_configs
- apache.developer_configs was created successfully
[student@workstation roles]$ cd ..
[student@workstation role-review]$
Atualize o arquivo roles/apache.developer_configs/meta/main.yml da função apache.developer_configs para refletir uma dependência da função infra.apache.
Após a edição, a variável dependencies é definida da seguinte forma:
dependencies:
- name: infra.apache
src: git@workstation.lab.example.com:infra/apache
scm: git
version: v1.4
Substitua o arquivo tasks/main.yml da função pelo arquivo developer_tasks.yml.
[student@workstation role-review]$ mv -v developer_tasks.yml \
> roles/apache.developer_configs/tasks/main.yml
renamed 'developer_tasks.yml' -> 'roles/apache.developer_configs/tasks/main.yml'
Coloque o arquivo developer.conf.j2 no diretório templates da função.
[student@workstation role-review]$ mv -v developer.conf.j2 \
> roles/apache.developer_configs/templates/
renamed 'developer.conf.j2' -> 'roles/apache.developer_configs/templates/developer.conf.j2'
A função apache.developer_configs processará uma lista de usuários definidos em uma variável denominada web_developers. O arquivo web_developers.yml no diretório do projeto define a variável da lista de usuários web_developers. Revise esse arquivo e use-o para definir a variável web_developers para o grupo de hosts do servidor web de desenvolvimento.
Revise o arquivo web_developers.yml.
---
web_developers:
- username: jdoe
name: John Doe
user_port: 9081
- username: jdoe2
name: Jane Doe
user_port: 9082
name, username e user_port são definidos para cada desenvolvedor da web.
Coloque web_developers.yml no subdiretório group_vars/dev_webserver.
[student@workstation role-review]$ mkdir -pv group_vars/dev_webserver
mkdir: created directory 'group_vars'
mkdir: created directory 'group_vars/dev_webserver'
[student@workstation role-review]$ mv -v web_developers.yml \
> group_vars/dev_webserver/
renamed 'web_developers.yml' -> 'group_vars/dev_webserver/web_developers.yml'
Adicione a função apache.developer_configs à ação no playbook web_dev_server.yml.
O playbook editado:
Verifique a sintaxe do playbook. Execute o playbook. A verificação de sintaxe deve ser transmitida, mas o playbook deve apresentar falha quando a função infra.apache tentar reiniciar o Apache HTTPD.
[student@workstation role-review]$ ansible-playbook \
--syntax-check web_dev_server.yml
playbook: web_dev_server.yml [student@workstation role-review]$ ansible-playbook web_dev_server.yml
PLAY [Configure Dev Web Server] **
TASK [Gathering Facts] *** ok: [servera.lab.example.com]
...output omitted...
TASK [infra.apache : Install a skeleton index.html] *** skipping: [servera.lab.example.com]
TASK [apache.developer_configs : Create user accounts] *** changed: [servera.lab.example.com] => (item={u'username': u'jdoe', u'user_port': 9081, u'name': u'John Doe'}) changed: [servera.lab.example.com] => (item={u'username': u'jdoe2', u'user_port': 9082, u'name': u'Jane Doe'})
...output omitted...
RUNNING HANDLER [infra.apache : restart firewalld] *** changed: [servera.lab.example.com]
RUNNING HANDLER [infra.apache : restart apache] ** fatal: [servera.lab.example.com]: FAILED! => {"changed": false, "msg": "Unable to restart service httpd: Job for httpd.service failed because the control process exited with error code. See \"systemctl status httpd.service\" and \"journalctl -xe\" for details.\n"}
NO MORE HOSTS LEFT *** to retry, use: --limit @/home/student/role-review/web_dev_server.retry
PLAY RECAP ***
servera.lab.example.com : ok=13 changed=11 unreachable=0 failed=1
skipped=1 rescued=0 ignored=0
Um erro ocorre quando o serviço httpd é reiniciado. O daemon de serviço httpd não pode ser vinculado a portas HTTP não padrão devido ao contexto do SELinux nessas portas.
O HTTPD Apache apresentou falha ao reiniciar a etapa anterior porque as portas de rede que ele usa para seus desenvolvedores estão rotuladas com os contextos SELinux incorretos. Você recebeu um arquivo variável, selinux.yml, que pode ser usado com a função rhel-system-roles.selinux para corrigir o problema.
Crie uma seção pre_tasks para sua ação no playbook web_dev_server.yml. Nessa seção, use uma tarefa para incluir a função rhel-system-roles.selinux em uma estrutura block/rescue para que seja devidamente aplicada. Revise a aula ou a documentação sobre essa função para ver como fazer isso.
Inspecione o arquivo selinux.yml. Mova-o para o local correto para que suas variáveis sejam definidas para o grupo de host dev_webserver.
A seção pre_tasks pode ser adicionada ao final da ação no playbook web_dev_server.yml.
Você pode verificar o bloco em /usr/share/doc/rhel-system-roles-1.0/selinux/example-selinux-playbook.yml para ver uma definição básica de como aplicar a função, mas o RedHat Ansible Engine 2.7 permite substituir o complexo shell e a lógica wait_for pelo módulo reboot.
A seção pre_tasks deve conter:
pre_tasks:
- name: Check SELinux configuration
block:
- include_role:
name: rhel-system-roles.selinux
rescue:
# Fail if failed for a different reason than selinux_reboot_required.
- name: Check for general failure
fail:
msg: "SELinux role failed."
when: not selinux_reboot_required
- name: Restart managed host
reboot:
msg: "Ansible rebooting system for updates."
- name: Reapply SELinux role to complete changes
include_role:
name: rhel-system-roles.selinux
O arquivo selinux.yml contém definições de variáveis para a função rhel-system-roles.selinux. Use o arquivo para definir variáveis para o grupo de hosts da ação.
[student@workstation role-review]$ cat selinux.yml
---
# variables used by rhel-system-roles.selinux
selinux_policy: targeted
selinux_state: enforcing
selinux_ports:
- ports:
- "9081"
- "9082"
proto: 'tcp'
setype: 'http_port_t'
state: 'present'
[student@workstation role-review]$ mv -v selinux.yml \
> group_vars/dev_webserver/
renamed 'selinux.yml' -> 'group_vars/dev_webserver/selinux.yml'
Verifique a sintaxe do playbook final. A verificação da sintaxe deve ser transmitida.
Não importa se o pre_tasks está no final da ação ou na posição "correta" em termos de ordem de execução no arquivo do playbook; isso não faz diferença para ansible-playbook. Ele ainda executará as tarefas da ação na ordem correta.
Execute o playbook. Ele deverá ser bem-sucedido.
[student@workstation role-review]$ ansible-playbook web_dev_server.yml
PLAY [Configure Dev Web Server] **
TASK [Gathering Facts] *** ok: [servera.lab.example.com]
TASK [include_role : rhel-system-roles.selinux] **
TASK [rhel-system-roles.selinux : Install SELinux python3 tools] ***** ok: [servera.lab.example.com]
...output omitted...
TASK [infra.apache : Apache Service is started] ** changed: [servera.lab.example.com]
...output omitted...
TASK [apache.developer_configs : Copy Per-Developer Config files] **** ok: [servera.lab.example.com] => (item={u'username': u'jdoe', u'user_port': 9081, u'name': u'John Doe'}) ok: [servera.lab.example.com] => (item={u'username': u'jdoe2', u'user_port': 9082, u'name': u'Jane Doe'})
PLAY RECAP ***
servera.lab.example.com : ok=19 changed=3 unreachable=0 failed=0
skipped=14 rescued=0 ignored=0
Teste a configuração do servidor web de desenvolvimento. Verifique se todos os pontos de extremidade estão acessíveis e se atendem ao conteúdo de cada desenvolvedor.
[student@workstation role-review]$ curl servera servera.lab.example.com has been customized using Ansible. [student@workstation role-review]$ curl servera:9081 This is index.html for user: John Doe (jdoe) [student@workstation role-review]$ curl servera:9082 This is index.html for user: Jane Doe (jdoe2) [student@workstation role-review]$
Avaliação
Classifique seu trabalho executando o comando lab role-review grade a partir da sua máquina workstation. Corrija todas as falhas relatadas e execute novamente o script até que ele seja concluído com êxito.
[student@workstation ~]$ lab role-review grade
Encerramento
Na workstation, execute o script lab role-review finish para limpar este exercício.
[student@workstation ~]$ lab role-review finish
Isso conclui o laboratório.
Neste capítulo, você aprendeu que:
As funções organizam códigos do Ansible para permitir a reutilização e o compartilhamento.
As funções do sistema RedHat Enterprise Linux são uma coleção de funções testadas e suportadas destinadas a ajudar você a configurar subsistemas de host em versões do RedHat EnterpriseLinux.
Ansible Galaxy é uma biblioteca pública de funções do Ansible gravadas por usuários do Ansible. O comando ansible-galaxy pode ser usado para pesquisar, exibir informações sobre, instalar, listar, remover ou inicializar funções.
As funções externas exigidas por um playbook podem ser definidas no arquivo roles/requirements.yml. O comando ansible-galaxy install -r roles/requirements.yml usa esse arquivo para instalar as funções no nó de controle.
Objetivos
Depois de concluir esta seção, você deverá ser capaz de escrever padrões de host sofisticados a fim de selecionar hosts com eficiência para uma ação ou um comando ad hoc.
Referências a hosts de inventário
Os padrões de host são usados para especificar os hosts que devem ser o alvo de uma ação ou comando ad hoc. Na sua forma mais simples, o nome de um host gerenciado ou de um grupo de hosts no inventário é um padrão de host que especifica o host ou grupo de hosts.
Você já usou padrões de host neste curso. Em uma ação, a diretiva de
hosts
especifica os hosts gerenciados nos quais executar a ação. Para um comando ad hoc, forneça o padrão de host como um argumento de linha de comando do comando ansible.Normalmente, é mais fácil controlar quais são os hosts de destino de uma ação usando padrões de host com cuidado e tendo grupos de inventário apropriados, em vez de configurar condicionais complexas nas tarefas da ação. Portanto, é importante ter uma compreensão robusta dos padrões de host.
O exemplo a seguir é usado em toda esta seção para ilustrar os padrões de host.
Para demonstrar como os padrões de host são resolvidos, você executará um playbook do Ansible,
playbook.yml
, usando diferentes padrões de host para segmentar diferentes subconjuntos de hosts gerenciados neste exemplo de inventário.Hosts gerenciados
O padrão de host mais básico é o nome de apenas um host gerenciado listado no inventário. Isso especifica que o host será o único destino de ação do comando ansible no inventário.
Quando o playbook é executado, a primeira tarefa
Gathering Facts
deve ser executada em todos os hosts gerenciados que correspondam ao padrão de host. Uma falha durante essa tarefa pode fazer com que o host gerenciado seja removido da ação.Se um endereço IP estiver listado explicitamente no inventário, em vez de um nome de host, ele poderá ser usado como um padrão de host. Se o endereço IP não estiver listado no inventário, você não poderá usá-lo para especificar o host, mesmo se o endereço IP for resolvido no nome de host no DNS.
O exemplo a seguir mostra como um padrão de host pode ser usado para referenciar um endereço IP contido em um inventário.
Um problema relacionado a hosts gerenciados por endereço IP no inventário é que pode ser difícil lembrar qual endereço IP corresponde a qual host para suas ações e comandos ad hoc. No entanto, pode ser necessário especificar o host por endereço IP, para fins de conexão, se o host não tiver um nome de host que possa ser resolvido.
É possível apontar um alias para um endereço IP específico no seu inventário, definindo a variável de host
ansible_host
. Por exemplo, você poderia ter um host no inventário chamadodummy.example
e direcionar conexões usando esse nome para o endereço IP 192.168.2.1, criando um arquivohost_vars/dummy.example
contendo a seguinte variável de host:Especificação de hosts usando um grupo
Você já usou grupos de hosts de inventário como padrões de host. Quando um nome de grupo é utilizado como padrão de host, ele especifica que o Ansible atuará sobre os hosts que são membros do grupo.
Há um grupo especial chamado
all
que corresponde a todos os hosts gerenciados no inventário.Há também um grupo especial chamado
ungrouped
que inclui todos os hosts gerenciados no inventário que não são membros de nenhum outro grupo:Correspondência de vários hosts com curingas
Outro método para obter o mesmo resultado que o do padrão de host
all
é usar o asterisco (*), que corresponde a qualquer string. Se o padrão de host for apenas um asterisco entre aspas, todos os hosts no inventário corresponderão.Alguns caracteres usados nos padrões de host também são relevantes para o shell. Isso pode ser um problema ao usar padrões de host para executar comandos ad hoc da linha de comando com ansible. A prática recomendada é colocar entre aspas simples os padrões de host usados na linha de comando para protegê-los de expansão de shell indesejada.
Da mesma forma, se você estiver usando algum curinga especial ou caracteres de lista em um playbook do Ansible, deverá colocar seu padrão de host entre aspas simples para garantir que seja analisado corretamente.
O caractere de asterisco também pode ser usado para corresponder hosts ou grupos gerenciados que contenham uma substring específica.
Por exemplo, o padrão de host de curinga a seguir corresponde a todos os nomes de inventário que terminam em
.example.com
:O exemplo a seguir usa um padrão de host de curinga que corresponde a nomes de hosts ou grupos de hosts que iniciam com
192.168.2.
:O próximo exemplo usa um padrão de host de curinga que corresponde a nomes de hosts ou grupos de hosts que iniciam com
datacenter
:Os padrões de host de curinga correspondem a todos os nomes de inventário, hosts e grupos de hosts. Eles não diferenciam entre nomes que são nomes DNS, endereços IP ou grupos, o que pode provocar algumas correspondências inesperadas.
Por exemplo, compare os resultados da especificação do padrão de host
datacenter*
do exemplo anterior com os resultados do padrão de hostdata*
com base no inventário de exemplo:Listas
Várias entradas em um inventário podem ser referenciadas usando listas lógicas. Uma lista separada por vírgulas de padrões de host corresponde a todos os hosts que correspondem a qualquer um dos padrões de host.
Se você fornecer uma lista separada por vírgulas de hosts gerenciados, todos esses hosts gerenciados serão o alvo:
Se você fornecer uma lista separada por vírgulas de grupos, todos os hosts nesses grupos serão o alvo:
Você também pode misturar hosts, grupos de hosts e curingas, conforme mostrado abaixo:
O caractere de dois-pontos (:) pode ser usado no lugar de uma vírgula. Porém, a vírgula é o separador de preferência, especialmente ao se trabalhar com endereços IPv6 como nomes de hosts gerenciados. Você pode ver a sintaxe de dois-pontos em exemplos anteriores.
Se um item em uma lista inicia com um caractere de "e" comercial (&), os hosts deverão corresponder a esse item para corresponder ao padrão de host. Funciona de modo semelhante a um AND lógico.
Por exemplo, com base no nosso inventário de exemplo, o padrão de host a seguir corresponde a máquinas no grupo
lab
apenas se elas também estiverem no grupodatacenter1
:Você também pode especificar que as máquinas no grupo
datacenter1
correspondem apenas se estiverem no grupolab
com os padrões de host&lab,datacenter1
oudatacenter1,&lab
.Você pode excluir hosts que correspondam a um padrão de uma lista, usando o caractere de ponto de exclamação (!) na frente do padrão de host. Isso funciona como um NOT lógico.
Este exemplo corresponde a todos os hosts definidos no grupo
datacenter
, excetotest2.example.com
, com base no inventário de exemplo:O padrão
'!test2.example.com,datacenter'
poderia ser usado no exemplo anterior para obter o mesmo resultado.O exemplo final mostra o uso de um padrão de host que corresponde a todos os hosts no inventário de teste, exceto os hosts gerenciados do grupo
datacenter1
.Working with Patterns — Ansible Documentation
Working with Inventory — Ansible Documentation