Algo que había quedado pendiente en mis anteriores artículos dedicados a Ansible, era la configuración y uso de playbooks. Los playbooks son el lenguaje de configuración, despliegue y orquestación de Ansible. Se utilizan para describir una política a aplicar sobre un sistema o conjunto de sistemas, o para ejecutar una serie de pasos en cualquier proceso de IT.

Este artículo demuestra la configuración y uso de un playbook que permita realizar una tarea básica y elemental: actualizar el sistema operativo de todos los hosts en nuestro inventario.



Básicamente, los playbooks pueden utilizarse para gestionar configuraciones y despliegues en máquinas remotas. En un nivel más avanzado, pueden secuenciar migraciones a lo largo de múltiples capas involucrando actualizaciones de múltiples sistemas, pueden delegar acciones a otros hosts, e interactuar con servidores de monitoreo y balanceadores de carga a lo largo del proceso.

Los playbooks están diseñados para ser legibles por el humano y desarrollados en un lenguaje de plano básico. Existen muchas formas de organizar playbooks y los archivos que éstos incluyen, aunque afortunadamente existen muchos ejemplos y sugerencias disponibles en el repositorio del proyecto en GitHub.

Mientras que es posible utilizar el binario principal ansible (tal como demostré en el artículo Actualizar todos tus servidores al mismo tiempo con Ansible) para llevar a cabo tareas ad-hoc, los playbooks suelen ser utilizados para implementar una configuración o asegurarse de que las configuraciones de los sistemas remotos sean consistentes según nuestra especificación.

Los playbooks se definen en el formato YAML, el cual tiene una sintaxis mínima y trata de no ser un lenguaje de programación o scripting, sino más bien un modelo de configuración o proceso. Cada playbook está compuesto por uno o más "plays" en una lista. La meta de un "play" es mapear un grupo de hosts con roles bien definidos, a través de lo que Ansible llama "tareas". Una tarea es nada más y nada menos que una llamada a un módulo de Ansible.

Al descomponer un playbook en múltiples "plays", se posibilida orquestar despliegues entre múltiples máquinas (por ejemplo correr ciertas tareas en los servidores Web, luego otras en los servidores de bases de datos, etc.)

Veamos un ejemplo

A modo de ejemplo, veamos cómo definir un playbook que se encargue de actualizar todos los servidores en nuestra organización. Este playbook tendrá dos "plays", uno para actualizar los servidores Debian (y derivados) y otro para actualizar los servidores CentOS (y derivados).

Personalmente se me ocurrió crear un directorio donde guardar todos mis playbooks. Luego, el primer paso consiste en crear el archivo de texto que define el nuevo playbook:

admin@obsd:~$ mkdir ~/ansible_playbooks
admin@obsd:~$ nano ~/ansible_playbooks/update.yml

El contenido del playbook es el siguiente:

---
# Este playbook actualiza los sistemas operativos de todos los servidores de desarrollo

- hosts: debian-devel
  become: yes
  tasks:
    - name: Actualizar todos los servidores Debian de desarrollo
      apt:
        update_cache: yes
        upgrade: safe

- hosts: centos-devel
  become: yes
  tasks:
    - name: Actualizar todos los servidores CentOS de desarrollo
      yum: 
        name: '*'
        state: latest
        update_cache: yes
        exclude: kernel*

Se observa claramente una lista de dos ítems, estos son precisamente los "plays", cada uno con una única tarea. Para los hosts en el grupo "debian-devel" se invoca al módulo "apt" con el parámetro "upgrade: safe". Esta tarea actualiza el sistema operativo en un host Debian. Luego se hace algo similar pero para los hosts CentOS, mediante el módulo de Ansible "yum".

Es posible también excluir paquetes al momento de actualizar a través del parámetro "exclude", utilizando expresiones regulares. Por ejemplo para los hosts en el grupo "centos-devel" se excluyen todos los paquetes que comiencen con la palabra "kernel", a fin de evitar actualizar el kernel Linux.

Por supuesto ambos grupos ("debian-devel" y "centos-devel") han sido definidos previamente en el inventario de Ansible.

Una vez definido el playbook, es posible ejecutarlo utilizando el binario ansible-playbook. Este utilitario posee opciones y argumentos similares a ansible. Por ejemplo es posible definir el nivel de paralelismo a través del argumento -f.

Ejecutar el playbook indicando el nombre de archivo como parámetro:

