Escribir funciones de Ansible con confianza


Ha estado automatizando sus tareas repetitivas de administrador de sistemas con Ansible desde hace un tiempo. Has rebotado servicios problemáticos, implementado objetos en Kubernetes, actualizado sistemas y realizado reinicios continuos. Tal vez incluso haya implementado y configurado servicios usando roles que encontró en galaxia ansible. Sin embargo, finalmente sucedió. No puede encontrar una función en Ansible Galaxy que haga lo que desea (lo comprobó, ¿verdad?), o se le ha asignado la tarea de escribir una función para la aplicación de su organización. Cualquiera que sea la razón, es hora de que escribas tu propio papel. ¿Cómo hace eso de una manera en la que puede estar seguro de que su rol funciona según lo previsto? Esta publicación responderá a esa pregunta al brindar orientación sobre cómo comenzar a desarrollar mejor los roles de Ansible.

Infraestructura como código y DevOps

Antes de sumergirnos en detalles, sería útil definir alguna terminología. Ansible cae bajo el infraestructura como código (IaC) paraguas de herramientas IaC es el proceso de administrar y aprovisionar recursos de TI a través de archivos de definición legibles por máquina. Este enfoque permite almacenar la configuración de la infraestructura en git, obteniendo todos los beneficios de hacerlo, incluidas las políticas de ramificación, historial, revisión y aprobación, and so forth.

DevOps es el conjunto de prácticas que combina el desarrollo de software program (dev) y las operaciones de TI (ops) para acortar el ciclo de vida del desarrollo y proporcionar una entrega continua de software program. Las herramientas de IaC son una pieza del rompecabezas que permite a las organizaciones adoptar un enfoque DevOps. El proceso DevOps se representa comúnmente de la siguiente manera:

13429_ILL_DevOpsLoop

Figura 1: El bucle infinito de DevOps.

Es útil tener este proceso en mente al desarrollar sus roles de Ansible, porque como software program también pueden beneficiarse de un enfoque DevOps.

Funciones de Ansible

En Ansible, los roles son un método para cargar automáticamente determinadas variables, tareas, archivos, plantillas y controladores en función de una estructura de archivos conocida. Agrupar contenido por roles permite compartir y reutilizar fácilmente. el ansible documentación on roles describe la estructura del archivo y otras consideraciones.

Al desarrollar roles, deberá lidiar con varias inquietudes, incluidos los sistemas operativos y las versiones que admitirá y si solo necesita un solo nodo o si tiene que apuntar a un grupo de máquinas. A menudo, también es importante comenzar desde un estado nuevo cada vez que vuelva a ejecutar su rol mientras lo desarrolla para asegurarse de que (1) sus roles se completen correctamente en su primera ejecución y (2) los cambios realizados en ejecuciones anteriores no afecten el resultado. . También debe verificar que su rol sea idempotente para asegurarse de que, sin importar cuántas veces se ejecute, obtenga el mismo resultado. También es importante verificar que las cosas solo deben cambiarse si es necesario cambiarlas. Por ejemplo, un servicio solo debe reiniciarse si los cambios de configuración justifican un reinicio.

Lo último a considerar es cómo verificar que su rol haya hecho lo que pretendía que hiciera. Iniciar sesión en un nodo de destino y verificar manualmente es sin duda una forma de hacerlo. Sin embargo, es mejor escribir pruebas que se puedan ejecutar automáticamente después de su rol de Ansible para verificar el estado actual.

Para automatizar este tipo de pruebas, necesitará un host de destino (o un conjunto de hosts) y deberá destruir y volver a crear ese host (o conjunto de hosts) constantemente durante el proceso de desarrollo. También será responsable de administrar las conexiones al host (o hosts) en uno de los servidores compatibles con Ansible. métodos. Además, debe pasar a la herramienta de prueba elegida y manejar su conexión con los nodos. Administrar esta infraestructura de desarrollo y prueba puede ser tedioso y consumirá mucho tiempo que podría dedicarse mejor a las características de los roles.

Introducir molécula

