Hoy vamos a profundizar más en la estructura recomendada para un proyecto de Ansible. Como ya vimos, una estructura mínima que nos permite aprovechar ciertas características, como la encriptación mediante el uso de ansible-vault, era la siguiente:
Estructura mínima de proyecto. |
Resumiendo lo expuesto anteriormente y por tanto, en el caso más simple:
- En la carpeta raíz del proyecto, tendremos al menos el fichero de configuración ansible.cfg así como el fichero de inventario.
- En la carpeta host_vars existirá un fichero que identificará, ya sea por nombre o dirección IP, a aquellos hosts que necesiten variables específicas.
- En la carpeta group_vars existirán ficheros identificando a los grupos de hosts definidos en el fichero de inventario, y que contendrán variables comunes a dichos grupos de hosts.
Con una estructura así, podemos lanzar comandos ad-hoc simples teniendo todas las variables necesarias controladas y localizadas facilmente. De esta manera, podemos añadir o modificar las variables necesarias de forma simple y localizada, evitando así posibles duplicidades y errores. En resumen, con esta estructura:
- Las variables comunes a grupos de hosts deben estar presentes en el fichero correspondiente al grupo, que debe encontrarse en la carpeta group_vars.
- Es muy importante tener en cuenta que, al poder definir variables en múltiples sitios, es necesario que las variables tengan diferentes nombres. Ansible asigna un orden a las variables en función del ámbito de las mismas, lo cual puede llevar a situaciones en las que, variables con el mismo nombre, sean aplicadas según el orden de preferencia dado por Ansible llevando a resultados incorrectos en la ejecución del comando ad-hoc o playbook. En el siguiente enlace puedes consultar el orden que sigue Ansible para el uso de variables.
Como es lógico, todo esto son solo recomendaciones y dependerá del entorno en el que trabajemos, nuestra infraestructura y necesidades que tengamos.
Por tanto, con esta estructura podemos trabajar de forma cómoda con comandos ad-hoc, pero la potencia de Ansible es la posibilidad de crear playbooks con múltiples tareas. En ese caso, la estructura cambiará ligeramente ya que incluiremos el playbook en la carpeta raíz del proyecto, y nos quedaría algo como lo siguiente:
Proyecto con un playbook. |
De forma muy simple, supongamos que tenemos que realizar ciertas tareas sobre un grupo de hosts, como por ejemplo:
- Crear un nuevo usuario en el sistema.
- Instalar un paquete.
- Crear un directorio y aplicarle unos permisos determinados.
- Copiar un fichero con cierta información.
Cada una de estas tareas, podemos realizarlas empleando comandos ad-hoc, pero, para que sea más sencillo y rapido realizar todas las tareas con una sola ejecución, podemos usar un playbook simple como el siguiente:
Playbook simple. |
El playbook es un documento en formato YAML en el cual, si lo analizamos detenidamente, observamos lo siguiente:
- Al ser un documento YAML, debe empezar siempre con tres guiones y terminar con tres puntos.
- El playbook comienza con la especificación de su nombre, si queremos obtener los facts de todos los hosts, con la opción gather_facts, así como a que hosts queremos que se aplique, especificado con la opción hosts que, en este ejemplo, esta fijada en all.
- Usando la cabecera tasks, definimos la lista de tareas que queremos que se apliquen a aquellos hosts sobre los que queramos lanzar el playbook.
- Cada tarea está definida a continuación, especificando el nombre, módulo necesario y los parámetros del mismo.
Es importante darse cuenta del indentado o sangrado necesario, para asegurar que la sintaxis del playbook es correcta o Ansible devolverá un error al procesarlo.
Al usar un playbook, podemos hacer uso de características adicionales de Ansible como las siguientes:
- Podemos usar el subdirectorio files, dentro de la carpeta del proyecto, para guardar aquellos ficheros estáticos que deben copiarse a los hosts. Al usar el módulo ansible.builtin.copy, Ansible buscará por defecto los ficheros a copiar dentro de dicha carpeta, lo que nos permite tener localizados de forma simple los ficheros cuyo contenido no cambia y que necesitamos copiar. En nuestro ejemplo tenemos lo siguiente:
Copia de fichero estático. |
Como podemos ver, no especificamos la ruta donde se encuentra el fichero que queremos copiar, especificado por el parámetro src. Al usar un playbook, Ansible buscará la carpeta files y, si esta existe, buscará el fichero a copiar a las máquinas de destino. Para este ejemplo simple, dicho fichero está presente en la carpeta files y se copia a todos los hosts al ejecutar esta tarea.
- Como vimos en entradas anteriores, usaremos variables, las cuales estarán presentes en el fichero de grupo correspondiente, dentro del directorio group_vars. En este caso, tenemos fijada la password del usuario que queremos crear con la variable secadmin_pass:
Creación de una cuenta de usuario. |
Contenido del fichero group_vars/all. |
- De nuevo, por simplicidad, no he utilizado ansible-vault para encriptar las contraseñas, pero una de las ventajas de emplear esta estructura de directorios con un playbook es que podemos encriptar dicha información para protegerla, como ya vimos en una entrada anterior.
Por tanto, como vemos, emplear la estructura de directorios recomendada, simplifica un poco la creación de proyectos de Ansible y nos permite utilizar características como la encriptación mediante ansible-vault, copia de ficheros sin necesidad de especificar la ruta completa al fichero origen, etc...
En el caso de emplear templates, ficheros cuyo contenido cambia en función de una variable, o del resultado de la ejecución de una tarea anterior, añadiriamos la carpeta templates al directorio de proyecto, con lo que la estructura del mismo quedaría del siguiente modo:
Proyecto incluyendo la carpeta templates. |
Mediante el uso de templates, Ansible puede copiar un fichero y al mismo tiempo modificar el contenido del mismo, mediante el uso de una o más variables. Veamoslo con un ejemplo práctico:
Uso de templates. |
Ejecución de playbook simple. |