--- title: "Pruebas de carga web con k6 en Ubuntu 24.04" description: "Instala k6 en Ubuntu 24.04 y escribe pruebas de carga en JavaScript para tu web o API: usuarios virtuales, rampas, checks, umbrales para CI e informe HTML." category: "Rendimiento y Benchmarking" language: es source: https://cubepath.com/es/docs/rendimiento-y-benchmarking/pruebas-de-carga-de-aplicacion-web-con-k6 updated: 2026-09-25 --- # Pruebas de carga web con k6 en Ubuntu 24.04 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`. > Advertencia: una 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): ```bash sudo gpg -k ``` Descarga la clave de firma del repositorio en `/etc/apt/keyrings`: ```bash 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`: ```bash 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: ```bash sudo apt update sudo apt install k6 ``` Comprueba que funciona: ```bash k6 version ``` ```output 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: ```bash mkdir ~/k6-tests && cd ~/k6-tests nano basic.js ``` ```javascript 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: ```bash k6 run -e BASE_URL=https://your_domain basic.js ``` Al terminar, k6 muestra un resumen. Esta es una versión abreviada: ```output █ 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 en `p(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: ```bash nano ramp.js ``` ```javascript 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: ```bash 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: ```bash nano thresholds.js ``` ```javascript 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: ```bash 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`: ```output 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: ```bash nano scenarios.js ``` ```javascript 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-vus` controla cuántos usuarios hay a la vez. Si la aplicación se vuelve lenta, cada usuario hace menos peticiones. - `constant-arrival-rate` mantiene 50 iteraciones por segundo pase lo que pase, añadiendo VU (hasta `maxVUs`) 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: ```bash 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: ```bash 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: ```bash 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`: ```bash 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 con `curl -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 con `ulimit -n 65536` antes 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.