Utilizando o Ansible – parte 2

ansible-2_abertura

A primeira parte constituiu de uma introdução ao Ansible, apresentando alguns conceitos básicos, configurando um ambiente para executá-lo com ajuda do Vagrant e Virtualenv e até realizando um teste bem simples para saber se tudo estaria funcionando corretamente.

Nesta parte será a vez de explorar alguns dos módulos disponíveis na ferramenta, rotinas que são executadas remotamente nos nós e que controlam recursos do sistema como status de serviços, instalação ou remoção de pacotes, transferência de arquivos, execução de comandos etc.

Mas antes de começar…

$ cd ~/Vagrant/ansible
$ vagrant up
...
$ vagrant ssh
...
$ source ~/ansible_env/bin/activate
(ansible_env) $

Para executar a máquina virtual, acessá-la e deixar o ambiente pronto para a entrada dos comandos.

Executando módulos do Ansible

Apenas para relembrar, a experiência com o Ansible até agora se resumiu ao módulo ping:

$ ansible localhost -c local -i ./hosts -m ping
127.0.0.1 | SUCCESS => {
    "changed": false, 
    "failed": false, 
    "ping": "pong"
}

Porém o Ansible possui uma grande quantidade de módulos específicos para ambientes, bancos de dados, ferramentas, sistemas operacionais, tecnologias etc mas infelizmente seria impossível tratar de cada um deles então listarei alguns módulos, específicos para tarefas de instalar pacotes, subir serviços ou mesmo executar comandos de forma remota.

O módulo “shell”

Começando com aquele que virtualmente permite fazer qualquer operação dentro de um nó, o módulo shell¹, e que serve para executar remotamente um comando e retornar seu resultado:

$ ansible localhost -c local -i ./hosts -m shell -a "uname -a"
127.0.0.1 | SUCCESS | rc=0 >>
Linux ubuntu-xenial 4.4.0-98-generic #121-Ubuntu SMP Tue Oct 10 14:24:
03 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

Interessante notar que diferente do ping, o módulo shell tem um argumento obrigatório que é o comando a ser executado, informado através do parâmetro “-a”. O retorno também é diferente sendo a saída gerada pelo comando e o return code — rc — da operação. Ou seja, não é JSON.

Aliás, por exemplo, caso algo dê errado…

$ ansible localhost -c local -i ./hosts -m shell -a "ksh select.sh"
127.0.0.1 | FAILED | rc=127 >>
/bin/sh: 1: ksh: not foundnon-zero return code
$ echo ${?}
2

…você será avisado, tanto pelo conteúdo valor de “rc” na saída da execução do módulo como pelo código de retorno do próprio comando.

(¹) Ele não funcionará em nós rodando Windows, para estes sujeitos existe um módulo análogo chamado win_shell.

O módulo “get_url”

Diferente do primeiro, este tem uma função bem mais específica que é baixar arquivos através de FTP, HTTP ou HTTPS e colocá-los em um local determinado, o get_url:

$ ansible localhost -c local -i ./hosts -m get_url \
  -a "url=https://br.wordpress.org/wordpress-4.9-pt_BR.tar.gz 
    dest=/vagrant"
127.0.0.1 | SUCCESS => {
    "changed": true, 
    "checksum_dest": null, 
    "checksum_src": "940f260079113bc830cd9371947777ad47f52237", 
    "dest": "/vagrant/wordpress-4.9-pt_BR.tar.gz", 
    "failed": false, 
    "gid": 1000, 
    "group": "ubuntu", 
    "md5sum": "c2fb94684095554f3f768cbbb424db63", 
    "mode": "0664", 
    "msg": "OK (10124112 bytes)", 
    "owner": "ubuntu", 
    "size": 10124112, 
    "src": "/tmp/tmpIXedd3", 
    "state": "file", 
    "status_code": 200, 
    "uid": 1000, 
    "url": "https://br.wordpress.org/wordpress-4.9-pt_BR.tar.gz"
}

