Ansible: ahorrando tiempo de tareas simples y repetitivas

por | octubre 2, 2018

No sólo de Playbooks vivimos y podemos sacar partido de Ansible para ahorrarnos tiempo de tareas simples que se vuelven tediosas cuando las tenemos que repetir en múltiples servidores.

Vamos a partir de un fichero de inventario de hosts de Ansible como el siguiente:

[jboss]
192.168.1.201
192.168.1.202
[wcg]
192.168.1.203
192.168.1.204
192.168.1.205

Los nodos bajo la etiqueta [jboss] son CentOS 7, los [wcg] son Ubuntu Server 18.04 LTS.

Pongamos como primer ejemplo que desconozco qué sistema tienen todos los nodos, podemos saberlo ejecutando:

ansible -i hosts all -a "cat /etc/os-release"

Esto se ejecutará en todos los hosts del inventario, en los que se ejecutará el comando cat /etc/os-release:

[jota@jota-pc test]$ ansible -i hosts all -a "cat /etc/os-release" 
192.168.1.203 | SUCCESS | rc=0 >>
NAME="Ubuntu"
VERSION="18.04.1 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.1 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

192.168.1.204 | SUCCESS | rc=0 >>
NAME="Ubuntu"
VERSION="18.04.1 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.1 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

192.168.1.202 | SUCCESS | rc=0 >>
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

192.168.1.201 | SUCCESS | rc=0 >>
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

192.168.1.205 | SUCCESS | rc=0 >>
NAME="Ubuntu"
VERSION="18.04.1 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.1 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

También podemos comprobar si están levantados estos servidores, su disponibilidad, invocando el módulo ping con -m:

[jota@jota-pc test]$ ansible -i hosts all -m ping
192.168.1.203 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
192.168.1.204 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
192.168.1.205 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
192.168.1.201 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
192.168.1.202 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

¿Qué hay de instalar un paquete en concreto? Aquí podemos en primer lugar invocar un módulo en concreto según el sistema operativo, ya que en CentOS utilizaremos yum y apt en Ubuntu. Además hay que tener en cuenta el usuario con el que vamos a lanzar la instalación. En mi caso es usuario jota y está incluido en el sudoers de la máquina destino. Para hacer sudo con el usuario utilizaremos las opciones -b –ask-become-pass

# CentOS
ansible -i hosts jboss -m yum -a "name=nginx state=latest" -u jota -b --ask-become-pass

# Ubuntu
ansible -i hosts wcg -m apt -a "name=nginx state=latest" -u jota -b --ask-become-pass

O bien utilizar el módulo package que después se encarga de utilizar en cada sistema operativo el gestor de paquetes correspondiente. Podemos lanzar en este caso la orden de instalación en todos los nodos de nuestro inventario:

ansible -i hosts all -m package -a "name=nginx state=latest" -u jota -b --ask-become-pass

Si el paquete ya está instalado en la máquina destino, el atributo state=latest nos asegura que esté en su última versión, por lo que el comando anterior también nos sirve para tener actualizado un determinado paquete a su última versión.

Por otro lado también podemos mantener todos los paquetes actualizados de nuestros sistemas:

# Ubuntu
ansible -i hosts wcg -m apt -a "upgrade=yes update_cache=yes" -u jota -b --ask-become-pass

# CentOS
ansible -i hosts jboss -m yum -a "upgrade=yes update_cache=yes" -u jota -b --ask-become-pass

# Genérico
ansible -i hosts all -m package -a "upgrade=yes update_cache=yes" -u jota -b --ask-become-pass

Otro ejemplo, reiniciar todos los nodos:

ansible -i hosts all -a "init 6" -u jota -b --ask-become-pass

Como vemos existen tareas que creo no son lo suficientemente complejas como para crear un Playbook. En los casos anteriores he utilizado como mucho 3 nodos como ejemplo, pero dependiendo del entorno podemos hablar de decenas, por lo que Ansible nos puede ahorrar mucho tiempo no sólo en tareas repetitivas donde resulta más obvio, sino en tareas puntuales que puedan ser simples pero tediosas.