Aquí estamos otra vez, ahora les quiero agradecer por el tiempo que se toman en leer estos articulos y también les quiero compartir éste nuevo articulo, el cual es el segundo de una serie de tres en donde mostraremos como usar ansible para automatizar los procesos de despliegue de las configuraciones generales del sistema, en este caso el sistema es un servidor Linux con SSH en donde ejecutaremos algunos servicios para la red casera.
Introducción
Recordemos que en el primer articulo ya teniamos ansible instalado en el servidor de control node01, y configuramos la llave SSH en el servidor controlado rpi, también configuramos el inventario de ansible con los parámetros de conexión hacía la máquina rpi y finalmente realizamos una prueba de conectividad vía SSH usando el módulo ping de ansible.
Realicemos una pequeña prueba de ansible usando el modo ad-hoc para ejecutar unos comandos bajo demanda usando el módulo shell en la máquina rpi:
Trabajaremos en el directorio /etc/ansible de la máquina node01 y crearemos un playbook definido en el archivo llamado deploy.yml.,
Para gestionar los playbooks nos cambiamos al directorio /etc/ansible:
$ cd /etc/ansible
$ vim deploy.yml
El documento YAML está compuesto de cuatro partes:
- hosts: la lista de nodos en los cuales se ejecutará el playbook, debe estar definido en el inventario.
- pre_tasks: las tareas que se ejecutan antes de las tareas de los roles principales.
- roles: las tareas especificas de los roles de cada servicio, estos son los roles principales.
- post_tasks: las tareas que se ejecutan después de las tareas de los roles principales.
Creación de roles de Ansible
Para gestionar los roles nos cambiamos al directorio /etc/ansible/roles:
$ cd /etc/ansible/roles
Usamos el comando ansible-galaxy con la opción init para crear la estructura de archivos y directorios del rol:
$ ansible-galaxy init general-settings
Veamos las tareas que definimos en el rol de general-settings, esto se define en el archivo tasks/main.yml:
$ vim general-settings/tasks/main.yml
En esta lista de tareas realizamos lo siguiente:
- Configurar el nombre de host en el sistema usando el módulo hostname.
- Configurar el nombre de host de forma persistente en /etc/hostname usando el módulo copy y la condicional when.
- Configurar resolución de nombres local en /etc/hosts usando el módulo template.
- Instalar el archivo de configuración del cliente wpa_supplicant usando el módulo template y notifica al handler restart wpa_supplicant.
- Instalar el archivo de configuración del cliente dhcpcd usando el módulo template y notifica al handler restart dhcpcd,
- Instalar el paquete tzdata usando el módulo apt.
- Conifgurar la zona horaria usando el módulo timezone y tomando el valor de la variable {{ timezone }}.
Veamos como usamos el módulo template, este se basa en archivos de plantillas definidos por Jinja2, para esto, dentro del directorio del rol debe existir el directorio templates, y ahí se crean los archivos de las plantillas, normalmente los archivos terminan con extensión .j2 para mejor identificación.
$ vim general-settings/templates/wpa_supplicant.conf.yml
Este template, está basado en un archivo de configuración funcional para una red casera, este archivo originalmente fue creado por el programa rasp-config, en base a esto he sustituído algunas partes, como los valores de los parámetros country, el ssid y el psk de network, en su lugar pongo la referencia a unas variables de ansible, a estas variables se les hace referencia invocandolas entre las dobles llaves {{ var_name }}. Cuando se ejecuta el módulo template, hace la sustitución de los valores y copia el archivo destino con la configuración ya parametrizada.
En algunas tareas se usa el parámetro notify, el cual invoca otra tarea que normalmente reinicia algún servicio, estas tareas son llamados handlers, y se definen en el archivo handlers/main.yml:
$ vim general-settings/handlers/main.yml
Como vimos en el uso de los templates jinja2 de arriba, estas son parametrizadas a través de variables de ansible que para este rol se definen en el archivo defaults/main.yml:
$ vim general-settings/defaults/main.yml
Ahora mostraremos como crear un rol de ansible para configurar el servicio del servidor OpenSSH, realizaremos unas configuraciones básicas para asegurar el servicio donde solo permitimos conexiones basadas en autenticación por llaves, y no permitimos conexiones SSH para el usuario root. Por lo tanto esta configuración se asegura que no se use root directamente, y en su lugar se use un usuario normal, siempre y cuando se autentique con una llave RSA.
Usamos el comando ansible-galaxy con la opción init para crear la estructura de archivos y directorios del rol:
$ ansible-galaxy init ssh-server
Veamos las tareas que definimos en el rol de ssh-server, esto se define en el archivo tasks/main.yml:
$ vim ssh-server/tasks/main.yml
En esta lista de tareas realizamos lo siguiente:
- Instalar el cliente y servidor OpenSSH usando el módulo apt.
- Definir nuevo bloque de configuración del servidor OpenSSH usando el módulo blockinfile.
- Reiniciar el servicio sshd cuando se cambie la configuración usando el módulo service.
El rol de ssh-sever es muy simple, no tiene variables predefinidas, tampoco hace uso de templates, en este caso se optó por modificar los archivos de configuración en vivo, y no se usan handlers, en su lugar se reinicia el servicio directamente si es que el archivo es modificado.
Agregamos el rol al playbook de despliegue:
$ cd /etc/ansible
$ vim deploy.yml
Pruebas y ejecución de playbooks de Ansible
Ahora que hemos terminado de editar los documentos de el rol general-settings, debemos hacer unas pruebas de sintaxis a los documentos para estar seguros que lo que escribimos no tiene defectos. Usaremos el comando ansible-playbook y la opción --syntax-check y el nombre del archivo del playbook que invoca el rol.
Como se puede veren los comandos anteriores, en esta ocación no tenemos errores en la sintaxis, por lo tanto ya podemos ejecutar el playbook y ver que se ejecuten las tareas en la máquina rpi:
Bien!!!. Al final, en el resumen de las tareas podemos ver que se ejecutaron en total 13 tareas con resultado OK, esta cuenta incluye la tarea inicial de Gathering Facts, la cual se usa para obtener facts desde la máquina rpi, los facts son datos que representan una parte de la configuración actual de la máquina controlada. También podemos ver que dos tareas cambiaron, es decir, tiene estado changed, no tenemos ninguna con estado unreachable ó inalcanzable, tampoco failed ó fallido, y no se saltó ninguna tarea.
Con esto terminamos esta edición, espero que les sea de utilidad esta información y que lo aprendido lo puedan aplicar en su trabajo del día a día como administradores de sistemas, SREs o ingenieros que implementan DevOps en sus organizaciones. En la siguiente publicación veremos como usar ansible para desplegar un servidor con docker y ahí desplegar pi-hole en modo contenedor.
No olviden que el código de ejemplo que creamos durante este articulo lo pueden descargar de Gitlab en el siguiente URL: https://gitlab.com/jorge.medina/ansible-pihole.
Hasta pronto!, nos vemos en la siguiente entrega.
El tercer articulo de la serie lo puedes encontrar acá.
Automatizando el despliegue de servidores Linux con Ansible