Tutorials 29 May 2020

Pruebas de carga con Azure Pipelines

Rafael Muñoz Cárdenas, Simon Aronsson

Si quiere pasar directamente a instalar la extensión del mercado, puede encontrarla aquí.

📖Lo que aprenderás

  • Cómo integrar las pruebas de carga con K6 y Azure Pipelines
  • Diferentes vías de implementación, y cuándo usar cada una

Introducción

Los problemas de rendimiento pueden resultar costosos. Las razones pueden variar desde aumentos de tráfico inesperados, piezas de código sin rendimiento que actúan como cuellos de botella o componentes de red mal configurados. La integración de las pruebas de carga y rendimiento en su canalización de CI le permitirá conocer las degradaciones de rendimiento con antelación, en la mayoría de los casos, incluso antes de que tengan algún impacto en sus usuarios en el entorno de producción.

En esta guía, usaremos K6 y Azure Pipelines para empezar rápidamente y sin esfuerzo.

K6 es una herramienta de pruebas gratuita y de código abierto para pruebas de carga y rendimiento de APIs, microservicios y sitios web. Proporciona a los usuarios una interfaz javascript fácil de usar para escribir pruebas de carga y rendimiento como código, permitiendo efectivamente a los desarrolladores encajarlas en su flujo de trabajo diario y en su cadena de herramientas sin la molestia de las interfaces gráficas de apuntar y hacer clic.

Azure Pipelines es un servicio de integración continua (CI) y entrega continua (CD) que forma parte de la oferta de Azure DevOps de Microsoft. Puede utilizarse para probar y construir continuamente su código fuente, así como para desplegarlo en cualquier destino que especifique. Al igual que K6, se configura a través de código y lenguaje de marcas o etiquetas.

Escribir su primera prueba de rendimiento

Por lo general, es una buena idea resistir el impulso de diseñar para el objetivo final de inmediato. En su lugar, comience con algo pequeño, escogiendo una parte aislada pero de alto valor del sistema bajo prueba, y una vez que tenga el control, itere y expanda. Nuestra prueba constará de tres partes:

  1. Una solicitud HTTP contra el endpoint que queremos probar.
  2. Un par de etapas de carga que controlarán la duración y la cantidad de usuarios virtuales.
  3. Un objetivo de rendimiento, o de nivel de servicio, expresado como un umbral.

Creación del script de prueba

Durante la ejecución, cada usuario virtual hará un bucle sobre la función que exportemos por defecto tantas veces como sea posible hasta que se agote la duración. Esto no será un problema ahora mismo, ya que todavía tenemos que configurar nuestra carga, pero para evitar inundar el sistema bajo prueba más tarde, añadiremos un sleep para que espere un segundo antes de continuar.

import http from 'k6/http';
import { sleep } from 'k6';
export default function () {
const res = http.get('https://test.k6.io');
sleep(1);
}

Configuración de la carga

En esta guía, crearemos una prueba K6 que simulará un aumento progresivo de 0 a 15 usuarios virtuales (VUs) durante diez segundos. A continuación, los 15 usuarios virtuales se mantendrán en 15 VUs 20 segundos, y finalmente, se reducirá en una duración de 10 segundos a 0 usuarios virtuales.

import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
stages: [
{ duration: '10s', target: 15 },
{ duration: '20s', target: 15 },
{ duration: '10s', target: 0 },
],
};
export default function () {
const res = http.get('https://test.k6.io');
sleep(1);
}

Con esto, nuestra prueba debería tener una media de unas diez peticiones por segundo. Como el punto final que estamos probando está usando SSL, cada petición también será precedida por una petición de opciones, haciendo que el promedio total mostrado por k6 sea de alrededor de 20 por segundo.

Definiendo nuestro objetivo de rendimiento

Un requisito básico para destacar en las pruebas de rendimiento es definir unos objetivos de nivel de servicio (SLO) claros y medibles con los que comparar. Los SLO son un aspecto vital para garantizar la fiabilidad de su sistema bajo prueba.

Como estos SLO a menudo, ya sea individualmente o como grupo, conforman un acuerdo de nivel de servicio con su cliente, es fundamental asegurarse de cumplir el acuerdo o arriesgarse a tener que pagar costosas penalizaciones.

Los umbrales le permiten definir criterios claros de lo que se considera un éxito o un fracaso de la prueba. Vamos a añadir un umbral a nuestro objeto options:

import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
stages: [
{ duration: '10s', target: 15 },
{ duration: '20s', target: 15 },
{ duration: '10s', target: 0 },
],
thresholds: {
http_req_duration: ['p(95)<250'],
},
};
export default function () {
const res = http.get('https://test.k6.io');
sleep(1);
}

En este caso, el tiempo de respuesta del percentil 95 debe ser inferior a 250 ms. Si el tiempo de respuesta es superior, la prueba fallará. Fallar un umbral conducirá a un código de salida distinto de cero, que a su vez permitirá a nuestra herramienta CI saber que el paso ha fallado y que la construcción requiere más atención.

ℹ️ Flexibilidad del umbral

Los umbrales son extremadamente versátiles, y puedes establecerlos para evaluar casi cualquier agregación numérica del tiempo de respuesta devuelto. Los más comunes son las métricas máximas o del percentil 95/99. Para más detalles, consulte nuestra documentación sobre Umbrales.

Antes de continuar, vamos a añadir el archivo de script a git y a confirmar los cambios en tu repositorio. Si tienes K6 instalado en tu máquina local, puedes ejecutar tu test localmente en tu terminal usando el comando: k6 run loadtest.js.

Ejecutando la prueba en Azure Pipelines