admin@obsd:~$ ansible-playbook ansible_playbooks/update.yml -f 5

PLAY [debian-devel] *****************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************
ok: [dataw-devel.linuxito.com]
ok: [apps1-devel.linuxito.com]
ok: [apps1-testing.colon.linuxito.com]
ok: [db5.linuxito.com]
ok: [s35-devel-v2.linuxito.com]
ok: [qwerty.linuxito.com]
ok: [web-devel.linuxito.com]
ok: [web-db-devel.linuxito.com]
ok: [eyf-devel.linuxito.com]
ok: [r2d2.linuxito.com]
ok: [proxy-test.linuxito.com]
ok: [apps2.linuxito.com]
ok: [apps3.linuxito.com]

TASK [Actualizar todos los servidores Debian de desarrollo] ************************************************************
changed: [db5.linuxito.com]
changed: [apps1-devel.linuxito.com]
changed: [dataw-devel.linuxito.com]
changed: [apps1-testing.colon.linuxito.com]
changed: [s35-devel-v2.linuxito.com]
changed: [r2d2.linuxito.com]
changed: [web-devel.linuxito.com]
changed: [web-db-devel.linuxito.com]
ok: [qwerty.linuxito.com]
ok: [eyf-devel.linuxito.com]
ok: [apps2.linuxito.com]
ok: [apps3.linuxito.com]
ok: [proxy-test.linuxito.com]

PLAY [centos-devel] *****************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************
ok: [apache2-test.linuxito.com]
ok: [postgres10.linuxito.com]
ok: [db12-develop.linuxito.com]
ok: [mysql56.linuxito.com]
ok: [temp3.linuxito.com]
ok: [temp2.linuxito.com]

TASK [Actualizar todos los servidores CentOS de desarrollo] ************************************************************
ok: [apache2-test.linuxito.com]
ok: [mysql56.linuxito.com]
ok: [temp2.linuxito.com]
changed: [db12-develop.linuxito.com]
changed: [postgres10.linuxito.com]

PLAY RECAP *************************************************************************************************************
db5.linuxito.com        : ok=2    changed=1    unreachable=0    failed=0   
s35-devel-v2.linuxito.com : ok=2    changed=1    unreachable=0    failed=0   
dataw-devel.linuxito.com : ok=2    changed=1    unreachable=0    failed=0   
postgres10.linuxito.com  : ok=2    changed=1    unreachable=0    failed=0   
apps1-testing.colon.linuxito.com : ok=2    changed=1    unreachable=0    failed=0   
eyf-devel.linuxito.com : ok=2    changed=0    unreachable=0    failed=0   
apps1-devel.linuxito.com  : ok=2    changed=1    unreachable=0    failed=0   
r2d2.linuxito.com : ok=2    changed=1    unreachable=0    failed=0   
web-db-devel.linuxito.com : ok=2    changed=1    unreachable=0    failed=0   
qwerty.linuxito.com : ok=2    changed=0    unreachable=0    failed=0   
apps2.linuxito.com  : ok=2    changed=0    unreachable=0    failed=0   
apps3.linuxito.com : ok=2    changed=0    unreachable=0    failed=0   
apache2-test.linuxito.com : ok=2    changed=0    unreachable=0    failed=0   
db12-develop.linuxito.com : ok=2    changed=1    unreachable=0    failed=0   
temp2.linuxito.com  : ok=2    changed=0    unreachable=0    failed=0   
mysql56.linuxito.com : ok=2    changed=0    unreachable=0    failed=0   
temp3.linuxito.com       : ok=1    changed=0    unreachable=0    failed=1   
web-devel.linuxito.com  : ok=2    changed=1    unreachable=0    failed=0   
proxy-test.linuxito.com : ok=2    changed=0    unreachable=0    failed=0   

Al final de la ejecución se presenta un sumario donde se detalla el resultado de la ejecución de la tarea (ok=), si hubo cambios en paquetes (changed=), si se pudo acceder al host (unreachable=) y su hubo errores (failed=).

Si se desea examinar en detalle la salida de la ejecución de cada tarea en cada host, es necesario acceder al log de Ansible, el cual debe ser habilitado previamente en el archivo de configuración de Ansible (~/.ansible.cfg) utilizando la variable log_path:

log_path = /var/log/ansible/ansible.log

Referencias


Tal vez pueda interesarte


Compartí este artículo