Hace unas semanas, comencé a usar Ansible para simplificar las tareas administrativas de las múltiples organizaciones a las que apoyo. Además, quería especialmente simplificar la gestión de mi propia flota de ocho o nueve hosts (el recuento exacto cambia con frecuencia). He estado haciendo toda mi automatización usando scripts Bash desde que comencé a usar Linux. Utilicé scripts para automatizar la distribución de otros scripts de automatización de actualizaciones, archivos de configuración del usuario y del sistema, actualizaciones a versiones más recientes de Fedora y actualizaciones a nuevas versiones de Fedora. Y eso no incluye todas esas pequeñas tareas ad-hoc que surgen cada hora.
Los scripts seguirán desempeñando un papel esencial en mi automatización administrativa. Sin embargo, parece que Ansible puede hacerse cargo de muchas tareas y hacerlas mucho mejor que incluso los scripts complejos. Se trata del libro de jugadas , y en este artículo, creo uno que puede realizar una actualización del sistema teniendo en cuenta las diferencias del sistema.
Recientemente escribí sobre Mi primer día de uso de Ansible. Si no ha leído ese artículo, es posible que desee hacerlo antes de continuar con este. Este artículo asume que tiene una familiaridad muy básica con el uso de Ansible. Si ha leído mi artículo en el enlace anterior, debería poder seguir este texto sin dificultad.
Este artículo se divide en dos partes, así que asegúrese de leer la segunda mitad. En esta sección, definiremos algunos conceptos y términos importantes de Ansible, analizaremos los comentarios e implementaremos la primera jugada del libro de jugadas. La segunda parte continúa con las dos obras restantes, información de seguimiento y mi lista de recursos.
El libro de jugadas de este artículo no requiere la instalación de ningún módulo o colección de Ansible más allá de los integrados predeterminados. Este manual de estrategias se probó con Ansible 2.9.14.
[A los lectores también les gustó: Agregar un repositorio e instalar un paquete al estilo de Ansible]
¿Qué es un libro de jugadas?
Mientras escribía este artículo, también estaba viendo algunas sesiones del AnsibleFest virtual de este año. Mientras observaba, desarrollé mi propia descripción de un libro de jugadas, uno que tiene sentido para mí. Esta descripción contiene fragmentos de sabiduría del libro de jugadas de varios de los presentadores, así como algunos libros y publicaciones de blog que he leído.
Aquí está mi definición:
Un libro de jugadas de Ansible es una descripción creada por humanos del estado deseado de una o más computadoras. Ansible lee el libro de jugadas, compara el estado real de los equipos con el estado especificado en el libro de jugadas y realiza las tareas necesarias para que esos equipos se ajusten al estado descrito en el libro de jugadas.
Actualizaciones
La instalación de actualizaciones en los hosts Linux modernos es una tarea casi constante, que se vuelve importante por la cantidad de correcciones de seguridad y mejoras de funciones que surgen continuamente. Si se actualiza cierto software, como kernel, glibc o systemd, también se debe reiniciar el host. También es necesario realizar algunas tareas adicionales, como actualizar la base de datos de la página de manual.
Aunque tengo instalaciones de actualización automatizadas con un script genial, algunos de mis hosts deben ser tratados de manera un poco diferente a otros. Por ejemplo, no quiero actualizar mi firewall y mi servidor de correo electrónico/web/DHCP/DNS simultáneamente. Si el servidor se reinicia, el cortafuegos no puede obtener la información que necesita para continuar con sus propias actualizaciones, ni tampoco los otros hosts de mi red. Si el firewall falla, el acceso a los repositorios externos de Fedora se pierde en mi servidor y en todos los demás hosts internos. Eso significa esperar a que estos dos hosts se reinicien antes de que puedan comenzar las actualizaciones en los otros hosts.
Así que solía hacer esas actualizaciones iniciando los scripts en el firewall y luego esperando que terminara, luego pasaba al servidor y esperaba que terminara antes de ejecutar un pequeño programa de línea de comandos para ejecutar el script de actualización en secuencia en el resto de mis anfitriones. Podría haber escrito estas dependencias en mis scripts, pero mis primeros días con Ansible me demostraron que ya tiene esas capacidades y muchas más que harían mi tarea mucho más sencilla. Realmente, MUCHO más simple. Y más rápido en general, sin intervención mía.
La estrategia de Ansible
Ansible utiliza una estrategia de concentrador para administrar hosts. El software Ansible está instalado en el host que actúa como controlador. El software Ansible del lado del cliente no existe, por lo que no es necesario instalarlo en los hosts remotos.
Ansible usa SSH, que ya está instalado en casi todas las distribuciones de Linux, para comunicarse con hosts remotos. Aunque los administradores de sistemas pueden elegir usar contraseñas para el acceso remoto a los hosts, eso ciertamente reduce la eficiencia y la naturaleza de no intervención de una herramienta como Ansible. Entonces, como la mayoría de los otros administradores, uso pares de claves pública/privada (PPKP), que se considera más seguro que las contraseñas y permite la automatización de tareas para desde uno hasta miles de hosts remotos sin la intervención del administrador.
Ansible envía comandos a los hosts remotos a través de SSH y usa los resultados para determinar el éxito del comando. También puede usar esos resultados para determinar el siguiente curso de acción usando condicional cuando declaraciones.
Definir los requisitos
Al igual que cualquier programa, ya sea escrito en C, Python, Bash o cualquier otro lenguaje, siempre empiezo con un conjunto de requisitos. Ha leído mi libro, La filosofía de Linux para administradores de sistemas, ¿no es así? Esto también es cierto para herramientas como Ansible. Necesito definir a dónde voy para poder identificar cuándo he llegado.
Estos son los requisitos para mi libro de jugadas de Ansible:
Juego 1:Controlador Ansible
- Primero, instale las actualizaciones en el nodo de control de Ansible.
- Actualice la base de datos de la página man.
- Apague si es necesario. Esto es diferente para mi nodo de control que para los otros hosts debido a una placa base extraña que no se reinicia correctamente.
- Inicie sesión después de reiniciar y vuelva a ejecutar el libro de jugadas. Debido a que el nodo de control ya se encuentra en el estado deseado, no se realizarán más acciones y comenzará el Juego 2.
Jugada 2:Servidores
- Instala actualizaciones en los firewalls y servidores en serie, es decir, uno a la vez.
- Actualice la base de datos de la página man.
- Reiniciar si es necesario.
- Espere a que se reinicie el primer host, si es necesario, antes de comenzar con el siguiente.
Juego 3:Estaciones de trabajo
- No comience a actualizar las estaciones de trabajo hasta que se hayan completado los servidores.
- Instala actualizaciones en cada computadora que se ejecuta simultáneamente en paralelo.
- Actualice la base de datos de la página man.
- Reiniciar si es necesario.
Sí, sé que hay otras formas de hacer esto. Pensé en hacer el controlador Ansible al final para no tener que lidiar con reiniciar el libro de jugadas después de que el controlador se reinicie. Pero la forma en que hago las cosas es primero hacer actualizaciones en mi estación de trabajo principal, que también es mi nodo de control de Ansible, y luego hacer algunas pruebas antes de actualizar el resto de los sistemas, por lo que esta estrategia funciona perfectamente para eso. Sus necesidades probablemente difieran de las mías, por lo que debe usar cualquier método que funcione mejor para usted. Lo que pasa con Ansible es que es lo suficientemente flexible como para adaptarse a diferentes necesidades.
Ahora que tengo los requisitos para una tarea, puedo comenzar el libro de jugadas.
Sintaxis
Los playbooks de Ansible deben cumplir con la sintaxis y el formato estándar de YAML. Los errores más frecuentes que he encontrado son mis propios errores de formato. Esto generalmente se debe a que usé o no guiones iniciales según lo requerido, o usé la sangría incorrecta.
Los nombres de las jugadas comienzan en la columna uno del libro de jugadas, y cada tarea siguiente tiene una sangría de exactamente dos espacios . Exactamente dos espacios sangran cada acción en una tarea, y las subtareas tienen una sangría adicional de exactamente dos espacios. Cualquier otra cantidad de espacios o el uso de cualquier espacio en blanco que no sean espacios, como tabulaciones, generará un error de tiempo de ejecución. Los espacios en blanco adicionales al final de una línea también generan un error.
Cometerá errores de formato y aprenderá rápidamente a ver los problemas. Hay algunas herramientas que puedo usar para ayudarnos a localizar estos errores antes de intentar ejecutar libros de estrategias y pueden ahorrar mucho tiempo a largo plazo.
Comenzando el libro de jugadas
Entonces, comencemos un libro de jugadas que realizará esas tareas en la secuencia requerida. Los libros de jugadas son simplemente colecciones de tareas que definen el estado deseado de un host. Un nombre de host o grupo de inventario se especifica al principio del libro de jugadas y define los hosts en los que Ansible ejecutará el libro de jugadas.
Nuestro libro de jugadas contendrá tres jugadas para manejar cada tipo de host que identifiqué en la declaración de requisitos. Cada juego tendrá una lógica un poco diferente pero producirá el mismo resultado:uno o más hosts con todas las actualizaciones instaladas.
Mi libro de jugadas se llama doUpdates.yml
y se encuentra en /root/ansible/Updates
directorio, que creé para este proyecto. El programa Bash instalado por las obras de este manual se encuentra en /root/ansible/Updates/files
directorio.
Exploremos este libro de jugadas una sección a la vez.
Definiendo esto como un archivo YAML
Comienzo todo mi código con comentarios bien estructurados para que el nombre del archivo y una breve descripción de este libro de jugadas existan para mí o para algún otro administrador de sistemas en el futuro. Los libros de jugadas pueden contener comentarios, aunque he visto pocos artículos o libros que mencionen esto.
Como administrador de sistemas que cree en documentar todo, encuentro que los comentarios pueden ser muy útiles. No se trata tanto de decir las mismas cosas en los comentarios que digo en el nombre de la tarea, sino de identificar el propósito de los grupos de tareas y asegurarme de registrar mis razones para hacer ciertas cosas de cierta manera o pedido. Esto puede ayudar con la depuración de problemas en una fecha posterior cuando podría haber olvidado mi pensamiento original. Al igual que en Bash, los comentarios comienzan con # .
La función principal de esta primera sección son los tres guiones (--- ) que se utilizan para definir esto como un archivo YAML. El yml extensión en el nombre del archivo significa YAML. He visto un par de significados para eso, pero mi apuesta es "Otro lenguaje de marcado más", a pesar de que he visto algunas afirmaciones de que YAML no es uno.
########################################################################
# doUpdates.yml
#------------------------------------------------------------------
# This playbook installs all available RPM updates on the inventory hosts.
#
#
#------------------------------------------------------------------
#
# Change History
# Date Name Version Description
# 2020/10/01 David Both 00.00 Started new code
# 2020/10/10 David Both 01.00 First release code finished
# 2020/10/18 David Both 01.01 Minor changes to sequence and
# fix a couple minor problems.
#
########################################################################
---
La primera jugada
La siguiente sección define la primera jugada en el libro de jugadas. Los libros de jugadas pueden tener una o más jugadas, y la nuestra tiene tres:una para el host de control en el que se ejecuta Ansible, una para los dos servidores de mi red y otra para el resto de las estaciones de trabajo. A continuación, defino la primera jugada; después de todo, este es un libro de jugadas.
Observe que la obra comienza en la columna cero y luego hay una sangría estricta en las líneas restantes de la obra. Ninguna declaración define el comienzo de la obra. Ansible usa la estructura rígida YAML para determinar dónde comienza cada juego y tarea.
########################################################################
#######################################################################
# Play 1 - Do updates for host david
########################################################################
########################################################################
- name: Play 1 - Install updates on david - the Ansible controler
hosts: david
remote_user: root
vars:
run: false
reboot: false
Nos encontraremos con varias palabras clave con frecuencia, así que aquí hay algunas explicaciones que desearía tener cuando comencé a trabajar con Ansible.
nombre :Esta línea es el nombre de la reproducción, y el nombre de la reproducción se muestra en el flujo de datos STDOUT. Esto facilita la identificación de cada reproducción que se ejecuta para realizar un seguimiento mientras miro o veo la transmisión redirigida más tarde. La palabra clave es necesaria para cada jugada y tarea, pero el contenido del texto es opcional.
anfitriones :Esto define los nombres de host en los que se ejecutará la reproducción. Puede contener una lista de nombres de host separados por espacios o el nombre de un grupo de hosts. El grupo de hosts y los nombres de todos los hosts enumerados deben aparecer en el archivo de inventario. De forma predeterminada, es /etc/ansible/hosts
pero puede ser otro archivo siempre y cuando uses el -i
(--inventory
) opción para especificar el archivo alternativo.
usuario_remoto :esta línea no es un requisito, pero especifica el usuario que Ansible actuará como en el host remoto. Si el usuario del host remoto es el mismo que el del host local, esta línea no es necesaria. De forma predeterminada, Ansible usa el mismo ID de usuario en el host remoto que el usuario que ejecuta el libro de jugadas de Ansible. Lo uso aquí simplemente con fines informativos. Ejecuto la mayoría de los playbooks como root en el host local, por lo que Ansible inicia sesión en el host remoto como root.
vars :Esta sección se puede utilizar para definir una o más variables, que se pueden utilizar como en cualquier lenguaje de programación. En este caso, los uso en declaraciones condicionales "cuando" más adelante en el libro de jugadas para controlar la ruta de ejecución.
El alcance de las variables se limita a la sección en la que se definen. En este caso, se definen en la Jugada 1, por lo que se limitan a esa jugada. Si quiero usarlos en jugadas posteriores, tendré que configurarlos nuevamente en cada jugada en la que sean necesarios. Si se establece una variable en una tarea, solo estará disponible dentro de esa tarea y no en el resto de ese juego.
Los valores de las variables se pueden anular en la línea de comando usando -e
(--extra_variables
) opción para especificar un valor diferente. Lo veremos cuando sea el momento de ejecutar el libro de jugadas.
Las tareas
Este es el comienzo de la sección de tareas para Play 1. La tarea :la palabra clave tiene una sangría de exactamente dos espacios. Cada tarea debe tener un nombre declaración, incluso si no hay texto para el nombre. El texto hace que sea más fácil seguir la lógica del libro de jugadas y se muestra en la pantalla durante la ejecución para ayudarme mientras sigo el progreso en tiempo real.
tasks:
########################################################################
# Do some preliminary checking
########################################################################
- name: Install the latest version of the doUpdates script
copy:
src: /root/ansible/Updates/files/doUpdates
dest: /usr/local/bin
mode: 0774
owner: root
group: root
- name: Check for currently available updates
command: doUpdates -c
register: check
- debug: var=check.stdout_lines
Esta primera sección contiene tres tareas. La primera tarea copia un programa Bash que escribí en el host de destino. El segundo ejecuta el programa recién instalado y asigna, registra, el flujo de datos STDOUT de doUpdates programa a la variable "check". La tercera tarea imprime todas las líneas STDOUT en la variable de verificación en la pantalla.
Veamos las nuevas palabras clave con un poco más de detalle:
copiar :la palabra clave copy define el comienzo de una estrofa que puede copiar uno o más archivos desde una ubicación de origen específica (src ) a una ubicación de destino específica (dest ). Las palabras clave de esta sección definen varios aspectos de la operación de copia y el estado final del archivo copiado.
origen :esta es la ruta completa y el nombre del archivo que se va a copiar. En este caso, solo voy a copiar un solo archivo, pero es fácil copiar todos los archivos en un directorio o solo aquellos que coinciden con un patrón global de archivos. El archivo de origen generalmente se almacena en una ubicación en el árbol de directorios del concentrador de Ansible. En este caso, la ruta completa a mi archivo de origen se encuentra en /root/ansible/Updates/files/doUpdates
.
destino :Esta es la ruta de destino en los hosts de destino en los que se copiará el archivo de origen.
modo :La palabra clave mode define el modo de archivo que se aplicará al archivo copiado. Independientemente del modo de archivo del archivo de origen, Ansible establecerá el modo de archivo en el especificado en esta declaración. Por ejemplo, rwxr_xr__ o 0754 . Asegúrese de utilizar los cuatro bytes cuando utilice el formato octal.
propietario :Esta es la cuenta del propietario que se aplicará al archivo.
grupo :Esta es la cuenta de grupo que se aplicará al archivo.
comando :cualquier comando de shell de Linux, script de shell o programa de línea de comandos junto con opciones y argumentos se pueden usar con esta palabra clave. Utilicé el programa Bash que acabo de instalar para obtener información que no se puede obtener fácilmente con las funciones integradas de Ansible, como dnf
.
registrarse :esta palabra clave establece el STDOUT del comando especificado anteriormente en una variable llamada "verificar". El cuándo: palabra clave puede consultar el contenido de esta variable. Luego se usa como condicional para determinar si se realizará la tarea de la que forma parte. Veremos esto en la siguiente sección.
depurar :Imprime el contenido de la variable especificada en la pantalla. Frecuentemente uso esto como una herramienta de depuración. Encuentro esto útil en la depuración. Pista, pista.
Ahora un poco sobre mis doUpdates Programa Bash.
Originalmente escribí este programa Bash para hacer las actualizaciones que ahora comencé a hacer con Ansible. Contiene algún código que determina si hay actualizaciones disponibles. También determina si el kernel, systemd o glibc han sido actualizados, cualquiera de los cuales debería requerir un reinicio para tener pleno efecto. Mi programa emite un par de líneas a STDOUT que puedo usar en Ansible como condicional para decidir si reinicio el host de destino. Lo uso en la siguiente sección, que realiza las actualizaciones reales, y la siguiente realiza un apagado de mi estación de trabajo principal. Un código similar realiza un reinicio en todos los demás hosts, como verá.
El STDOUT de este programa usado con -c
La opción se ve así cuando hay actualizaciones disponibles, pero no es necesario reiniciar. Puedo usar una expresión regular para buscar cadenas clave en cualquier parte del texto de este flujo de datos, que se pueden usar en un cuando :condicional para determinar si se realiza una tarea específica.
TASK [debug] ******************************************************************************************************************************************
ok: [wally1] => {
"check.stdout_lines": [
"########## 48 updates ARE available for host wally1.both.org. ##########",
"########## Including: ##########",
"Last metadata expiration check: 1:47:12 ago on Tue 20 Oct 2020 01:50:07 PM EDT.",
"Updates Information Summary: available",
" 3 Security notice(s)",
" 2 Moderate Security notice(s)",
" 3 Bugfix notice(s)",
" 2 Enhancement notice(s)",
" 2 other notice(s)",
"########## A reboot will NOT be required after these updates are installed. ##########",
"Program terminated normally"
]
}
La siguiente sección inmediatamente anterior realiza las actualizaciones reales si todos los condicionales en el cuando :afirmación son verdaderas. Esta sección utiliza el dnf
integrado de Ansible administrador de paquetes.
########################################################################
# Do the updates.
########################################################################
# Install all available updates
- name: Install all current updates
dnf:
name: "*"
state: latest
when: (check.stdout | regex_search('updates ARE available')) and run == "true"
dnf :llama al Ansible incorporado que interactúa con el administrador de paquetes DNF. Aunque un poco limitado en sus capacidades, puede instalar, eliminar y actualizar paquetes. Una de las limitaciones del módulo DNF es que no tiene el check-update
función. Por lo tanto, sigo usando mi programa Bash para descubrir la lista de paquetes que se actualizarán y, a partir de ahí, determinar si es necesario reiniciar (o apagar). Ansible también tiene integrados YUM y APT.
nombre :proporciona el nombre del paquete en el que operar. En este caso, el carácter global del archivo * denota todos los paquetes instalados.
estado :El valor "más reciente" para esta palabra clave indica que todos los paquetes instalados deben actualizarse a la versión más reciente. Algunas de las otras opciones de estado son "presente", lo que significa que el paquete está instalado pero no necesariamente la última versión, y "ausente", lo que significa eliminar el paquete si está instalado.
cuando :esta frase condicional especifica las condiciones que se deben cumplir para que se ejecute esta tarea. En este caso, las actualizaciones solo se instalarán cuando la cadena de texto definida en la expresión regular esté presente en la variable "verificar" que se registró previamente, y la variable "ejecutar" esté establecida en "verdadero".
Ahora que se han realizado las actualizaciones, es posible que deba reiniciar, así que veamos cómo puedo lidiar con eso. La siguiente tarea lo hace por nosotros.
Primero, tengo un poco de documentación a través de comentarios, que describe que apagué en lugar de reiniciar este host debido a un posible problema de hardware. Este es un ejemplo perfecto de por qué debemos incluir comentarios en nuestro código y libros de jugadas porque explican por qué se necesita este juego en particular y por qué es diferente de los demás. También es un gran ejemplo de cómo puedo tratar a un host de manera diferente a los demás.
########################################################################
# Now poweroff host david because of MB problems that won't let it
# do a reboot without manual intervention. Need to see if I
# can figure out this problem and fix it but it is a hardware issue
# and this is just a temporary circumvention.
########################################################################
- name: Poweroff this host if necessary and reboot extra variable is true
command: poweroff
when: (check.stdout | regex_search('reboot will be required')) and reboot == "true" and run == "true"
En esta tarea, envío el poweroff
comando en lugar de la acción preferida de reiniciar la computadora. Hago esto por el motivo indicado en los comentarios:porque la placa base de mi estación de trabajo principal, que también es mi concentrador Ansible, no se reinicia correctamente. Esto probablemente se deba a una mala configuración de mi parte más que a cualquier tipo de mal funcionamiento. Todavía no he descubierto el motivo porque encuentro que el tiempo que ya he dedicado a buscar y hacer cambios en la configuración del BIOS ha excedido mi límite de tolerancia, y necesito hacer el trabajo. De vez en cuando, trabajo un poco más en ello, pero ya no vale la pena el tiempo extra.
La ejecución del libro de jugadas se detiene después de que se apague (o se reinicie si su dispositivo Ansible hub se reinicia correctamente), por lo que debo reiniciarlo después de que finalmente vuelva a funcionar. Esta vez, debido a que se han instalado las actualizaciones, no se produce el apagado ni el reinicio y se ejecuta la siguiente reproducción.
Y esto concluye la primera jugada.
[ ¿Necesita más información sobre Ansible? Realice un curso gratuito de descripción técnica de Red Hat. Ansible Essentials:descripción técnica de la simplicidad en la automatización. ]
Conclusión
Cubrimos mucha información aquí y espero que una explicación sólida de las palabras clave y las tareas haya sido útil. También está claro cuál es mi opinión sobre los comentarios:son críticos. Play 1 pone en marcha nuestro libro de jugadas de Ansible.
En la segunda parte de este artículo, concluiremos el libro de jugadas con dos jugadas adicionales para administrar el firewall y los servidores, y luego el resto de los hosts en la red. También proporcionaré algunos conceptos y detalles de seguimiento.