Para poder utilizar la extensión de marketplace en nuestro pipeline, primero tenemos que instalarla en nuestra organización Azure DevOps. Esto se puede hacer directamente desde el listado de marketplace. Una vez hecho esto, ya tenemos todo listo para crear la configuración de nuestros pipelines.

⚠️ Se requiere de un permiso para instalar extensiones del mercado

El enfoque recomendado es usar la extensión de marketplace, pero si por alguna razón no puedes, por ejemplo si no tienes la capacidad de instalar extensiones, usando la imagen de docker como se describe más abajo, funciona muy bien también.

Ejecución local

# azure-pipelines.yml
pool:
vmImage: 'ubuntu-latest'
steps:
- task: k6-load-test@0
inputs:
filename: 'YOUR_K6_TEST_SCRIPT.js'

Ejecutaremos nuestras pruebas en una máquina virtual que ejecuta la última versión disponible de Ubuntu. Para ejecutar nuestra prueba de carga real, sólo se requiere un paso.

La tarea para este paso será ejecutar la extensión k6-load-test recién instalada. Además, le suministraremos el nombre de archivo de nuestro script de prueba. Esto será el equivalente a ejecutar k6 run YOUR_K6_TEST_SCRIPT.js en la máquina virtual del pipeline.

Si su prueba se llama test.js y se coloca en la raíz del proyecto, la clave inputs puede ser omitida por completo.

No olvides añadir azure-pipelines.yml y confirmar los cambios en tu repositorio. Después de hacer push a tu código, dirígete al panel de control de Azure y visita el trabajo que desencadenó el git push. A continuación se muestra el trabajo exitoso:

succeeded job

Ejecución en la nube

La ejecución en la nube puede ser útil en estos casos comunes:

  • Se desea ejecutar una prueba desde una o varias ubicaciones geográficas (zonas de carga).
  • Desea ejecutar una prueba con una carga elevada que necesitará más recursos informáticos que los aprovisionados por el servidor de CI.
  • Obtenga un análisis automático de los resultados.

La ejecución de sus pruebas en nuestra nube es transparente para el usuario, ya que no es necesario realizar cambios en sus scripts. Sólo tienes que añadir cloud: true a la configuración de tu pipeline.

Para que este script funcione, necesitas obtener tu token de Grafana Cloud k6 y añadirlo como variable. El comando Azure Pipeline pasará tu token de cuenta a la instancia Docker como la variable de entorno K6_CLOUD_TOKEN, y K6 lo leerá para autenticarte en la nube k6 automáticamente.

create variable

Por defecto, el servicio en la nube ejecutará la prueba desde el norte de Virginia (Ashburn). Pero, vamos a añadir un código extra a nuestro script anterior para seleccionar otra zona de carga:

export const options = {
// ...
ext: {
loadimpact: {
name: 'test.k6.io',
distribution: {
loadZoneLabel1: {
loadZone: 'amazon:ie:dublin',
percent: 100,
},
},
},
},
};

Esto creará el 100% de los usuarios virtuales en Irlanda. Si quieres saber más sobre las diferentes opciones de Zonas de Carga, lee más aquí.

Ahora, te recomendamos que pruebes cómo activar una prueba en la nube desde tu máquina. Ejecuta el siguiente comando en la terminal:

$ k6 login cloud
$ k6 cloud loadtest.js

Una vez hecho esto, podemos seguir adelante y git add, git commit y git push los cambios que hemos hecho en el código e iniciar el trabajo de CI.

Por defecto, la tarea de Azure Pipelines imprimirá la URL del resultado de la prueba en la Nube K6, que puedes utilizar para navegar directamente a la vista de resultados y realizar cualquier análisis manual que necesites.

cloud url

Grafana Cloud k6 results

Le recomendamos que defina sus umbrales de rendimiento en las pruebas k6 en un paso anterior. Si ha configurado sus umbrales correctamente y su prueba pasa, no debería haber nada de qué preocuparse.

Si la prueba falla, querrá visitar el resultado de la prueba en el servicio en la nube para encontrar su causa.

Variaciones

Ejecuciones programadas (nightlies)

Es común ejecutar algunas pruebas de carga durante la noche cuando los usuarios no acceden al sistema bajo prueba. Por ejemplo, para aislar las pruebas más grandes de otros tipos de pruebas o para generar periódicamente un informe de rendimiento.

A continuación se muestra el primer ejemplo de configuración de un trigger programado que se ejecuta a medianoche (UTC) de cada día, pero sólo si el código ha cambiado en el master desde la última ejecución.

# azure-pipelines.yml
pool:
vmImage: 'ubuntu-latest'
steps:
- task: k6-load-test@0
inputs:
filename: 'YOUR_K6_TEST_SCRIPT.js'
schedules:
- cron: '0 0 * * *'
displayName: Daily midnight build
branches:
include:
- master

Usando la imagen docker oficial

Si por alguna razón, no quieres usar la extensión del mercado, puedes usar la imagen docker oficial en su lugar.

# azure-pipelines.yml
pool:
vmImage: 'ubuntu-18.04'
steps:
- script: |
docker pull grafana/k6
displayName: Pull k6 image
- script: |
docker run -i \
-e K6_CLOUD_TOKEN=$(K6_CLOUD_TOKEN) \
-v `pwd`:/src \
grafana/k6 \
cloud /src/loadtest.js \
displayName: Run cloud test

Recursos adicionales

Resumen

Integrar K6 en Azure Pipelines se hace en cuestión de minutos. Al integrar las pruebas de rendimiento en tu proceso de CI/CD, podrás identificar y corregir las regresiones de rendimiento y seguir cumpliendo con tus requisitos de SLO o SLA.

< Back to all posts