Diferente do primeiro, este módulo tem dois argumentos obrigatórios. Um é “url” que é justamente o que deverá ser baixado e o outro é “dest” informando o local onde salvar o arquivo.

Aliás, diferente das demais execuções até agora, o resultado desta, apesar de bem sucedida, foi impressa em uma cor diferente do verde ou vermelho habituais. Repare a chave “changed” do JSON com o valor “true”, ela indica que a execução deste módulo resultou em uma alteração da situação anterior, isto é, como o arquivo não existia, ele foi baixado e colocado no lugar indicado.

Mas execute-o novamente…

$ ansible localhost -c local -i ./hosts -m get_url \
  -a "url=https://br.wordpress.org/wordpress-4.9-pt_BR.tar.gz 
    dest=/vagrant"
127.0.0.1 | SUCCESS => {
    "changed": false, 
    "checksum_dest": "940f260079113bc830cd9371947777ad47f52237", 
    "checksum_src": "940f260079113bc830cd9371947777ad47f52237", 
    "dest": "/vagrant/wordpress-4.9-pt_BR.tar.gz", 
    "failed": false, 
    "gid": 1000, 
    "group": "ubuntu", 
    "md5sum": "c2fb94684095554f3f768cbbb424db63", 
    "mode": "0664", 
    "msg": "OK (10124112 bytes)", 
    "owner": "ubuntu", 
    "size": 10124112, 
    "src": "/tmp/tmpv8nn5z", 
    "state": "file", 
    "status_code": 200, 
    "uid": 1000, 
    "url": "https://br.wordpress.org/wordpress-4.9-pt_BR.tar.gz"
}

…para o resultado aparecer em verde e a chave “changed” marcada como “false” pois o arquivo, apesar de ter sido baixado, é o mesmo que existia anteriormente, ou seja, não houve a necessidade de fazer a alteração.

O módulo “apt”

Ele, o módulo apt, gerencia a instalação de pacotes via APT. No argumento “name” você informa o nome do pacote a ser instalado. Uma argumento opcional mas que pode ser bastante útil é o “update_cache=true” para executar um apt-get update antes. Assim, para instalar um pacote, neste caso o Servidor HTTP Nginx, utilizando este módulo, você faz:

$ ansible localhost -c local -i ./hosts -m apt \
  -a "name=nginx update_cache=true"
127.0.0.1 | FAILED! => {
    "changed": false, 
    "cmd": "apt-get update", 
    "failed": true, 
    "msg": "W: chmod 0700 of directory /var/lib/apt/lists/partial fai
    led - SetupAPTPartialDirectory (1: Operation not permitted)\nE: C
    ould not open lock file /var/lib/apt/lists/lock - open (13: Permi
    ssion denied)\nE: Unable to lock directory /var/lib/apt/lists/\nW
    : Problem unlinking the file /var/cache/apt/pkgcache.bin - Remove
    Caches (13: Permission denied)\nW: Problem unlinking the file /va
    r/cache/apt/srcpkgcache.bin - RemoveCaches (13: Permission denied
    )", 
    ...
}

O que foi que aconteceu? Simples, o usuário que estou utilizando, no caso o ubuntu², não tem permissão para alterar os arquivos da base de dados do APT e dentro do Ansible não é diferente.

Aqui é preciso dizer para a ferramenta executar o módulo com um outro usuário e, claro, identificar qual será utilizado, neste caso o “root”, respectivamente, com os parâmetros “- -become” e “- -become-user”:

$ ansible localhost -c local -i ./hosts -m apt \
  -a "name=nginx update_cache=true" \
  --become --become_user=root