Molécula es un proyecto para facilitar el desarrollo y la prueba de roles de Ansible mediante el manejo del conjunto de inquietudes descrito anteriormente y la simplificación de todo el proceso de desarrollo de roles. Molécula de emparejamiento con Estibador ya que su aprovisionador le permite desarrollar rápida y fácilmente sus roles contra cualquier cantidad de sistemas operativos y versiones recién implementadas simultáneamente. Molecule también tiene verificación de idempotencia incorporada y soporte para una variedad de métodos de prueba de verificación.

Para comenzar, primero instale Estibador. Entonces suponiendo que tienes pip3instale Molecule y las dependencias de soporte:

pip3 set up yamllint ansible molecule(docker) docker pytest-testinfra

Con Molecule y sus dependencias instaladas, es hora de comenzar a desarrollar un rol de Ansible. Molecule puede ayudar aquí construyendo la estructura de archivos de su rol y los propios archivos de configuración necesarios de Molecule para usted:

$ molecule init function maheckathorn.instance -d docker
$ tree
.
├── README.md
├── defaults
│ └── predominant.yml
├── recordsdata
├── handlers
│ └── predominant.yml
├── meta
│ └── predominant.yml
├── molecule
│ └── default
│      ├── converge.yml
│      ├── molecule.yml
│      └── confirm.yml
├── duties
│ └── predominant.yml
├── templates
├── checks
│ ├── stock
│ └── check.yml
└── vars
└── predominant.yml
10 directories, 11 recordsdata

Dentro de Carpeta de moléculaslos siguientes archivos tienen propósitos específicos:

  • converge.yml es el archivo del libro de jugadas que contiene la llamada para su rol. Molecule invocará este libro de jugadas con ansible-playbook y ejecútelo contra una instancia creada por el controlador, que es Docker en nuestro escenario.
  • molecule.yml es el punto de entrada de configuración central para Molecule. Con este archivo, puede configurar cada herramienta que Molecule empleará al probar su rol.
  • confirm.yml es el archivo Ansible utilizado para la prueba ya que Ansible es el predeterminado verificador, que le permite escribir pruebas específicas contra el estado del contenedor después de que su función haya terminado de ejecutarse. Hay otras herramientas de verificación disponibles (tenga en cuenta que TestInfra period el verificador predeterminado antes de la versión 3 de Molecule).

El molecule.yml El archivo contiene diferentes secciones para configurar cómo se comportan los componentes de la molécula:

  • El dependencia gerente—Usos de las moléculas Galaxia por defecto para resolver las dependencias de su rol.
  • El conductor proveedor. Usos de moléculas Estibador por defecto. Molecule usa el controlador para delegar la tarea de crear instancias.
  • El hilas dominio-Molecule puede llamar a comandos externos para garantizar que se fomenten las mejores prácticas. Nota: Ansible-lint no está incluido con la molécula o la molécula (pelusa).
  • El plataformas definiciones—Molecule se basa en esto para saber qué instancias crear y nombrar, e identificar a qué grupo pertenece cada instancia. Si necesita probar su rol en varias distribuciones populares (CentOS, Fedora, Debian), puede especificarlo en esta sección.
  • El proveedorMolecule solo proporciona un aprovisionador de Ansible. Ansible gestiona el ciclo de vida de la instancia en función de esta configuración.
  • El guión definición—Molecule se basa en esta configuración para controlar el orden de secuencia del escenario.
  • El verificador estructura—Molecule usa Ansible de forma predeterminada para proporcionar una forma de escribir pruebas de verificación de estado específicas (como pruebas de humo de implementación) en la instancia de destino.

Hay muchas opciones para configurar estas secciones para satisfacer sus necesidades. Sin embargo, ceñirse a un archivo de configuración común en todos los proyectos ayuda a establecer expectativas estándar. Lo siguiente se basa en El común de Jeff Geerling molecule.yml archivo:

https://github.com/cmu-sei/ansible-role-silk/blob/grasp/molecule/default/molecule.yml

---
dependency:
  title: galaxy
driver:
  title: docker
