Automatización, automáticamente, automatizado.
Al final el tiempo es el bien más preciado.
Resumen del artículo
Ansible es un programa informático, una herramienta utilizada tanto por por desarrolladores, administradores de sistemas como por DevOps. Es muy sencillo de usar pero tiene una curva de aprendizaje muy pronunciada, esto significa que el inicio es sencillo pero según avancemos vamos a poder realizar acciones muy complejas.
Fue desarrollado después de otras herramientas similares como Puppet o Chef, en 2012. Fue comprado por Red Hat. Y a diferencia de esas herramientas, Ansible, no tiene agentes, por lo que no hay que gastar recursos en tener una máquina para gestionar.
Ansible se basa en utilizar SSH instalado en los servidores para poder gestionarlos utilizando archivos llamados playbooks en lenguaje YAML. Dentro de otro archivo llamado inventario es donde almacenamos las IPs o URLs de los servidores con el puerto que si es el 22 (por defecto de SSH) no hace falta indicarlo. Estos archivos podemos subirlos a un repositorio de código y así tener un versionado. Las tareas dentro de los playbooks se hacen en distintos hilos, por lo que son en paralelo y ahorran mucho tiempo de ejecución.
¿Como funciona Ansible?
Como he mencionado en el anterior párrafo brevemente, Ansible utiliza SSH para conectarse a los servidores y ejecutar las tareas de los playbooks.
Se llama controlador a la máquina desde donde se ejecuta Ansible, el cual puede ser nuestro ordenador habitual. Y se llaman nodos a cada uno de los servidores.
Instalación y primeros pasos
Vamos a diferenciar e instalar lo necesario en nuestro ordenador local, el cual va a gestionar los servidores y luego los servidores.
Ordenador Local
Solo tienes que instalar Ansible en el ordenador local, luego el ya va a conectarse con los servidores mediante SSH por lo que no necesitas instalar Ansible en cada servidor.
Puedes instalar Ansible en casi cualquier sistema operativo. Para ello vamos a su página oficial y seguimos las últimas instrucciones para instarlo.
Lo recomendable es utilizar siempre Linux, pero es normal utilizar Windows como sistema operativo principal. La forma más sencilla de utilizar Ansible en Windows (ya que no tiene compatibilidad) es descargar VirtualBox o Docker y utilizar una máquina virtual o un contenedor con Linux. También se puede utilizar Cygwin o incluso la nueva utilidad de susbistema Ubuntu en Windows 10.
Servidores
Es una herramienta para gestionar servidores así que necesitamos servidores.
No es muy normal tener un par de servidores baremetal por casa, aun así vamos a ver las diferentes alternativas que podemos utilizar como servidor:
- Varios servidores físicos (baremetal)
- Utilizar un Cloud (Google Cloud tiene 200$ de prueba gratuita sin coste y otros clouds también tiene capa gratuita)
- Utilizar varios contenedores con Docker como servidores
- Utilizar varias máquinas virtuales como servidores con VirtualBox o programas similares
Al final da igual cual elijamos, mientras tengan SSH se pueden gestionar con Ansible.
Yo la que recomiendo es utilizar Cloud, que con la capa gratuita podemos hacer las pruebas y es muy cercano a un nivel de producción. Además así no consume recursos de nuestro propio ordenador. Tan solo tienes que ir a Compute Engine, pulsas sobre crear instancia y seleccionas la más pequeña, f1-micro, con lo que gastarás solo 0,006 $ por hora y las 720 horas son gratuitas cada mes. Con lo que nunca gastarás la prueba gratuita de 200$.
Una vez creada la máquina virtual en el Google Cloud tienes que configurar SSH, para ello vamos a nuestra terminal de nuestro ordenador local y ejecutamos el comando ssh-keygen:
ssh-keygen -t rsa
Ahora nos pedirá donde guardar las claves. Lo más recomendable es crear una carpeta, por ejemplo en el escritorio, donde tener las claves organizadas.
A continuación nos va a pedir la contraseña (passphrase). Es una contraseña que podemos poner para añadir más seguridad al certificado y la clave que estamos generando. No es necesario así que podemos pulsar enter para finalizar.
Esto nos generará 2 archivos. Uno sin terminación, que es la clave privada. Y otro que termina en .pub, que es la clave pública. Vamos a añadir la clave privada (sin terminación) a nuestro ordenador y la clave pública (con terminación .pub) al servidor de Google Cloud.
Para añadir la clave privada a nuestro ordenador ejecutamos el siguiente comando:
ssh-add ruta/y/nombre/de/la-clave/privada #Por ejemplo está en mi carpeta Escritorio y se llama clavePr ssh-add /home/luis/Escritorio/clavePr
Y para añadir la clave pública en Google Cloud pulsamos sobre Editar si ya está creada, luego bajamos hasta Claves SSH y sobre Tienes una clave SSH. Ahí pulsamos sobre añadir elemento y pegamos la clave pública.
Capítulo 0 - El inicio
Para tener un playground donde probar se necesitan servidores. Y hay varias maneras como hemos visto antes en la explicación de que es Ansible.
- Contenedores docker en local
- Máquinas virtuales tipo VirtualBox en local
- Máquinas virtuales en Cloud
- Vagrant en local o en Cloud
- Servidores baremetal / VPS
Todas son validas. Todas son, más o menos, iguales. Lo único que cambia será en la forma de conectarte por SSH o la gestión de los usuarios de cada uno. Yo voy a utilizar Google Cloud como ya mencioné.
Para ello inicio sesión en Google Cloud, voy a la pestaña izquierda de Compute Engine y pulso sobre Crear Instancia. No tiene mucha complicación, le pongo un nombre, elijo el tipo de máquina más pequeño y bajo hasta Administración, seguridad, discos, redes, único propietario. Ahí pulso sobre Seguridad y añado la clave pública SSH que acabo de crear.
Repito este proceso 3 veces. Para generar las claves más rápido solo tenéis que poneros en el mismo directorio en el que queréis que se guarden. Una vez tengamos 3 máquinas podremos probar el acceso por SSH en nuestro local.
Para probarlas en nuestro ordenador tan solo tenemos que apuntar la IP pública (externa) de cada máquina y ejecutar el cliente de SSH en nuestra terminal:
ssh IP-PUBLICA #Ejemplo de mi linux-ansible-2 ssh 35.239.139.167
Si es la primera vez que entramos nos saldrá el aviso de fingerprint, escribimos yes y ya podremos acceder a la máquina virtual. Probamos las 3 máquinas antes de continuar para comprobar si funciona correctamente el SSH en cada máquina.
Capítulo 1 - El inventario
Necesitamos un archivo donde tener las IPs de los servidores a gestionar. Para ello está el inventario. Es un archivo en texto plano en donde podemos organizar estos servidores. Podemos indicar los servidores de diferentes formas.
- Podemos definir directamente la IP / URL
- Podemos crear un grupo de IPs / URLs
- Podemos crear un grupo de subgrupos
- Podemos asociar a un grupo ciertas variables predefinidas
- Podemos usar un patrón de varias IPs / URLs
- Si se cambia el puerto SSH hay que especificarlo (en los anteriores ejemplos es por defecto el 22 así que a hí no hace falta).
- Se pueden utilizar camelcase (tanto mayúsculas como minúsculas mezcladas) en los nombres de los grupos. También se pueden utilizar números en los nombres. Pero no caracteres especiales u otros símbolos.
Mencionar que podemos asociar una dirección IP a una URL de forma muy sencilla, podemos utilizar el panel del dominio, utilizar servicios externos como NO-IP si no tienes un dominio propio o utilizar CloudFlare para apuntar un dominio o subdominio a nuestra IP. En este ejemplo he asociado cada IP a un subdominio con su mismo nombre utilizando Cloudflare y un dominio propio.
Mejor verlo con un ejemplo. Puede ya existir un archivo hosts (inventario) pero que esté todo comentado con #.
sudo nano /etc/ansible/hosts
Vamos a crear cada posibilidad una por una. Primero voy a poner un comentario y luego ya el código, no es necesario el comentario (#).
1. Podemos definir directamente la IP / URL
No hay mucha complicación. Ponemos la IP o la URL directamente, pulsamos enter y escribimos la siguiente IP o URL, poniendo una por línea.
2. Podemos crear un grupo de IPs / URLs
Lo normal no es poner todas las URLs o IPs directamente. Lo normal es utilizar grupos y subgrupos para organizar por categorías. Por ejemplo un grupo para las bases de datos, otro grupo para los de Python, otro para los de NodeJS. Y luego los subgrupos para por ejemplo todos los servidores (da igual de bases de datos, python, nodejs) del centro de datos de León, otro subgrupo para los de Málaga.
Para crear grupos abrimos 2 corchetes cuadrados [ ] y en medio escribimos el nombre del grupo. Luego pulsamos enter y escribimos linea por linea los servidores en IP o URL. Podemos escribir solo 1 servidor o varios. Podemos mezclar IPs y URLs. Y podemos escribir 1 solo grupo o tantos como necesitemos.
Existen 2 grupos por defecto:
- all : Reúne todos los servidores.
- ungrouped : Reúne todos los servidores pero que no estén en ningún grupo.
3. Podemos crear un grupo de subgrupos
Para crear un subgrupo que agrupe varios grupos seguimos abriendo 2 corchetes cuadrados [] escribimos el nombre del subgrupo y añadimos dos puntos : y la palabra children, luego linea por línea ponemos los nombres de los grupos.
4. Podemos asociar variables
Tenemos la opción de asociar variables a una IP / URL determinada o a todo un grupo o subgrupo.
Estas variables van a estar solo disponible al momento de ejecutar el comando AD-HOC no dentro del sistema de los servidores.
Podemos utilizar tanto variables personalizadas definidas por nosotros como varibles predefinidas definidas para configurar Ansible. Lista de variables oficiales. Las más usuales son ansible_user
y ansible_connection
.
Para definir variables, es igual para las personalizadas como para las predefinidas, vamos a nuestro archivo hosts (inventario). Hya 2 maneras para declararlas, podemos asociar una o varias variables solo a una IP / URL separandola con un espacio:
IP / URL var=dato var2=num var3=etc
O podemos asociar una variable a todo un grupo o subgrupo. Para ello ponemos dos puntos seguido de la palabra reservada vars, entonces todas las variables linea por linea a continuación estarán disponibles para ese grupo o subgrupo. Es importante mencionar que si tenemos una misma variable (mismo nombre) en el grupo y en el subgrupo, se va a aplicar la variable del subgrupo.
Luego ya podemos al ejecutar el comando AD-HOC utilizar estas varibles con un formato de doble llave curva {{ nombre-variable }}. Este seria el comando, aunque lo veremos más adelante que significa cada parte.
ansible pruebascomandos -m shell -a "echo {{ ejemplostring }} && echo {{ ejemplobool }}"
Utilizar así las variables es valido pero no recomendado. Lo recomendado, en vez de asociar las variables directamente en el archivo de inventario, es organizarlas en carpetas (group_vars
y hosts_vars
).
5. Podemos usar un patrón de varias IPs / URLs
Se pueden utilizar patrones, también conocido como Expresiones Regulares (Regex) tanto dentro del inventario como luego mezclándolos con los comandos propios de Ansible. Puedes leer más sobre esto en su página oficial: https://docs.ansible.com/ansible/latest/user_guide/intro_patterns.html
Los patrones pueden ahorrar mucho tiempo pero si se utilizan mal entonces aparecerán errores críticos. Por ello hay que especificar muy bien el patrón.
Un patrón muy sencillo es por ejemplo cuando tenemos varios servidores, con un mismo nombre, seguidos por un numero consecutivo. En nuestro ejemplo tenemos 3 servidores asociados a cada uno a un subdominio con el siguiente orden:
- ansible1
- ansible2
- ansible3
En vez de escribir cada uno a uno, podemos utilizar un patrón que recorra desde un número (o letra) inicial hasta un número (o letra) final.
ansible[1:3].ludiba.org ansible[a:c].ludiba.org
Capítulo 2 - Comandos AD-HOC
Podemos llamar con nuestra terminal al programa de Ansible para ejecutar comandos dentro de 1 o varios servidores remotos añadidos en nuestro archivo hosts (inventario).
¿Pero no se utilizaban playbooks para ejecutar estas tareas?
Sí. Los playbooks son un archivo donde vamos a escribir un conjunto de ordenes para ejecutar en nuestros servidores. Pero estos archivos los solemos escribir cuando son tareas repetitivas, si solo ejecutamos ese comando muy de vez en cuando o es la primera y última vez que vamos a ejecutarlo podemos utilizar directamente la terminal.
Puedes utilizar estos comandos AD-HOC por ejemplo para hacer una reinicio en un servidor, para copiar algún archivo individual, para comprobar los recursos, para realizar alguna gestión, etc.
Nota: Lo normal en producción es tener otras herramientas específicas como Zabbix para monitorear la red y los recursos, DataDog, Prometheus, Elastic Stack, New Relic, Nagios, etc.
Modificadores del comando Ansible
Lo primero, como en todos los ejemplos va a ser crear el archivo de hosts (inventario).
sudo nano /etc/ansible/hosts
Vamos a crear un grupo que contenga 2 de nuestros 3 servidores. Con la IP directamente.
Recuerda antes de ejecutar el comando tener las claves SSH bien instaladas en nuestro equipo.
Antes de ejecutar el comando hay que entender que son los módulos en Ansible.
Los módulos son las unidades de trabajo en Ansible. Cada modulo puede estar escrito en diferentes lenguajes de programación y cada uno se puede utilizar de forma individual sin necesidad de instalar ninguna librería en Ansible. La característica principal y por lo que se utilizan módulos es que son idempotentes. Este termino que se usa tanto en informática como en matemáticas como en lógica lo que significa es que una operación si se ejecuta con éxito, al volver a ejecutar la misma operación si continua en el mismo estado, no se vuelve a ejecutar.
Hay más de 5.000 módulos distintos, cada uno con su tarea especifica. Aquí está la lista oficial de módulos disponibles en Ansible.
No necesitas saberte todos los módulos por razones obvias. Pero puedes ir a ese enlace y en el menú de la izquierda filtrar por tipo de módulo cada vez que lo necesites. Por ejemplo pulsas sobre Network modules, aparecen ordenados y puedes filtrar por tipo.
Ahora que ya sabemos que son los módulos pasamos a la linea de comandos. El comando ansible
tiene varios argumentos (modificadores) que le podemos pasar. Aquí está la lista oficial de modificadores para Ansible.
Ahora vamos a ver la estructura del comando. Primero llamamos al comando ansible
que tenemos instalado en nuestro ordenador local. A continuación tenemos varias opciones. Podemos llamar a los servidores donde vamos a ejecutar los módulos de diferentes formas.
- Podemos llamar a una IP o URL sola o llamar a varias separandolas con comas.
ansible ansible1.ludiba.org ansible 35.239.139.167 ansible ansible1.ludiba.org,35.239.139.167
- Podemos utilizar grupos o subgrupos.
ansible pruebascomandos
- Podemos utilizar la palabra reservada
all
para ejecutar el comando en todos los servidores del archivo hosts (inventario).
ansible all
Modificador comando Ansible: -f
Recordamos que Ansible trabaja con hilos, por lo que aunque en el archivo hosts (inventario) o en el propio comando esté antes una IP o URL no significa que se vaya a ejecutar por orden la lista de los servidores. Podemos especificar el número de hilos que va a utilizar Ansible con un modificador.
Por defecto utiliza 5 hilos pero podemos modificar este valor. Tenemos que tener en cuenta que al modificar los hilos, como en cualquier programa, cambia el consumo de recursos que va a consumir. Si aumentamos los hilos consume más, al reducirlo consume menos. Cuando tengamos una gran cantidad de servidores podemos aumentar los hilos, si queremos hacer una tarea en orden consecutivo podemos reducir a 1 el número de hilos, entonces tardará más pero seguirá el orden.
Tiene la siguiente estructura. Aplicamos lo anterior y añadimos el modificador -f
seguido del número de hilos.
ansible pruebascomandos -f 1 ansible pruebascomandos -f 7
Al ejecutarlo dará error ya que aun no hemos visto los módulos.
Modificador comando Ansible: -u
Con el modificador -u
en versión corta o --user
en versión larga indicas el nombre del usuario con el que vas a realizar el comando de Ansible utilizando SSH.
Puede darse el caso que haya diferentes usuarios para realizar diferentes tareas, como por ejemplo es usual tener un usuario especifico para gestionar las bases de datos MySQL.
Para utilziadar este modificador tan solo ponemos -u
o --user
y a continuación el nombre de usuario.
ansible pruebascomandos -u usuariomysql ansible pruebascomandos --user usuariomysql
Modificador comando Ansible: -b
Este modificador -b
en versión corta o --become
en versión larga indica que el modulo va a escalar de permisos. Por ejemplo si utilizas un comando se va a ejecutar como superusuario (root). Es como si ese comando lo ejecutaras con sudo
.
En este modificador no te pedirá la contraseña de superusuario (root).
ansible pruebascomandos -b
Modificador comando Ansible: -K
Este modificador -K
en versión corta o --ask-become-pass
en versión larga es el mismo que el anterior pero sí te pedirá la contraseña de superusuario (root).
ansible pruebascomandos -K
Modificador comando Ansible: -m y -a
Acabamos de ver la lista con más de 5.000 módulos (Lista completa módulos Ansible). Para poder utilizar estos módulos tenemos que especificarlos con el modificador -m
en versión corta o --module-name
en versión larga. Si no especificamos este modificador entonces va a utilziar el módulo command por defecto. Es parecido al módulo shell, pero tiene las siguientes diferencias:
- Los comandos ejecutados bajo el módulo command no van a ejecutarse en la shell del sistema por lo tanto no van a estar disponibles las variables de entorno como $HOME, $USER o $LANG. Al utilizar el módulo shell sí estarían disponibles.
- El módulo shell utiliza la consola por defecto del sistema. Puede ser SH, BASH u otra.
- Con el módulo shell están disponibles las operaciones especiales como redirecciones con los símbolos > y <, las pipelines con la barra vertical |, los operadores AND y OR con && y ||, etc.
- EL módulo command es más seguro justo por lo anterior, no necesita abrir una shell ni un entorno de usuario.
El siguiente ejemplo va a utilizar otro modificador (-a
) que veremos a continuación ya que van de la mano. Podemos ver que si no especificamos el modificador -m
se ejecuta igual solo que bajo el módulo command.
ansible pruebascomandos -m shell -a date
Los dos siguientes son los mismos, si no se pone -m
usa command por defecto
ansible pruebascomandos -m command -a date ansible pruebascomandos -a date
Dará error si lo ejecutamos con command las variables, redirecciones, etc. Pero no con shell.
ansible pruebascomandos -m shell -a "echo $HOME" ansible pruebascomandos -m shell -a "echo $HOME & date" # Los siguientes comandos darán error ansible pruebascomandos -a "echo $HOME" ansible pruebascomandos -a "echo $HOME & date"
Ejemplos de comandos AD-HOC
Vamos a ver varios ejemplos prácticos de comandos, módulos y modificadores.
Modificador -a y hostname
Como hemos visto, si no definimos ningún modulo con -m
entonces ejecutamos un command general con Ansible.
También que utilizamos el modificador -a
para indicar argumentos para cualquier módulo, tanto si no lo indicamos sería command o si indicamos otro pues a ese.
En este ejemplo vamos a utilizar el módulo por defecto command y pasaremos el comando de Linux hostname para comprobar el nombre del host de cada servidor.
ansible pruebascomandos -a hostname
Modificador -a y free
Continuamos con comandos. Un comando de Linux muy típico es free. Con este comando podemos ver la cantidad de memoria RAM y su disponibilidad.
Para ejecutar este comando vamos a utilizar a su vez un modificador con el comando free, por lo tanto como es más de una palabra lo tenemos que poner entre comillas.
ansible pruebascomandos -a "free -m"
Modificador -a y date
Como hemos visto podemos ejecutar cualquier comando Linux en nuestros servidores con Ansible.
ansible pruebascomandos -a date
Módulo PING
Es el módulo más clásico. Su única utilidad es comprobar la conexión con los servidores, si se realiza devuelve una cadena de texto con PONG. No tiene ninguna utilidad en playbooks pero sí en comandos AD-HOC.
ansible pruebascomandos -m ping
Módulo APT
En todos los módulos podemos indicar parámetros que van a modificar el comportamiento de estos módulos al igual que si fueran un comando. Hay diferentes tipos de módulos para esto según el sistema operativo de cada servidor. Debian y sus derivaciones utilizan apt
(esté modulo), CentOS y Red Hat utilizan yum
, Fedora utiliza dnf
.
Para usar este módulo APT lo único que tenemos que hacer es ejecutarlo con -m
y vamos a ver varios de sus parámetros utilizados dentro de -a
.
Recuerda ejecutarlo como sudo con el modificador -b
si la acción requiere hacer cambios en el sistema para hacerlo con sudo. Al igual que un comando en Linux.
ansible pruebascomandos -m apt -a "name=ntp state=present" -b
- name: Indicamos el nombre del paquete. Si solo especificamos el nombre (Ej: ntp) entonces busca la última versión. También podemos especificar una versión. Para especificar una versión en Debian, Ubuntu y derivados primero comprobamos las versiones del paquete (
apt-cache madison nombrepaquete
) y una vez tengamos la que queremos lo instalamos (apt-get install nombrepaquete=versionpaquete
). Pues en Ansible igual. Tan solo lo especificamos en el name la versión, en este caso es Debian (name=ntp=1:4.2.8p12+dfsg-4
). - state: Tenemos varias opciones:
- absent: Borra el paquete especificado en name. El comando Debian sería
apt-get remove
. - build-dep: Instala el paquete especificado en name. El comando Debian sería
apt-get build-dep
. Este estado se usa a la hora de desarrollar un paquete o para instalar una librería desde código fuente. - latest: Instala el paquete especificado en name. Hace una actualización para comprobar que la lista de paquetes disponibles y sus versiones sea la última. El comando Debian sería
apt-get update && apt-get install
. - present: Instala el paquete especificado en name. A diferencia del anterior latest, solo se encarga de comprobar que exista el paquete. El comando Debian sería
apt-get install
. - fixed: Sirve para arreglar dependencias rotas del paquete especificado en name.
- absent: Borra el paquete especificado en name. El comando Debian sería
Si lo ejecutamos varias veces podemos ver como la primera vez sí lo ejecuta y lo descarga, pero las demás como primero hace la comprobación y ve que ya está instalado, no hace cambios en el sistema.
En el caso de querer borrar un paquete solo tenemos que cambiar el estado a absent.
ansible pruebascomandos -m apt -a "name=ntp state=absent" -b
Módulo SERVICE
Controla los servicios del servidor. Podemos activar, parar, reiniciar y otras tareas.
Por ejemplo si solo especificamos el nombre del servicio nos saldrá como respuesta todos los datos respecto a ese servicio.
ansible pruebascomandos -m service -a "name=ntp"
Módulo GROUP
Este módulo sirve para gestionar los grupos dentro de los servidores.
Podemos usar el siguiente ejemplo para crear un grupo admin. Para usar este módulo necesitamos permisos de superusuario por lo que usamos el modificador -b
.
ansible pruebascomandos -m group -a "name=admin state=present" -b
También podemos borrar grupos, por ejemplo ahora voy a borrar el mismo grupo.
ansible pruebascomandos -m group -a "name=admin state=absent" -b
Se puede indicar un GID (Identificador de grupo) específico.
Módulo USER
Al igual que hay un módulo para gestionar grupos, también hay un módulo para gestionar usuarios.
En este ejemplo usamos el módulo user y especificamos el nombre del usuario, también que pertenece al grupo creado anteriormente admin y aunque ya por defecto crea la carpeta home también lo especificamos.
ansible pruebascomandos -m user -a "name=luisdieguez group=admin create_home=yes" -b
Módulo STAT
Es casi diario gestionar, modificar y archivos. Y como hay módulos para todo también para esto.
Lo primero que tenemos que hacer es comprobar el estado y los permisos del archivo a modificar.
Para comprobar los datos de un archivo utilizamos el módulo stat
. Lo utilizamos cuando queramos comprobar los permisos u otras propiedades de un archivo.
En este ejemplo comprobamos el fichero host.
ansible pruebascomandos -m stat -a "path=/etc/host"
Módulo COPY
Sirve para copiar un archivo a los servidores. O sea, desde nuestro ordenador local hacia los servidores.
En este ejemplo vamos a copiar nuestro archivo local hosts a los servidores en el directorio tmp con el nombre de archivo copia.
ansible pruebascomandos -m copy -a "src=/etc/hosts dest=/tmp/copia"
Si queremos que se mantenga el nombre original en vez de poner como destino /tmp/copia en donde especificamos uno nuevo ponemos solo barra /tmp/ para que sea el mismo que el de origen.
Tiene muchos parámetros diferentes, por ejemplo podemos especificar que en vez el archivo solo copie el contenido, los modos de copia, el usuario, validación, etc.
Módulo FETCH
Es el mismo que COPY pero al revés. Ese módulo sirve para copiar archivos del servidor a nuestro local.
Aunque sea el mismo archivo, por defecto crea una carpeta con la IP /URL de cada servidor en nuestro local y dentro el archivo descargado de cada servidor.
ansible pruebascomandos -m fetch -a "src=/etc/hosts dest=/tmp/"
Módulo FILE
Este módulo sirve para crear tanto archivos como directorios. Además nos permite gestionar permisos o crear enlaces simbólicos / físicos dentro del servidor.
Es un módulo muy completo y tiene varios parámetros importantes aunque solo es requerido el path.
Los más interesantes son mode para indicar los permisos. Y state para indicar:
- absent : Los directorios se eliminarán de forma recursiva y los archivos o enlaces simbólicos se desvincularán.
- directory : Crea un directorio.
- file : Opción por defecto. Hace un stat.
- hard : Crea un enlace físico.
- link : Crea un enlace simbólico.
- touch : Crea un archivo vacío.
En estos ejemplos por orden vamos a primero crear un directorio con permisos 700 (Rwx ------). En el segundo creamos un archivo vacío dentro de ese directorio. En el tercero borro solo el archivo y en el cuarto borró el directorio. Si ejecutas entes el cuarto que el tercero también borra el directorio y todo su contenido ya que es recursivo.
ansible pruebascomandos -m file -a "path=/tmp/test mode=700 state=directory"
ansible pruebascomandos -m file -a "path=/tmp/test/archivo.vacio.prueba state=touch"
ansible pruebascomandos -m file -a "path=/tmp/test/archivo.vacio.prueba state=absent"
ansible pruebascomandos -m file -a "path=/tmp/test state=absent"
Módulo CRON
CRON es el demonio (proceso en segundo plano) de Linux que comprueba el archivo de texto plano CRONTAB donde están indicados scripts y la hora programada de ejecución de cada uno.
Con este módulo de Ansible podremos controlar todos los aspectos de CRON en nuestros servidores.
Aunque el nombre (name) no sea actualmente obligatorio vamos a ponerlo para poder borrar después ese CRON y actualizarlo. Por ejemplo este CRON va a ejecutar un script ficticio cada martes a las 4:00 todos los meses.
ansible pruebascomandos -m cron -a "name='ejemplo' weekday=2 hour=4 minute=0 job='/script.sh'"
Pero me he confundido, solo quiero que se ejecute los meses Enero, Febrero y Marzo. Pues puedo modificar el mismo CRON poniendo el mismo nombre.
ansible pruebascomandos -m cron -a "name='ejemplo' month=1-3 weekday=2 hour=4 minute=0 job='/script.sh'"
Módulo SETUP
Ya es el último módulo que voy a mencionar. Viendo solo comandos AD-HOC ya podríamos usar Ansible a un nivel medio con lo podríamos gestionar cientos o miles de servidores simultáneamente de forma sencilla.
Con este módulo vamos a poder ver todos los datos técnicos de los servidores. Estos datos técnicos o propiedades del sistema también se conocen como Facts en Ansible.
ansible pruebascomandos -m setup
Y podemos filtrar, ya que la cantidad de información es muy amplia, con el parámetro -a
.
ansible pruebascomandos -m setup -a "filter=*ipv4"
Aquí tenéis un enlace para ampliar un poco más el tema: Using Ansible Facts to View System Properties.
Capítulo 3 - Playbooks
Como ya mencione al inicio los Playbooks son lo que te van a llevar al siguiente nivel de Ansible.
- Permite tener un control de versiones si los guardamos en GIT.
- Pasar de un script de Bash a un playbook de Ansible es muy sencillo.
- Organización y gestión multi nivel.
Los Playbooks están escritos en lenguaje YAML. No necesitas saber programar, tan solo es un formato por lo que lo único que tienes que aprender es como colocar los atributos. Es muy sencillo de usar, por ejemplo Kubernetes usa este lenguaje. Tiene varias características clave generales como:
- El contenido tiene que ser formato UTF-8 o UTF-16
- Lo recomendable es utilizar espacios en blancos y nunca TAB para indentar.
- Cada elemento de una lista comienzan con un guion ( - ) y un espacio. Tiene versión corta.
- Los diccionarios clave valor utilizan el siguiente formato ( clave: valor ), la palabra que es la calve, dos puntos, espacio, la palabra que es el valor. Tiene versión corta.
- Los comentarios se indican con una almohadilla ( # ).
- La terminación de los archivos YAML puede ser .yml o .yaml indistintamente aunque se recomienda usar .yaml como estándar.
Características generales de YAML para Ansible
Acabamos de ver las características generales de YAML. Pero Ansible dentro de este lenguaje tiene sus propias características.
Variables
Para indicar una variable dentro de un Playbook de Ansible utilizamos la estructura de doble corchete.
{{ nombrevar }}
Es muy típico declarar variables al inicio del Playbook y usarlas a lo largo de todo el archivo. Por ejemplo.
directorio: "/home/luis/Downloads" archivo: "{{ directorio }}/ejemplo.txt"
Inicio y final archivo
El inicio del contenido del archivo YAML, del Playbook de Ansible. Comienza con tres guiones y acaba con tres puntos.
Aunque esto es opcional, no hay que ponerlo obligatoriamente y el Playbook funcionaría igual, es considerado buena practica.
--- contenido playbook ...
Características generales de un Playbook
Un Playbook se compone de uno o varios plays. Un play es realizado en un determinado grupo de servidores. Un play es equivalente a usar un módulo de Ansible. Dentro de un Playbook tenemos diferentes tareas que se ejecutan en uno o varios servidores al mismo tiempo.
Ejemplo estructura de Playbook
Vamos a crear un Playbook para instalar Apache.
Cómo sería en comandos de Linux: Primero instalamos el paquete de Apache y luego iniciamos el servicio.
sudo apt install apache2
sudo service apache2 start
Como sería en un playbook de Ansible.
--- - hosts: pruebascomandos become: yes tasks: - name: Install Apache apt: name=apache2 state=latest - name: Check Apache is running & start on boot service: name=apache2 state=started enabled=yes ...
Este playbook básico está formado por lo siguiente:
- Iniciamos una lista.
- Primero ponemos los
hosts
que son los servidores de nuestro inventario, indicados de cualquier forma. - Opcionalmente y en este caso obligatorio ya que vamos a realizar cambios en el sistema y necesitamos permisos de super usuario, vamos a poner
become
(become superuser) dos puntosyes
. Seria equivalente al-b
en los comandos AD-HOC. Puede darse el caso que los comandos no necesiten permisos de superusuario entonces no lo ponemos. - Luego ponemos las tareas (
tasks
) que irán en formato lista por lo que podemos poner solo una o varias.- Cada tarea inicia, aunque es opcional, con un nombre (
name
). Sirve solo para identificar la tarea. - Después ponemos el módulo de Ansible a utilizar. En la misma línea del módulo ponemos sus paramentos y lo configuramos igual que un comando AD-HOC.
- Cada tarea inicia, aunque es opcional, con un nombre (
- Primero ponemos los
Recomendaciones:
- Crear un directorio donde guardar los playbooks o utilizar un repositorio GIT.
- Las tareas se ejecutan por orden.
- Podemos utilizar cualquier editor, tanto un IDE tipo Visual Studio Code, como en la terminal con un editor de texto tipo NANO o VIM.
- El nombre del archivo no tiene que seguir ningún formato. Puede ser a gusto.
- Los
name
de cada tarea suelen ser en ingles como estándar, pero nadie te quita de usar castellano u otro idioma mientras siga UTF-8 o 16. - Dentro de un mismo Playbook podemos crear diferentes grupos de tareas para diferentes servidores. Para ello tan solo tenemos que escribir otra vez
- hosts: etc
ya que al ser una lista podemos seguir añadiendo. - Podemos definir el usuario que va a ejecutar todo el playbook o una tarea añadiendo
remote_user: nombre
.
Para ejecutar el playbook que hemos escrito previamente vamos a utilizar un nuevo comando de Ansible: ansible-playbook
seguido del nombre o ruta del archivo playbook.
ansible-playbook ejemplo-apache.yaml
Características avanzadas de un Playbook
Una vez vistas la base de Ansible podemos ir más allá.
Handlers
Los handlers son tareas pero que solo se van a ejecutar cuando se les llame. Es similar a los triggers de MySQL o a una función en cualquier lenguaje de programación, el código está ahí pero solo se ejecuta cuando se llama. Así ahorraremos mucho tiempo en escribir lo mismo una y otra vez.
Los handlers se ejecutan siempre a final del playbook. Si el comando da como resultado SUCCESS o OK, que no produce ningún cambio (CHANGED) entonces ni la tarea ni el handler se ejecutarán.
Así que vamos a ver varias nuevas estructuras para introducir dentro de nuestro playbook.
- notify
- handlers
- listen
La estructura básica de handlers es un notify y luego un handler. Vamos a continuar con el mismo ejemplo de Apache. Al mismo nivel que los tasks ponemos los handlers, al ser ambos una lista podemos poner varios. Y en la tarea que queramos que se ejecute ponemos el notify y el nombre único (por eso lo he acortado un poco) del handle.
--- - hosts: pruebascomandos become: yes tasks: - name: Install Apache apt: name=apache2 state=latest notify: check apache handlers: - name: check apache service: name=apache2 state=started enabled=yes ...
Una duda que suele surgir es: ¿Si tengo varias tareas diferentes, tengo que poner el notify en cada una?
La respuesta es: Según lo que sean esas tareas. Si por ejemplo instalas Apache y en otra tarea instalas PHP, para que funcione cada una individualmente necesitas realizar un inicio del servicio, pero si se la pones solo a una, y esa tarea da OK ya sea por que ya está instalada u otro caso, entonces no se va a ejecutar el handler necesario en la siguiente si no lo has puesto.
Esa sería la estructura básica. Pero podemos añadir una estructura más a los handlers. Esta nueva estructura se llama listen. Tal y como ponen en la documentación oficial, esta estructura hace mucho más sencillo ejecutar varios handlers.
Esta estructura sustituye el notify de cada handlers por listen. Es el mismo ya que queremos que se ejecuten ambos handlers, agrupamos varios handlers para cuando la tarea ejecute el notify se ejecuten ambos.
--- - hosts: pruebascomandos become: yes tasks: - name: Install Apache apt: name=apache2 state=latest notify: "check web services" handlers: - name: check apache service: name=apache2 state=started enabled=yes listen: "check web services" - name: check ntp service: name=ntp state=started enabled=yes listen: "check web services" ...
Mostrar la salida
Podemos mostrar la salida de los comandos al igual que en un comando AD-HOC cuando ejecutemos nuestros Playbooks.
Para ello solo utilizamos el parámetro -v
en versión corta, --verbose
en versión larga.
ansible-playbook ejemplo-apache.yaml -v
De diario no se utiliza, solo en caso de que haya fallos y tengamos que debuggear.
Solo comprobar
Otra utilidad a la hora de debuggear es que podemos ejecutar un playbook sin que realice cambios en los servidores, solo que compruebe si se podrían hacer esos cambios.
Para ello utilizamos el parámetro --check
.
ansible-playbook ejemplo-apache.yaml --check
Capítulo 4 - El inventario AVANZADO
Ya hemos visto en el capitulo 1 lo que es el inventario y todas las formas de indicar los servidores. Pero podemos hacer mucho más.
Por defecto y el archivo que hemos estado modificando hasta ahora el inventario está en la ruta /etc/ansible/hosts
. Lo que no había mencionado es que podemos tener varios archivos de inventario. Para ello solo tenemos que crear un archivo de texto plano y escribir de misma manera los servidores. Para especificarlo tanto en los comandos AD-HOC como en los Playbooks utilizamos el parámetro --inventory
seguido de la ruta donde esté o en formato corto -i
seguido de la ruta donde esté.
Ejemplo comando AD-HOC:
ansible pruebascomandos -m ping -i /home/luis/Escritorio/inventario
Ejemplo Playbooks. No hay que modificar el archivo, se indica el inventario en el comando.
ansible-playbook ejemplo-apache.yaml -i /home/luis/Escritorio/inventario
Capítulo 5 - El playbook AVANZADO
Include
Es similar a una librería en cualquier lenguaje de programación.
En vez de copiar y pegar varias tareas en nuestro playbook, en el anterior ejemplo instalamos Apache, lo podemos añadir como una librería y instalar Apache.
Por ejemplo, queremos instalar Apache en todos los servidores y luego hacer alguna tarea más especifica. Pues utilizamos Include. Para ello quitamos del archivo que vamos a incluir las palabras clave antes de las tareas (hosts
, become
, tasks
, etc). Y separamos en dos archivos diferentes las tareas y los handlers.
Archivo de solo tareas, en este caso instalar Apache.
--- - name: Install Apache apt: name=apache2 state=latest notify: "check web services" ...
Archivo de solo handlers.
--- - name: check apache service: name=apache2 state=started enabled=yes listen: "check web services" - name: check ntp service: name=ntp state=started enabled=yes listen: "check web services" ...
Y luego el archivo general, donde vamos a hacer esas llamadas y podemos hacer además otras tareas. Como podemos ver tan solo tenemos que utilizar la palabra include
seguida de la ruta de los anteriores archivos. Podemos poner varios include
dentro de un mismo archivo, por ejemplo uno para instalar Apache, otro PHP, otro MySQL. Lo mismo para los handlers
.
--- - hosts: pruebascomandos become: yes tasks: - include: playbook-solo-apache.yaml handlers: - include: varios-handlers.yaml ...
Y lo ejecutamos con el comando normal para playbooks.
Es muy recomendado utilizar esta forma de organización. Es mucho mejor utilizar includes de archivos pequeños que un solo playbook enorme.
Roles
Lo roles nos sirven principalmente para organizar mejor los playbooks. Junto con los handlers, los include y los pre_task nos sirven para hacer que nuestro código sea más sencillo de mantener a largo plazo.
Los roles nacen de la necesidad de gestión de playbooks grandes. Cuando un playbook es grande es normal tener un include que a su vez llama a otro include y a su vez llama a otro. Y te puedes acabar perdiendo.
Había dicho que un include es similar a una librería, pues un rol es un nivel superior. Son paquetes de aplicaciones predefinidas, en las que controlamos todos los aspectos y podemos utilizarlas en cualquier servidor. Suelen ser complejos, podemos configurarlo para que identifique el sistema operativo y ejecute unos comandos u otros según el que sea, que utilice ciertos archivos, ciertas variables, etc.
Un rol está compuesto de muchos include pero bien organizados.
La estructura sería la siguiente. Siendo "ejemplo" el nombre del rol. Como podemos ver hay diferentes carpetas, cada una especifica para su tarea y dentro del archivo main es donde escribimos el código. Podemos dejar vacíos los archivos si nos los utilizamos, incluso borrar las carpetas que no utilicemos ya que no afectaría al funcionamiento del rol.
Podemos crear la estructura manualmente, creando cada carpeta una a una o podemos utilizar directamente el siguiente comando que nos crearía la estructura anterior:
ansible-galaxy init ejemplo
Para añadir un rol a un playbook tan solo tenemos que añadirlo:
--- - hosts: pruebascomandos roles: - carpeta-del-rol ...
Pre_tasks
Una pre_task
no es más que una tarea normal. Solo que se ejecuta antes que las otras tareas.
No tiene nada de especial, se suele utilizar para hacer tests en el sistema o para organizar.
Por ejemplo si quieres actualizar el sistema y luego instalar Apache, sería el playbook así:
--- - hosts: pruebascomandos become: yes pre_tasks: - name: Update apt: update_cache=yes force_apt_get=yes tasks: - name: Install Apache apt: name=apache2 state=latest - name: Check Apache is running & start on boot service: name=apache2 state=started enabled=yes ...
Template
Este modulo de Ansible es muy similar al módulo COPY que hemos visto anteriormente en los comandos AD-HOC.
Ambos módulos sirven para transferir archivos desde nuestro local hacia los servidores. Pero tienen 2 grandes diferencias:
- Si utilizamos una ruta relativa:
- En el módulo COPY va a buscar ese archivo que le indiquemos a en la ruta files.
- En el módulo TEMPLATE va a buscar ese archivo que le indiquemos a en la ruta templates.
- Con el módulo TEMPLATE podemos utilizar Jinja2. Con esto podremos configurar nuestros servidores basándonos en variables.
Los archivos Jinja2 tienen terminación .j2
La estructura seria la siguiente. En la misma carpeta en la que tenemos nuestro playbook vamos a crear otra llamada templates. Y dentro creamos un archivo.
Dentro del archivo Jinja2 podemos utilizar tanto variables definidas por nosotros, por ejemplo variables para diferentes escenarios como producción o testing, como variables predefinidas de Ansible.
Y para añadirlo en nuestro playbook tan solo tenemos que añadir una tarea más con ese módulo:
- name: template file to remote host template: src: archivo-config.j2 dest: /tmp/archivo-config
Capítulo 6 - Los últimos retoques
Por ejemplo un último retoque es que te puedes encontrar otra manera de escribir las tareas de los playbooks. En vez el modelo clásico, similar a los comandos AD-HOC, desde la última actualización puedes encontrarlos de forma escalonada.
--- - hosts: pruebascomandos become: yes tasks: - name: Install Apache apt: name: apache2 state: latest - name: Check Apache is running & start on boot service: name: apache2 state: started enabled: yes ...
Es exactamente igual que hemos visto antes pero en vez todo en una línea utilizando el símbolo igual ( = ) se pone cada uno en una línea y con el símbolo dos puntos ( : ).
Capítulo FINAL
¿Terminé?
¿Ya soy un maestro de Ansible?
¡Pues aún no!
Ahora queda practicar mucho e investigar sobre un par de cosillas que aun no he incluido como son:
- blocks
- conditionals
- loops
- vault
- molecule
- tower
- cfg