Cómo probar la implementación de Ansible con InSpec y Kitchen

El autor seleccionó el Fondo de Diversidad en Tecnología para recibir una donación como parte del programa Write for DOnations.
Introducción
InSpec es un marco de auditoría y pruebas automatizadas de código abierto que se utiliza para describir y probar problemas, recomendaciones o requisitos normativos. Está diseñado para ser legible por humanos y no depende de ninguna plataforma. Los desarrolladores pueden trabajar con InSpec localmente o mediante SSH, WinRM o Docker para ejecutar pruebas, por lo que no es necesario instalar ningún paquete en la infraestructura que se está probando.
Aunque con InSpec puedes ejecutar pruebas directamente en tus servidores, existe la posibilidad de que se produzcan errores humanos que podrían causar problemas en tu infraestructura. Para evitar este escenario, los desarrolladores pueden usar Kitchen para crear una máquina virtual e instalar un sistema operativo de su elección en las máquinas donde se ejecutan las pruebas. Kitchen es un ejecutor de pruebas, o una herramienta de automatización de pruebas, que te permite probar el código de infraestructura en una o más plataformas aisladas. También es compatible con muchos marcos de prueba y es flexible con una arquitectura de complemento de controlador para varias plataformas como Vagrant, AWS, DigitalOcean, Docker, contenedores LXC, etc.
En este tutorial, escribirás pruebas para tus playbooks de Ansible ejecutándose en un Droplet de DigitalOcean Ubuntu 18.04. Usarás Kitchen como ejecutor de pruebas e InSpec para escribir las pruebas. Al finalizar este tutorial, podrás probar la implementación de tu playbook de Ansible.
Prerrequisitos
Antes de comenzar con esta guía, necesitará una cuenta de DigitalOcean además de lo siguiente:
- Una instalación local
Ruby
en su máquina. Puede instalar Ruby siguiendo el tutorial correspondiente a su distribución en la serie: Cómo instalar y configurar un entorno de programación local para Ruby. - Chef Development Kit (ChefDK) instalado en su máquina.
- Las claves SSH se configuran en su máquina siguiendo los pasos 1 y 2 de Cómo configurar claves SSH. Para cargar su clave pública SSH en su cuenta de DigitalOcean, puede seguir nuestro tutorial Cómo agregar claves SSH a una cuenta de DigitalOcean.
- Un token de acceso personal de lectura y escritura de DigitalOcean. Asegúrese de registrar el token en un lugar seguro; lo usará más adelante en este tutorial. Esto le permite crear un Droplet en DigitalOcean, que es donde se ejecutarán las pruebas en este tutorial.
Paso 1: Configuración e inicialización de la cocina
Ha instalado ChefDK como parte de los requisitos previos que vienen incluidos con Kitchen. En este paso, configurará Kitchen para que se comunique con DigitalOcean.
Antes de inicializar Kitchen, creará un directorio de proyecto y se trasladará a él. En este tutorial, lo llamaremos ansible_testing_dir
.
Ejecute el siguiente comando para crear el directorio:
- mkdir ~/ansible_testing_dir
Y luego pasar a ello:
- cd ~/ansible_testing_dir
Utilice gem
la instalación del kitchen-digitalocean
paquete en su máquina local. Esto le permite indicarle kitchen
que use el controlador de DigitalOcean al ejecutar pruebas:
- gem install kitchen-digitalocean
Dentro del directorio del proyecto, ejecutará el kitchen init
comando especificando ansible_playbook
como aprovisionador y digitalocean
como controlador al inicializar Kitchen:
- kitchen init --provisioner=ansible_playbook --driver=digitalocean
Verás el siguiente resultado:
Outputcreate kitchen.ymlcreate chefignorecreate test/integration/default
Esto ha creado lo siguiente dentro del directorio de su proyecto:
-
test/integration/default
Es el directorio donde guardarás tus archivos de prueba. -
chefignore
es el archivo que usarías para garantizar que ciertos archivos no se carguen al servidor Chef Infra, pero no lo usarás en este tutorial. -
kitchen.yml
es el archivo que describe su configuración de prueba: lo que desea probar y las plataformas de destino.
Ahora, debe exportar sus credenciales de DigitalOcean como variables de entorno para tener acceso a la creación de Droplets desde su CLI. Primero, comience con su token de acceso de DigitalOcean ejecutando el siguiente comando:
- export DIGITALOCEAN_ACCESS_TOKEN="YOUR_DIGITALOCEAN_ACCESS_TOKEN"
También debe obtener el número de identificación de su clave SSH; tenga en cuenta que YOUR_DIGITALOCEAN_SSH_KEY_IDS
debe ser el ID numérico de su clave SSH, no el nombre simbólico. Con la API de DigitalOcean, puede obtener el ID numérico de sus claves con el siguiente comando:
- curl -X GET https://api.digitalocean.com/v2/account/keys -H "Authorization: Bearer $DIGITALOCEAN_ACCESS_TOKEN"
Con este comando verás una lista de tus claves SSH y los metadatos relacionados. Lee el resultado para encontrar la clave correcta e identificar el número de identificación dentro del resultado:
Output... {"id":your-ID-number,"fingerprint":"fingerprint","public_key":"ssh-rsa your-ssh-key","name":"your-ssh-key-name"...
Nota: Si desea que su salida sea más legible para obtener sus identificadores numéricos, puede buscar y descargar jq
según su sistema operativo en la página de descarga de jq. Ahora, puede ejecutar el comando anterior incluido jq
de la siguiente manera:
- curl -X GET https://api.digitalocean.com/v2/account/keys -H "Authorization: Bearer $DIGITALOCEAN_ACCESS_TOKEN" | jq
Verá la información de su clave SSH con un formato similar al siguiente:
Output{ "ssh_keys": [ { "id": YOUR_SSH_KEY_ID, "fingerprint": "2f:d0:16:6b", "public_key": "ssh-rsa AAAAB3NzaC1yc2 example@example.local", "name": "sannikay" } ],}
Una vez que haya identificado sus ID numéricas SSH, expórtelas con el siguiente comando:
- export DIGITALOCEAN_SSH_KEY_IDS="YOUR_DIGITALOCEAN_SSH_KEY_ID"
Ha inicializado kitchen
y configurado las variables de entorno para sus credenciales de DigitalOcean. Ahora, podrá crear y ejecutar pruebas en sus Droplets de DigitalOcean directamente desde la línea de comandos.
Paso 2: creación del manual de Ansible
En este paso, creará un playbook y roles que configuran Nginx y Node.js en el Droplet creado en kitchen
el siguiente paso. Las pruebas se ejecutarán en el playbook para garantizar que se cumplan las condiciones especificadas en el playbook.
Para comenzar, cree un roles
directorio para los roles Nginx y Node.js:
- mkdir -p roles/{nginx,nodejs}/tasks
Esto creará una estructura de directorio como la siguiente:
roles├── nginx│ └── tasks└── nodejs └── tasks
Ahora, crea un main.yml
archivo en el roles/nginx/tasks
directorio usando tu editor preferido:
- nano roles/nginx/tasks/main.yml
En este archivo, cree una tarea que configure e inicie Nginx agregando el siguiente contenido:
roles/nginx/tareas/main.yml
---- name: Update cache repositories and install Nginx apt: name: nginx update_cache: yes- name: Change nginx directory permission file: path: /etc/nginx/nginx.conf mode: 0750- name: start nginx service: name: nginx state: started
Una vez que haya agregado el contenido, guarde y salga del archivo.
En roles/nginx/tasks/main.yml
, se define una tarea que actualizará el repositorio de caché de su Droplet, lo que equivale a ejecutar el apt update
comando manualmente en un servidor. Esta tarea también cambia los permisos del archivo de configuración de Nginx e inicia el servicio Nginx.
También vas a crear un main.yml
archivo roles/nodejs/tasks
para definir una tarea que configure Node.js:
- nano roles/nodejs/tasks/main.yml
Agregue las siguientes tareas a este archivo:
roles/nodejs/tareas/main.yml
---- name: Update caches repository apt: update_cache: yes- name: Add gpg key for NodeJS LTS apt_key: url: "https://deb.nodesource.com/gpgkey/nodesource.gpg.key" state: present- name: Add the NodeJS LTS repo apt_repository: repo: "deb https://deb.nodesource.com/node_{{ NODEJS_VERSION }}.x {{ ansible_distribution_release }} main" state: present update_cache: yes- name: Install Node.js apt: name: nodejs state: present
Guarde y salga del archivo cuando haya terminado.
En roles/nodejs/tasks/main.yml
, primero se define una tarea que actualizará el repositorio de caché de su Droplet. Luego, con la siguiente tarea, se agrega la clave GPG para Node.js que sirve como medio para verificar la autenticidad del apt
repositorio de Node.js. Las dos tareas finales agregan el repositorio de Node.js apt
e instalan Node.js.
Ahora definirá sus configuraciones de Ansible, como las variables, el orden en el que desea que se ejecuten sus roles y la configuración de privilegios de superusuario. Para ello, creará un archivo llamado playbook.yml
, que sirve como punto de entrada para Kitchen. Cuando ejecuta sus pruebas, Kitchen comienza desde su playbook.yml
archivo y busca los roles que se ejecutarán, que son sus archivos roles/nginx/tasks/main.yml
y .roles/nodejs/tasks/main.yml
Ejecute el siguiente comando para crear playbook.yml
:
- nano playbook.yml
Añade el siguiente contenido al archivo:
directorio_de_pruebas_ansible/playbook.yml
--- - hosts: all become: true remote_user: ubuntu vars: NODEJS_VERSION: 8
Guardar y salir del archivo.
Ha creado los roles del libro de estrategias de Ansible contra los cuales ejecutará sus pruebas para garantizar que se cumplan las condiciones especificadas en el libro de estrategias.
Paso 3: Cómo escribir las pruebas InSpec
En este paso, escribirá pruebas para verificar si Node.js está instalado en su Droplet. Antes de escribir su prueba, veamos el formato de una prueba InSpec de ejemplo. Al igual que con muchos marcos de prueba, el código InSpec se parece a un lenguaje natural. InSpec tiene dos componentes principales, el sujeto a examinar y el estado esperado del sujeto:
Bloque A
describe 'entity' do it { expectation }end
En el bloque A, las palabras clave do
y end
definen un conjunto de pruebas, que contienen casos de prueba. La block
palabra clave se utiliza para definir los casos de prueba.describe
it
entity
es el objeto que desea examinar, por ejemplo, un nombre de paquete, servicio, archivo o puerto de red. expectation
Especifica el resultado deseado o el estado esperado, por ejemplo, Nginx debe estar instalado o debe tener una versión específica. Puede consultar la documentación de InSpec DSL para obtener más información sobre el lenguaje InSpec.
Otro ejemplo de bloque de prueba InSpec:
Bloque B
control 'Can be anything unique' do impact 0.7 title 'A human-readable title' desc 'An optional description' describe 'entity' do it { expectation } endend
La diferencia entre el bloque A y el bloque B es el control
bloque. El control
bloque se utiliza como medio de control, recomendación o requisito regulatorio. El control
bloque tiene un nombre, generalmente un identificador único, metadatos como desc
, title
, impact
y finalmente agrupa describe
bloques relacionados para implementar las verificaciones.
desc
, title
, y define impact
metadatos que describen completamente la importancia del control, su propósito, con una descripción sucinta y completa. impact
define un valor numérico que va desde 0.0
hasta 1.0
donde se clasifica como sin impacto, se clasifica como de bajo impacto, se clasifica como de impacto medio, se clasifica como de alto impacto, se clasifica como control crítico.0.0
0.01
0.01
0.4
0.4
0.7
0.7
0.9
0.9
1.0
Ahora, para implementar una prueba, utilizará la sintaxis del bloque A y utilizará package
el recurso de InSpec para probar si Node.js
está instalado en el sistema. Creará un archivo con el nombre sample.rb
en su test/integration/default
directorio para sus pruebas.
Crear sample.rb
:
- nano test/integration/default/sample.rb
Añade lo siguiente a tu archivo:
prueba/integración/predeterminado/muestra.rb
describe package('nodejs') do it { should be_installed }end
Aquí su prueba utiliza el package
recurso para verificar que Node.js esté instalado.
Guarde y salga del archivo cuando haya terminado.
Para ejecutar esta prueba, debe editar kitchen.yml
para especificar el libro de estrategias que creó anteriormente y agregarlo a sus configuraciones.
Abra su kitchen.yml
archivo:
- nano ansible_testing_dir/kitchen.yml
Reemplace el contenido de kitchen.yml
por lo siguiente:
directorio_de_pruebas_ansible/kitchen.yml
---driver: name: digitaloceanprovisioner: name: ansible_playbook hosts: test-kitchen playbook: ./playbook.ymlverifier: name: inspecplatforms: - name: ubuntu-18 driver_config: ssh_key: PATH_TO_YOUR_PRIVATE_SSH_KEY tags: - inspec-testing region: fra1 size: 1gb private_networking: false verifier: inspec_tests: - test/integration/defaultsuites: - name: default
Las platform
opciones incluyen lo siguiente:
-
name
:La imagen que estás usando. -
driver_config
: Su configuración de Droplet de DigitalOcean. Está especificando las siguientes opciones paradriver_config
:ssh_key
: Ruta aYOUR_PRIVATE_SSH_KEY
. SuYOUR_PRIVATE_SSH_KEY
se encuentra en el directorio que especificó al crear sussh
clave.tags
:Las etiquetas asociadas a tu Droplet.region
:Elregion
lugar donde quieres que se aloje tu Droplet.size
:La memoria que quieres que tenga tu Droplet.
-
verifier
:Esto define que el proyecto contiene pruebas InSpec.- La
inspec_tests
parte especifica que las pruebas existen en eltest/integration/default
directorio del proyecto.
- La
Tenga en cuenta que name
y region
utilizan abreviaturas. Puede consultar la test-kitchen
documentación para saber qué abreviaturas puede utilizar.
Una vez que haya agregado su configuración, guarde y salga del archivo.
Ejecute el kitchen test
comando para ejecutar la prueba. Esto comprobará si Node.js está instalado. Esto fallará intencionalmente porque actualmente no tiene la función Node.js en su playbook.yml
archivo:
- kitchen test
Verá un resultado similar al siguiente:
Output: failing test results----- Starting Kitchen (v1.24.0)----- Cleaning up any prior instances of default-ubuntu-18----- Destroying default-ubuntu-18... DigitalOcean instance 145268853 destroyed. Finished destroying default-ubuntu-18 (0m2.63s).----- Testing default-ubuntu-18----- Creating default-ubuntu-18... DigitalOcean instance 145273424 created. Waiting for SSH service on 138.68.97.146:22, retrying in 3 seconds [SSH] Established (ssh ready) Finished creating default-ubuntu-18 (0m51.74s).----- Converging default-ubuntu-18...$$$$$$ Running legacy converge for 'Digitalocean' Driver----- Installing Chef Omnibus to install busser to run tests PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [localhost] PLAY RECAP ********************************************************************* localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Downloading files from default-ubuntu-18 Finished converging default-ubuntu-18 (0m55.05s).----- Setting up default-ubuntu-18...$$$$$$ Running legacy setup for 'Digitalocean' Driver Finished setting up default-ubuntu-18 (0m0.00s).----- Verifying default-ubuntu-18... Loaded tests from {:path=". ansible_testing_dir.test.integration.default"}Profile: tests from {:path="ansible_testing_dir/test/integration/default"} (tests from {:path="ansible_testing_dir.test.integration.default"})Version: (not specified)Target: ssh://root@138.68.97.146:22 System Package nodejs × should be installed expected that System Package nodejs is installedTest Summary: 0 successful, 1 failure, 0 skipped ------Exception------- Class: Kitchen::ActionFailed Message: 1 actions failed. Verify failed on instance default-ubuntu-18. Please see .kitchen/logs/default-ubuntu-18.log for more details ---------------------- Please see .kitchen/logs/kitchen.log for more details Also try running `kitchen diagnose --all` for configuration 4.54s user 1.77s system 5% cpu 2:02.33 total
El resultado indica que la prueba falla porque no tienes Node.js instalado en el Droplet que aprovisionaste kitchen
. Solucionarás la prueba agregando el nodejs
rol a tu playbook.yml
archivo y ejecutando la prueba nuevamente.
Edite el playbook.yml
archivo para incluir el nodejs
rol:
- nano playbook.yml
Agregue las siguientes líneas resaltadas a su archivo:
directorio_de_pruebas_ansible/playbook.yml
--- - hosts: all become: true remote_user: ubuntu vars: NODEJS_VERSION: 8 roles: - nodejs
Guarde y cierre el archivo.
Ahora, volverá a ejecutar la prueba usando el kitchen test
comando:
- kitchen test
Verás el siguiente resultado:
Output......Target: ssh://root@46.101.248.71:22 System Package nodejs ✔ should be installedTest Summary: 1 successful, 0 failures, 0 skipped Finished verifying default-ubuntu-18 (0m4.89s).----- Destroying default-ubuntu-18... DigitalOcean instance 145512952 destroyed. Finished destroying default-ubuntu-18 (0m2.23s). Finished testing default-ubuntu-18 (2m49.78s).----- Kitchen is finished. (2m55.14s) 4.86s user 1.77s system 3% cpu 2:56.58 total
Tu prueba ahora pasa porque tienes Node.js instalado usando el nodejs
rol.
A continuación se muestra un resumen de lo que está haciendo Kitchen en Test Action
:
- Destruye la gota si existe
- Crea la gota
- Converge la gota
- Verifica la gota con InSpec
- Destruye la gota
Kitchen abortará la ejecución de su Droplet si encuentra algún problema. Esto significa que si su manual de Ansible falla, InSpec no se ejecutará y su Droplet no se destruirá. Esto le da la oportunidad de inspeccionar el estado de la instancia y solucionar cualquier problema. El comportamiento de la acción de destrucción final se puede anular si lo desea. Consulte la ayuda de CLI para obtener el --destroy
indicador ejecutando el kitchen help test
comando.
Ha escrito sus primeras pruebas y las ha ejecutado en relación con su libro de estrategias, pero una instancia falló antes de solucionar el problema. A continuación, ampliará su archivo de prueba.
Paso 4: Agregar casos de prueba
En este paso, agregará más casos de prueba a su archivo de prueba para verificar si los módulos Nginx están instalados en su Droplet y si el archivo de configuración tiene los permisos correctos.
Edite su sample.rb
archivo para agregar más casos de prueba:
- nano test/integration/default/sample.rb
Agregue los siguientes casos de prueba al final del archivo:
prueba/integración/predeterminado/muestra.rb
. . .control 'nginx-modules' do impact 1.0 title 'NGINX modules' desc 'The required NGINX modules should be installed.' describe nginx do its('modules') { should include 'http_ssl' } its('modules') { should include 'stream_ssl' } its('modules') { should include 'mail_ssl' } endendcontrol 'nginx-conf' do impact 1.0 title 'NGINX configuration' desc 'The NGINX config file should owned by root, be writable only by owner, and not writeable or and readable by others.' describe file('/etc/nginx/nginx.conf') do it { should be_owned_by 'root' } it { should be_grouped_into 'root' } it { should_not be_readable.by('others') } it { should_not be_writable.by('others') } it { should_not be_executable.by('others') } endend
Estos casos de prueba comprueban que nginx-modules
en su Droplet se incluyan http_ssl
, stream_ssl
y mail_ssl
. También se comprueban los /etc/nginx/nginx.conf
permisos de archivo.
Estás utilizando las palabras claves it
y its
para definir tu prueba. La palabra clave its
solo se utiliza para acceder a las propiedades de los recursos. Por ejemplo, modules
es una propiedad de nginx
.
Guarde y salga del archivo una vez que haya agregado los casos de prueba.
Ahora ejecute el kitchen test
comando para probar nuevamente:
- kitchen test
Verás el siguiente resultado:
Output...Target: ssh://root@104.248.131.111:22 ↺ nginx-modules: NGINX modules ↺ The `nginx` binary not found in the path provided. × nginx-conf: NGINX configuration (2 failed) × File /etc/nginx/nginx.conf should be owned by "root" expected `File /etc/nginx/nginx.conf.owned_by?("root")` to return true, got false × File /etc/nginx/nginx.conf should be grouped into "root" expected `File /etc/nginx/nginx.conf.grouped_into?("root")` to return true, got false ✔ File /etc/nginx/nginx.conf should not be readable by others ✔ File /etc/nginx/nginx.conf should not be writable by others ✔ File /etc/nginx/nginx.conf should not be executable by others System Package nodejs ✔ should be installedProfile Summary: 0 successful controls, 1 control failure, 1 control skippedTest Summary: 4 successful, 2 failures, 1 skipped
Verás que algunas de las pruebas fallan. Para solucionarlas, agrega la nginx
función a tu archivo de libro de estrategias y vuelve a ejecutar la prueba. En la prueba que falla, estás verificando nginx
los módulos y los permisos de archivos que actualmente no están presentes en tu servidor.
Abra su playbook.yml
archivo:
- nano ansible_testing_dir/playbook.yml
Añade la siguiente línea resaltada a tus roles:
directorio_de_pruebas_ansible/playbook.yml
---- hosts: all become: true remote_user: ubuntu vars: NODEJS_VERSION: 8 roles: - nodejs - nginx
Guarde y cierre el archivo cuando haya terminado.
Luego ejecuta tus pruebas nuevamente:
- kitchen test
Verás el siguiente resultado:
Output...Target: ssh://root@104.248.131.111:22✔ nginx-modules: NGINX version ✔ Nginx Environment modules should include "http_ssl" ✔ Nginx Environment modules should include "stream_ssl" ✔ Nginx Environment modules should include "mail_ssl" ✔ nginx-conf: NGINX configuration ✔ File /etc/nginx/nginx.conf should be owned by "root" ✔ File /etc/nginx/nginx.conf should be grouped into "root" ✔ File /etc/nginx/nginx.conf should not be readable by others ✔ File /etc/nginx/nginx.conf should not be writable by others ✔ File /etc/nginx/nginx.conf should not be executable by others System Package nodejs ✔ should be installedProfile Summary: 2 successful controls, 0 control failures, 0 controls skippedTest Summary: 9 successful, 0 failures, 0 skipped
Después de agregar el nginx
rol al libro de estrategias, todas las pruebas pasan. El resultado muestra que los módulos http_ssl
, stream_ssl
y mail_ssl
están instalados en su Droplet y que se establecieron los permisos correctos para el archivo de configuración.
Una vez que hayas terminado, o ya no necesites tu Droplet, puedes destruirlo ejecutando el kitchen destroy
comando para eliminarlo después de ejecutar tus pruebas:
- kitchen destroy
Si sigue este comando verá un resultado similar al siguiente:
Output----- Starting Kitchen (v1.24.0)----- Destroying default-ubuntu-18... Finished destroying default-ubuntu-18 (0m0.00s).----- Kitchen is finished. (0m5.07s) 3.79s user 1.50s system 82% cpu 6.432 total
Ha escrito pruebas para su playbook, las ha ejecutado y ha corregido las pruebas que fallaron para garantizar que todas las pruebas funcionen correctamente. Ahora está preparado para crear un entorno virtual, escribir pruebas para su playbook de Ansible y ejecutar la prueba en el entorno virtual con Kitchen.
Conclusión
Ahora tienes una base flexible para probar tu implementación de Ansible, lo que te permite probar tus playbooks antes de ejecutarlos en un servidor activo. También puedes empaquetar tu prueba en un perfil. Puedes usar perfiles para compartir tu prueba a través de Github o Chef Supermarket y ejecutarla fácilmente en un servidor activo.
Para obtener detalles más completos sobre InSpec y Kitchen, consulte la documentación oficial de InSpec y la documentación oficial de Kitchen.
Deja una respuesta