platforms:
  - title: occasion
    picture: "geerlingguy/docker-${MOLECULE_DISTRO:-centos7}-ansible:newest"
    command: ${MOLECULE_DOCKER_COMMAND:-""}
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    privileged: true
    pre_build_image: true
    env:
      http_proxy: "${http_proxy}"
      https_proxy: "${https_proxy}"
      no_proxy: "${no_proxy} "  
provisioner:
  title: ansible
  playbooks:
    converge: ${MOLECULE_PLAYBOOK:-converge.yml}
verifier:
  title: testinfra
  choices:
    v: 1

La clave a tener en cuenta en este archivo es el uso de Contenedor(es) Docker de Jeff Geerling como fuente de imagen, la configuración de Testinfra como verificador, y la variable de entorno MOLECULE_DISTRO con centos7 como predeterminado. Las imágenes de Docker prefabricadas personalizadas ya contienen Python, Ansible y systemd. Ayudan a acelerar las ejecuciones de prueba al no necesitar que Molecule haga nada para usar la imagen más que buscarla. La variable de entorno MOLECULE_DISTRO le permite probar fácilmente con otros tipos y versiones de SO al:

$ MOLECULE_DISTRO=ubuntu1804 molecule check

Se enumeran otras imágenes prediseñadas aquí.

Finalmente, el verificador Testinfra configura Molecule para usar Testinfra para las pruebas de verificación, que period el valor predeterminado antes de la versión 3 de la molécula. Si ha estado desarrollando roles con pruebas de verificación durante un tiempo, es útil poder configurar esta configuración, lo que significa el directorio de pruebas que crea la molécula no es necesario. También puede editar su archivo converge.yml para que tenga el siguiente aspecto:

https://github.com/cmu-sei/ansible-role-silk/blob/grasp/molecule/default/converge.yml

---
- title: Converge
  hosts: all
  roles:
    - function: "{ basename }"
  setting:
    http_proxy: "{{ lookup('env', 'http_proxy') }}"
    https_proxy: "{{ lookup('env', 'https_proxy') }}"
    no_proxy: "{{ lookup('env', 'no_proxy') }}"

Esta configuración ayuda a evitar problemas en integración continua/implementación continua (CI/CD) y también se ocupa de los problemas de espacio de nombres del proyecto Ansible.

Con Molecule configurado, podemos ejecutar el escenario de Molecule predeterminado completo, que es un conjunto de pruebas para su nuevo rol:

$ molecule check
INFO     default situation check matrix: dependency, lint, cleanup, destroy, syntax, create, put together, converge, idempotence, side_effect, confirm, cleanup, destroy
INFO     Performing prerun...
INFO     Set ANSIBLE_LIBRARY=/Customers/maheckathorn/.cache/ansible-compat/50d858/modules:/Customers/maheckathorn/.ansible/plugins/modules:/usr/share/ansible/plugins/modules
INFO     Set ANSIBLE_COLLECTIONS_PATH=/Customers/maheckathorn/.cache/ansible-compat/50d858/collections:/Customers/maheckathorn/.ansible/collections:/usr/share/ansible/collections
INFO     Set ANSIBLE_ROLES_PATH=/Customers/maheckathorn/.cache/ansible-compat/50d858/roles:/Customers/maheckathorn/.ansible/roles:/usr/share/ansible/roles:/and so forth/ansible/roles
INFO     Utilizing /Customers/maheckathorn/.cache/ansible-compat/50d858/roles/maheckathorn.instance symlink to present repository in an effort to allow Ansible to search out the function utilizing its anticipated full title.
INFO     Operating default > dependency
WARNING  Skipping, lacking the necessities file.
WARNING  Skipping, lacking the necessities file.
INFO     Operating default > lint
INFO     Lint is disabled.
INFO     Operating default > cleanup
WARNING  Skipping, cleanup playbook not configured.
INFO     Operating default > destroy
INFO     Sanity checks: 'docker'
 
PLAY (Destroy) *****************************************************************
 
TASK (Destroy molecule occasion(s)) ********************************************
modified: (localhost) => (merchandise=occasion)
 
