k6 es una herramienta de pruebas de carga de código abierto mantenida por Grafana Labs. Los escenarios se escriben en JavaScript y k6 los ejecuta con usuarios virtuales (VU) que lanzan peticiones HTTP en paralelo, midiendo tiempos de respuesta, errores y caudal. En este tutorial instalarás k6 en Ubuntu 24.04, escribirás una prueba con validaciones, simularás una rampa de tráfico, definirás umbrales que hagan fallar la prueba si el rendimiento no es aceptable y generarás un informe HTML.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS desde el que lanzar la carga, por ejemplo un VPS de CubePath. Lo ideal es que no sea el mismo servidor que aloja la aplicación, para que k6 no le robe CPU.
- Un usuario no root con privilegios
sudo. - Una aplicación web o API tuya que probar, accesible en
https://your_domain.
Advertenciauna prueba de carga es, a efectos prácticos, un pico de tráfico masivo. Lánzala solo contra sistemas que te pertenezcan o sobre los que tengas autorización expresa, y avisa a quien gestione la infraestructura, el CDN o el WAF para que no la bloqueen como un ataque.
Paso 1: Instalar k6 desde el repositorio oficial
Grafana publica k6 en su propio repositorio APT. Primero inicializa el almacén de claves de GnuPG de root (solo hace falta la primera vez):
sudo gpg -k
Descarga la clave de firma del repositorio en /etc/apt/keyrings:
sudo install -m 0755 -d /etc/apt/keyrings
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/k6-archive-keyring.gpg \
--keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
Añade el repositorio indicando esa clave con signed-by:
echo "deb [signed-by=/etc/apt/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
Instala k6:
sudo apt update
sudo apt install k6
Comprueba que funciona:
k6 version
k6 v1.3.0 (commit/5870e99ae8, go1.24.6, linux/amd64)
Paso 2: Escribir y ejecutar una primera prueba
Un script de k6 exporta una función por defecto que cada usuario virtual ejecuta en bucle durante la prueba. Cada ejecución de esa función es una iteración. Crea un directorio para las pruebas y el primer script:
mkdir ~/k6-tests && cd ~/k6-tests
nano basic.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 10,
duration: '30s',
};
const BASE_URL = __ENV.BASE_URL || 'https://your_domain';
export default function () {
const res = http.get(`${BASE_URL}/`);
check(res, {
'status es 200': (r) => r.status === 200,
'responde en menos de 500 ms': (r) => r.timings.duration < 500,
});
sleep(1);
}
Qué hace cada parte:
options: 10 usuarios virtuales durante 30 segundos.__ENV.BASE_URL: lee la URL de una variable que pasarás con-e, así el mismo script sirve para staging y producción.check: valida cada respuesta. Un check fallido no detiene la prueba, pero queda contabilizado.sleep(1): pausa de un segundo entre iteraciones, que simula el tiempo que un usuario real pasa leyendo la página. Sin ella, cada VU lanzaría peticiones sin descanso.
Ejecuta la prueba:
k6 run -e BASE_URL=https://your_domain basic.js
Al terminar, k6 muestra un resumen. Esta es una versión abreviada:
█ TOTAL RESULTS
checks_total.......: 560 18.4/s
checks_succeeded...: 100.00% 560 out of 560
checks_failed......: 0.00% 0 out of 560
HTTP
http_req_duration..: avg=74.21ms min=41.03ms med=68.55ms max=312.4ms p(90)=102.1ms p(95)=121.87ms
http_req_failed....: 0.00% 0 out of 280
http_reqs..........: 280 9.2/s
EXECUTION
iteration_duration.: avg=1.07s min=1.04s med=1.06s max=1.31s p(90)=1.1s p(95)=1.12s
iterations.........: 280 9.2/s
vus................: 10 min=10 max=10
Las métricas principales son:
http_req_duration: tiempo total de cada petición. Fíjate enp(95), el tiempo por debajo del cual está el 95 % de las peticiones, más que en la media.http_req_failed: porcentaje de peticiones con error de red o código HTTP 4xx/5xx.http_reqs: peticiones totales y por segundo.
Paso 3: Simular una rampa de tráfico
Una carga constante no muestra cómo reacciona la aplicación cuando el tráfico crece. Con stages, k6 sube y baja el número de VU de forma gradual. Crea el script:
nano ramp.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '1m', target: 20 },
{ duration: '3m', target: 20 },
{ duration: '1m', target: 100 },
{ duration: '3m', target: 100 },
{ duration: '1m', target: 0 },
],
};
const BASE_URL = __ENV.BASE_URL || 'https://your_domain';
export default function () {
const res = http.get(`${BASE_URL}/`);
check(res, { 'status es 200': (r) => r.status === 200 });
sleep(1);
}
La prueba sube a 20 VU en un minuto, los mantiene tres minutos, sube a 100, los mantiene y baja a cero: nueve minutos en total. Ejecútala:
k6 run -e BASE_URL=https://your_domain ramp.js
Mientras corre, vigila el servidor de la aplicación con top o con las gráficas de tu panel. Si http_req_duration se dispara al pasar de 20 a 100 VU, has encontrado el punto donde la aplicación empieza a saturarse.
Paso 4: Definir umbrales para aprobar o suspender la prueba
Los umbrales (thresholds) convierten una prueba de carga en una prueba automatizada: si alguno no se cumple, k6 termina con un código de salida distinto de cero, lo que permite usarla en un pipeline de CI. Crea el script:
nano thresholds.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 20,
duration: '1m',
thresholds: {
http_req_failed: ['rate<0.01'],
http_req_duration: ['p(95)<500', 'p(99)<1000'],
checks: ['rate>0.99'],
},
};
const BASE_URL = __ENV.BASE_URL || 'https://your_domain';
export default function () {
const res = http.get(`${BASE_URL}/`);
check(res, { 'status es 200': (r) => r.status === 200 });
sleep(1);
}
Estos umbrales exigen menos de un 1 % de errores, un percentil 95 por debajo de 500 ms, un percentil 99 por debajo de 1 s y más de un 99 % de checks correctos. Ejecuta la prueba y muestra el código de salida:
k6 run -e BASE_URL=https://your_domain thresholds.js; echo "Código de salida: $?"
Si todo se cumple, el resumen marca cada umbral como superado y el código es 0. Si alguno falla, verás un mensaje como este y el código será 99:
ERRO[0061] thresholds on metrics 'http_req_duration' have been crossed
Código de salida: 99
Paso 5: Probar varios flujos con escenarios
Una web real recibe tráfico de distinto tipo a la vez. Los scenarios permiten ejecutar varios flujos en paralelo, cada uno con su propio modelo de carga (executor) y su propia función. Este ejemplo combina usuarios que navegan por la portada con una tasa fija de llamadas a una API:
nano scenarios.js
import http from 'k6/http';
import { check, sleep } from 'k6';
const BASE_URL = __ENV.BASE_URL || 'https://your_domain';
export const options = {
scenarios: {
navegacion: {
executor: 'ramping-vus',
exec: 'browse',
startVUs: 0,
stages: [
{ duration: '1m', target: 30 },
{ duration: '2m', target: 30 },
{ duration: '30s', target: 0 },
],
},
api: {
executor: 'constant-arrival-rate',
exec: 'api',
rate: 50,
timeUnit: '1s',
duration: '3m',
preAllocatedVUs: 20,
maxVUs: 100,
},
},
thresholds: {
'http_req_duration{scenario:api}': ['p(95)<300'],
'http_req_duration{scenario:navegacion}': ['p(95)<800'],
},
};
export function browse() {
const res = http.get(`${BASE_URL}/`);
check(res, { 'portada 200': (r) => r.status === 200 });
sleep(Math.random() * 3 + 1);
}
export function api() {
const res = http.get(`${BASE_URL}/api/health`);
check(res, { 'api 200': (r) => r.status === 200 });
}
Cambia /api/health por un endpoint real de tu aplicación. Diferencias entre los dos executors:
ramping-vuscontrola cuántos usuarios hay a la vez. Si la aplicación se vuelve lenta, cada usuario hace menos peticiones.constant-arrival-ratemantiene 50 iteraciones por segundo pase lo que pase, añadiendo VU (hastamaxVUs) si las respuestas se ralentizan. Es el modelo adecuado para APIs con un volumen de peticiones conocido.
Los umbrales con {scenario:...} se aplican solo a las peticiones de ese escenario. Ejecuta la prueba:
k6 run -e BASE_URL=https://your_domain scenarios.js
Si k6 muestra Insufficient VUs, reached 100 active VUs, la aplicación responde tan despacio que ni 100 VU bastan para mantener la tasa: es una señal clara de saturación.
Paso 6: Generar un informe HTML
k6 incluye un panel web que puede exportar un informe HTML autocontenido al terminar la prueba. Actívalo con variables de entorno:
K6_WEB_DASHBOARD=true K6_WEB_DASHBOARD_EXPORT=informe-ramp.html k6 run -e BASE_URL=https://your_domain ramp.js
Durante la prueba, el panel en vivo está disponible en el puerto 5665 del servidor, escuchando solo en localhost. Para verlo desde tu equipo, abre un túnel SSH en otra terminal local:
ssh -L 5665:localhost:5665 your_user@your_server_ip
Después abre http://localhost:5665 en tu navegador. Cuando termina la prueba, el archivo informe-ramp.html queda en el directorio actual. Descárgalo desde tu equipo con scp:
scp your_user@your_server_ip:~/k6-tests/informe-ramp.html .
Si prefieres procesar los datos en bruto, --out json=resultados.json guarda cada muestra como una línea JSON.
Solución de problemas
dial tcp: lookup your_domain: no such host: la URL es incorrecta o el servidor de carga no resuelve el dominio. Comprueba concurl -I https://your_domain.- Muchas peticiones con estado 403 o 429: el WAF, el CDN o un limitador de peticiones de la aplicación está bloqueando la prueba. Permite la IP del servidor de carga durante la prueba.
socket: too many open files: con cientos de VU se agota el límite de descriptores. Súbelo en la sesión actual conulimit -n 65536antes de lanzar k6.- El servidor de carga llega al 100 % de CPU: k6 es el cuello de botella y los resultados no son fiables. Usa un servidor con más vCPU o reparte la carga entre varios.
Conclusión
Ya tienes k6 instalado y sabes escribir pruebas con checks, simular rampas de tráfico, combinar escenarios con distintos modelos de carga y definir umbrales que devuelven un código de salida útil en CI. Como siguientes pasos, puedes añadir k6 run thresholds.js a tu pipeline para detectar regresiones antes de cada despliegue, medir la base de datos de la aplicación con pgbench o sysbench, o correlacionar los resultados con las métricas de CPU y memoria del servidor durante la prueba.