127.0.0.1 | SUCCESS => {
    "cache_update_time": 1511869821, 
    "cache_updated": true, 
    "changed": true, 
    "failed": false, 
     ...
    "stderr": "", 
    "stderr_lines": [], 
     ...
    "stdout_lines": [
        "Reading package lists...", 
        "Building dependency tree...", 
        "Reading state information...",
         ... 
        "Setting up nginx-common (1.10.3-0ubuntu0.16.04.2) ...", 
        "Setting up nginx-core (1.10.3-0ubuntu0.16.04.2) ...", 
        "Setting up nginx (1.10.3-0ubuntu0.16.04.2) ...", 
        "Processing triggers for libc-bin (2.23-0ubuntu9) ...", 
        "Processing triggers for systemd (229-4ubuntu21) ...", 
        "Processing triggers for ureadahead (0.100.0-19) ...", 
        "Processing triggers for ufw (0.35-0ubuntu2) ..."
    ]
}

Pronto, pacote instalado! E assim como aconteceu com o get_url, executá-lo novamente não o instalará novamente o pacote:

$ ansible localhost -c local -i ./hosts -m apt \
  -a "name=nginx update_cache=true" \
  --become --become-user=root 
127.0.0.1 | SUCCESS => {
    "cache_update_time": 1511869821, 
    "cache_updated": false, 
    "changed": false, 
    "failed": false
}

(²) Veja as saídas do módulo get_url, no JSON está registrado tanto o UID quanto o GID do usuário atualmente em uso, ou apenas execute o Ansible com -m shell -a whoami para verificar.

O módulo “service”

Para finalizar o módulo service que permite iniciar, reiniciar, parar, habilitar ou desabilitar serviços dentro de um determinado nó, ou conjunto de nós. Aproveitando que o Nginx que acabou de ser instalado, que tal para iniciar o serviço?

$ ansible localhost -c local -i ./hosts -m service \
  --args="name=nginx state=started" \
  --become --become-user=root
127.0.0.1 | SUCCESS => {
    "changed": false, 
    "failed": false, 
    "name": "nginx", 
    "state": "started", 
    "status": {
        ...
    }
}

Não houve mudança de status, pois justamente após a instalação o Nginx já fora iniciado com sucesso, daí o valor “false” na chave “changed”, ou seja, não houve alteração. Isto acontece pois o Ansible iniciará o serviço caso ele esteja parado, assim como o parará somente se ele estiver em execução.

Neste módulo e, como visto também nos demais, as ações só serão executadas se forem necessárias.

Já que ele está iniciado que tal então pará-lo?

$ ansible localhost -c local -i ./hosts -m service \
  --args="name=nginx state=stopped" \
  --become --become-user=root 
127.0.0.1 | SUCCESS => {
    "changed": true, 
    "failed": false, 
    "name": "nginx", 
    "state": "stopped", 
    "status": {
        ...
    }
}

O que neste caso constará como mudança, já que o serviço estava em execução e foi interrompido.

Fim desta parte

Com esta lista de comandos já é possível remotamente parar o servidor HTTP (ou instalá-lo no caso de um novo host), baixar a última versão estável do sítio web, descompactá-la no lugar adequado e então iniciá-lo de forma automática. Claro que ainda está meio chato sendo necessário usar uma sequência de comandos contendo vários parâmetros e argumentos.

Mas na próxima parte será a vez de simplificar um pouco a tarefa trabalhando com os playbooks, até!

6 comentários sobre “Utilizando o Ansible – parte 2

  1. Opa….ótimo material, me ajudou muito…obrigado!

    Obs: precisa arrumar o titulo dessa pagina…a palavra Ansible esta incorreta…abs

    Curtir

  2. Giovanni, por que há a necessidade de se utilizar os dois parâmetros, “-become” e “-become-user”?

    Curtir

    • O primeiro, o “become”, serve para indicar ao Ansible que você trocará de usuário (por padrão ele usa o mesmo usuário com o qual você está logado). O segundo, “become_user” serve para indicar qual usuário será utilizado, quase sempre o ‘root’ mas as vezes você pode necessitar de outro (tipo fazer manutenção em um banco de dados).

      Curtir

  3. Pingback: Utilizando o Ansible – parte 3 | giovannireisnunes

Os comentários estão desativados.