TASK (Wait for example(s) deletion to finish) *******************************
FAILED - RETRYING: (localhost): Wait for example(s) deletion to finish (300 retries left).
okay: (localhost) => (merchandise=occasion)
 
TASK (Delete docker networks(s)) ***********************************************
 
PLAY RECAP *********************************************************************
localhost                  : okay=2    modified=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
 
INFO     Operating default > syntax
 
playbook: /Customers/maheckathorn/check/instance/molecule/default/converge.yml
INFO     Operating default > create
 
PLAY (Create) ******************************************************************
 
TASK (Log right into a Docker registry) **********************************************
skipping: (localhost) => (merchandise=None)
skipping: (localhost)
 
TASK (Examine presence of customized Dockerfiles) ************************************
okay: (localhost) => (merchandise={'command': '', 'env': '', 'picture': 'geerlingguy/docker-centos7-ansible:newest', 'title': 'occasion', 'pre_build_image': True, 'privileged': True, 'volumes': ('/sys/fs/cgroup:/sys/fs/cgroup:ro')})
 
TASK (Create Dockerfiles from picture names) *************************************
skipping: (localhost) => (merchandise={'command': '', 'env': '', 'picture': 'geerlingguy/docker-centos7-ansible:newest', 'title': 'occasion', 'pre_build_image': True, 'privileged': True, 'volumes': ('/sys/fs/cgroup:/sys/fs/cgroup:ro')})
 
TASK (Uncover native Docker photos) ********************************************
okay: (localhost) => (merchandise={'modified': False, 'skipped': True, 'skip_reason': 'Conditional consequence was False', 'merchandise': {'command': '', 'env': '', 'picture': 'geerlingguy/docker-centos7-ansible:newest', 'title': 'occasion', 'pre_build_image': True, 'privileged': True, 'volumes': ('/sys/fs/cgroup:/sys/fs/cgroup:ro')}, 'ansible_loop_var': 'merchandise', 'i': 0, 'ansible_index_var': 'i'})
 
TASK (Construct an Ansible appropriate picture (new)) *********************************
skipping: (localhost) => (merchandise=molecule_local/geerlingguy/docker-centos7-ansible:newest)
 
TASK (Create docker community(s)) ************************************************
 
TASK (Decide the CMD directives) ********************************************
okay: (localhost) => (merchandise={'command': '', 'env': '', 'picture': 'geerlingguy/docker-centos7-ansible:newest', 'title': 'occasion', 'pre_build_image': True, 'privileged': True, 'volumes': ('/sys/fs/cgroup:/sys/fs/cgroup:ro')})
 
TASK (Create molecule occasion(s)) *********************************************
modified: (localhost) => (merchandise=occasion)
 
TASK (Wait for example(s) creation to finish) *******************************
FAILED - RETRYING: (localhost): Wait for example(s) creation to finish (300 retries left).
modified: (localhost) => (merchandise={'failed': 0, 'began': 1, 'completed': 0, 'ansible_job_id': '429858788464.21737', 'results_file': '/Customers/maheckathorn/.ansible_async/429858788464.21737', 'modified': True, 'merchandise': {'command': '', 'env': '', 'picture': 'geerlingguy/docker-centos7-ansible:newest', 'title': 'occasion', 'pre_build_image': True, 'privileged': True, 'volumes': ('/sys/fs/cgroup:/sys/fs/cgroup:ro')}, 'ansible_loop_var': 'merchandise'})
 
PLAY RECAP *********************************************************************
localhost                  : okay=5    modified=2    unreachable=0    failed=0    skipped=4    rescued=0    ignored=0
 
INFO     Operating default > put together
WARNING  Skipping, put together playbook not configured.
INFO     Operating default > converge
 
PLAY (Converge) ****************************************************************
 
TASK (Gathering Information) *********************************************************
okay: (occasion)
 
PLAY RECAP *********************************************************************
occasion                   : okay=1    modified=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
 
INFO     Operating default > idempotence
 
PLAY (Converge) ****************************************************************
 
TASK (Gathering Information) *********************************************************
okay: (occasion)
 
PLAY RECAP *********************************************************************
occasion                   : okay=1    modified=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
 
INFO     Idempotence accomplished efficiently.
INFO     Operating default > side_effect
WARNING  Skipping, aspect impact playbook not configured.
INFO     Operating default > confirm
WARNING  Skipping, no checks discovered.
INFO     Operating default > cleanup
WARNING  Skipping, cleanup playbook not configured.
INFO     Operating default > destroy
 
PLAY (Destroy) *****************************************************************
 
TASK (Destroy molecule occasion(s)) ********************************************
modified: (localhost) => (merchandise=occasion)
 
TASK (Wait for example(s) deletion to finish) *******************************
FAILED - RETRYING: (localhost): Wait for example(s) deletion to finish (300 retries left).
modified: (localhost) => (merchandise=occasion)
 
TASK (Delete docker networks(s)) ***********************************************
 
PLAY RECAP *********************************************************************
localhost                  : okay=2    modified=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
 
INFO     Pruning additional recordsdata from situation ephemeral listing

Ya que mostramos una gran cantidad de resultados arriba, analicemos qué cosas interesantes están sucediendo aquí. Inmediatamente después de ejecutar la prueba Molecule, obtenemos un resultado que nos indica qué pasos se ejecutarán en el proceso de prueba:

INFO     default situation check matrix: dependency, lint, cleanup, destroy, syntax, create, put together, converge, idempotence, side_effect, confirm, cleanup, destroy

Como muestra este resultado, de forma predeterminada, Molecule ejecuta estos pasos como parte de la matriz de prueba en el orden que se muestra. Cada vez que vemos un

INFO     Operating default >

en la salida, estamos viendo un paso diferente en la matriz que se está ejecutando. Si examina la salida, verá que muchos de los pasos se omiten de forma predeterminada. Por ejemplo:

INFO     Operating default > dependency
WARNING  Skipping, lacking the necessities file.

En nuestro ejemplo, el primer paso en la matriz donde Molécula realmente hace algo es el paso de destrucción. En este paso, Molecule interactúa con el controlador configurado, en nuestro caso Docker, e intenta destruir cualquier entorno de prueba anterior para garantizar que se utilice un nuevo entorno de prueba limpio. La molécula interactúa con el Demonio acoplable y destruye cualquier contenedor en ejecución con nuestro nombre definido de nuestro molecule.yml archivo:

platforms:
- title: occasion

Si un contenedor en ejecución con ese nombre no existe actualmente, como en nuestro caso, simplemente continúa. El siguiente paso en el que Molecule realmente hace algo es el paso de creación. En este punto del proceso, la molécula interactúa con el controlador e intenta crear un entorno de prueba utilizando el controlador que le indicamos y configuramos de la manera descrita en la sección de la plataforma de la molécula.yml:

driver:
  title: docker
platforms:
  - title: occasion
    picture: "geerlingguy/docker-${MOLECULE_DISTRO:-centos7}-ansible:newest"
    command: ${MOLECULE_DOCKER_COMMAND:-""}
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    privileged: true
    pre_build_image: true
    env:
      http_proxy: "${http_proxy}"
      https_proxy: "${https_proxy}"
      no_proxy: "${no_proxy} "

Dado que usamos Docker, Molecule maneja la extracción de la imagen del contenedor que definimos, establece las opciones de tiempo de ejecución de Docker y ejecuta el contenedor en segundo plano. Las siguientes líneas muestran la creación exitosa de nuestro entorno de prueba deseado:

TASK (Wait for example(s) creation to finish) *******************************
FAILED - RETRYING: (localhost): Wait for example(s) creation to finish (300 retries left).
modified: (localhost) => (merchandise={'failed': 0, 'began': 1, 'completed': 0, 'ansible_job_id': '429858788464.21737', 'results_file': '/Customers/maheckathorn/.ansible_async/429858788464.21737', 'modified': True, 'merchandise': {'command': '', 'env': '' '}, 'picture': 'geerlingguy/docker-centos7-ansible:newest', 'title': 'occasion', 'pre_build_image': True, 'privileged': True, 'volumes': ('/sys/fs/cgroup:/sys/fs/cgroup:ro')}, 'ansible_loop_var': 'merchandise'})

Con nuestro entorno de prueba ahora en su lugar, Molecule pasa a ejecutar el paso de convergencia del proceso, que ejecuta convenientemente el libro de jugadas llamado converge.yml que definimos anteriormente. Este libro de jugadas ejecuta nuestro papel. A partir de ahora, nuestro rol no hace nada, como muestra este resultado:

INFO     Operating default > converge
 
PLAY (Converge) ****************************************************************
 
TASK (Gathering Information) *********************************************************
okay: (occasion)
 
PLAY RECAP *********************************************************************
occasion                   : okay=1    modified=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Sin embargo, lo que esto muestra es que Molecule pudo conectarse con éxito a nuestro entorno de prueba. Inmediatamente después de un paso de convergencia exitoso, Molecule prueba automáticamente nuestro papel para la idempotencia. Esto consiste en volver a ejecutar nuestro libro de jugadas converge.yml y asegurarse de que no se haya cambiado nada.

Si hubiéramos definido las pruebas de Testinfra, el paso de verificación las habría ejecutado:

INFO     Operating default > confirm
WARNING  Skipping, no checks discovered.

Un ejemplo de código Testinfra easy se puede ver en el Repositorio GitHub de Ansible SiLK:

import os
 
import testinfra.utils.ansible_runner
 
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
    os.environ('MOLECULE_INVENTORY_FILE')).get_hosts('all')
 
 
def test_silk_version(host):
    model = "3.19.2"
    command = """/usr/native/bin/silk_config --silk-version"""
 
    cmd = host.run(command)
 
    assert model in cmd.stdout

En este caso, Molecule ejecutaría este código de Python en el host de Docker y Testinfra se encargaría de conectarse al entorno de prueba, ejecutar las pruebas y devolver la salida a la molécula. La prueba que estamos ejecutando simplemente comprueba si la versión de Seda instalado en el entorno de prueba es 3.19.2. Si nuestras pruebas pasan, Molecule considera que el paso de verificación fue un éxito y continúa. Lo último que hace Molecule durante una ejecución de prueba es limpiarse volviendo a ejecutar el paso de destrucción.

Automatización de la confianza

Como se destaca en nuestro ejemplo anterior, Molecule es capaz de optimizar su proceso de desarrollo de funciones de Ansible. Se pone de pie y derriba entornos de prueba configurables rápida y fácilmente y maneja pruebas de idempotencia y verificación. Sin embargo, esta publicación de weblog solo araña la superficie de lo que Molecule es capaz de hacer.

Por ejemplo, manejar un entorno de prueba en clúster es muy sencillo simplemente agregando otra instancia con nombre a la sección de la plataforma del molecule.yml archivo. La prueba contra diferentes sistemas operativos y diferentes versiones del sistema operativo también es un easy ajuste de comando. Agregar preparaciones a los nodos de prueba que, por una razón u otra, deben ocurrir fuera del rol es easy mediante la inclusión del paso de preparación (agregando un put together.yml libro de jugadas). También es fácil agregar dependencias de roles creando un necessities.yml archivo en el directorio Molécula.

Finalmente, todo el proceso es easy para pasar a un sistema CI/CD. El ci.yml en el repositorio de Ansible SiLK muestra cómo hacer esto con las acciones de Github, pero el proceso es lo suficientemente portátil como para recrearlo fácilmente usando la plataforma de CI/CD de su elección. Si no utiliza Molecule para desarrollar sus funciones de Ansible, es posible que esté ralentizando considerablemente su cadencia de desarrollo y reduciendo la calidad de su código de Ansible. Escribir roles de Ansible con la ayuda de Molecule hace que sea muy possible que pueda estar seguro de que su rol hace lo que quiere, lo que genera un código de mejor calidad y scale back la frustración del usuario.

Related Articles

Comments

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Same Category

spot_img

Stay in touch!

Follow our Instagram