Por Lucas Yoris · Performate
Pruebas de carga de APIs y microservicios en Kubernetes: ingress, timeouts y señales del HPA
Pruebas de carga en Kubernetes: timeouts de ingress, HPA, overhead del mesh—k6 contra hostnames reales del cluster con contexto de red de Kubernetes.io.
La prueba de carga «pasó» contra la IP del pod en el namespace staging, pero producción sigue fallando en el ingress: timeouts de proxy-read, HPA que escala tarde y un sidecar de mesh que suma 40 ms por hop. En Kubernetes, el hostname que ve el cliente y las señales del plano de control son parte del experimento—no un detalle de infra.
Las pruebas de carga de microservicios en Kubernetes no tratan de demostrar que un Deployment arranca. Tratan de validar que tráfico externo realista cumple SLO mientras ingress, autoscaling y mesh interactúan. En esta guía verás por qué golpear pod IPs engaña, cómo alinear duraciones de test con anotaciones de ingress, y cómo correlacionar rampas de k6 con eventos de HPA y métricas de cluster.
Por qué Kubernetes cambia los modos de fallo
Bajo concurrencia, la latencia de microservicios suele estar dominada por la plataforma, no solo por tu handler HTTP:
- Ingress / Gateway API: timeouts de lectura, buffers y límites de conexión cortan requests lentos antes de que el servicio responda.
- HPA: el lag entre métrica, decisión y pod listo crea rampas de latencia durante subidas de carga (documentación de Kubernetes).
- Service mesh: sidecars duplican TLS, retries y políticas—milisegundos por hop que se acumulan en cadenas de llamadas.
- DNS y políticas de red: resolución y
NetworkPolicydistintas entre «desde laptop» y «desde runner en cluster».
Piensa en k6 como un cliente fuera del cluster (o en un job de CI con egress real): debe usar el mismo FQDN que la app móvil o el BFF, no http://10.x.x.x:8080 interno.
Cuando el microservicio está sano pero el percentil explota
Un p99 que solo aparece bajo rampa suele ser cola en ingress o cold pods, no un bug de SQL. Sin correlacionar kubectl get hpa y eventos con la ventana de k6, el equipo optimiza el servicio equivocado. Etiqueta workloads con mesh:on / mesh:off al comparar—ver k6 observabilidad: métricas y tags.
Implementación práctica con k6: ingress, rampas y tags
Script de ejemplo (ilustrativo). Hostnames y umbrales ficticios.
Qué demuestra este ejemplo:
- BASE_URL apunta al ingress público (
api.staging.example.com), no al Service ClusterIP. - Escenario con rampa para observar lag del HPA, no solo meseta instantánea.
- Tags
route,meshyingresspara partir métricas en postmortems.
import http from 'k6/http';
import { check, sleep } from 'k6';
// Hostname que resuelve el ingress — igual que clientes reales
const BASE = __ENV.INGRESS_HOST || 'https://api.staging.example.com';
export const options = {
scenarios: {
checkout_ramp: {
executor: 'ramping-arrival-rate',
startRate: 5,
timeUnit: '1s',
preAllocatedVUs: 20,
maxVUs: 120,
stages: [
{ duration: '2m', target: 20 },
{ duration: '3m', target: 50 },
{ duration: '2m', target: 10 },
],
tags: { route: 'checkout', mesh: __ENV.MESH || 'on' },
exec: 'checkout',
},
},
thresholds: {
http_req_failed: ['rate<0.01'],
'http_req_duration{route:checkout}': ['p(95)<900', 'p(99)<1500'],
},
};
export function checkout() {
const res = http.post(
`${BASE}/v1/checkout`,
JSON.stringify({ sku: 'SKU-1', qty: 1 }),
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${__ENV.API_TOKEN}`,
},
tags: { route: 'checkout', mesh: __ENV.MESH || 'on' },
timeout: '60s', // alinea con proxy-read-timeout del ingress
},
);
check(res, { 'checkout 2xx': (r) => r.status >= 200 && r.status < 300 });
sleep(0.3);
}
Patrones que funcionan
- Revisa anotaciones del ingress (
proxy-read-timeout,proxy-body-size) antes de escalar RPS—un timeout de 30s mata soak de 45m aunque el pod aguante. - Corre k6 desde un runner con egress similar a prod (CI en VPC, no solo laptop) cuando las políticas de red importan.
- Captura en paralelo:
kubectl top pods, eventos HPA, métricas de kube-state; alinea timestamps con el export de k6. - Para colas async downstream, combina con pruebas de carga de pipeline async queue/worker.
Anti-patrones a evitar
- Load test solo contra pod IP—omite TLS termination, WAF y límites de ingress.
- Ignorar
maxReplicasdel HPA durante stress—el test «pasa» porque nunca llegó al techo realista. - Mezclar namespaces sin aislar datos—staging compartido invalida umbrales (ver errores comunes).
Pro tip (comando de ejemplo):
k6 run k8s-checkout-ramp.js -e INGRESS_HOST="https://api.staging.example.com" -e MESH=on \
--summary-export=summary-k8s.json
Qué demuestra este comando: el export JSON se adjunta a tickets de capacidad junto a capturas de kubectl describe hpa en la misma ventana temporal.
Marco de decisión: qué observar según la pregunta
| Pregunta | Acción recomendada |
|---|---|
| ¿El ingress aguanta el pico? | Hostname público + timeout alineado a anotaciones |
| ¿El HPA escala a tiempo? | ramping-arrival-rate + eventos HPA en la rampa |
| ¿El mesh es el costo? | Comparar corrida mesh:on vs mesh:off (solo en entornos permitidos) |
| ¿Capacidad para launch? | Campaña manual + planificación de capacidad desde resultados k6 |
| ¿Regresión por PR? | Smoke bajo RPS en ingress de preview—pruebas de carga en CI/CD |
Usa hostname de ingress si necesitas evidencia que el cliente real verá.
Usa rampas si la hipótesis es autoscaling o colas durante subida de tráfico.
Usa soak controlado si buscas fugas o inestabilidad tras pods estables—ver playbook de soak testing.
Observabilidad y documentación
Antes de escalar más allá del presupuesto acordado con plataforma:
- Documenta FQDN, namespace, versión de chart y
git_shadel servicio bajo test. - Registra
proxy-read-timeouty límites de conexión del ingress en el informe. - Adjunta gráfica de réplicas HPA vs RPS de k6 en la misma línea de tiempo.
- Si usas mesh, anota versión de control plane y política de retries.
- Archiva
summary-k8s.jsony capturas de cluster para postmortems.
Cómo Performate encaja en pruebas K8s
Los equipos pierden días cableando auth, hostnames y metadata de export cada vez que cambia el ingress. Abajo hay un ejemplo concreto de flujo para la API de búsqueda a través del ingress de staging.
Ejemplo: escenario de búsqueda realista por ingress sin hacks de port-forward
- Importa OpenAPI o Postman para
GET /v1/searchcon query params similares a producción. Problema resuelto: URLs y headers coinciden con lo que enruta el ingress—no atajos localhost. - Define
API_BASEal hostname del ingress de staging (https://api.staging.example.com) en el panel de entorno. Problema resuelto: rutas TLS y DNS coinciden con el tráfico del cliente. - Crea escenario ramping-arrival-rate—5→30 req/s en quince minutos. Problema resuelto: ajuste visual de rampa mientras observas el HPA en otra terminal.
- Aplica tags
route:search,target:ingressymesh:on/offdesde entorno. Problema resuelto: reportes aíslan debates de overhead del mesh con datos, no anécdotas. - Define umbrales en
p99y tasa de error del gateway (checks502/504en script). Problema resuelto: gates de release detectan kills del proxy que la latencia media oculta. - Exporta script k6 y resumen con metadata del escenario para la carpeta de postmortem. Problema resuelto: snapshots del cluster y mezclas de tráfico citan el mismo artefacto.
Ese flujo conecta directamente con el cta de este post: escenarios ejecutables y reportes compartibles sin perder días en glue code.
Cierre
En Kubernetes, una prueba de carga creíble golpea ingress + autoscaling + mesh, no solo el contenedor. Usa hostnames de cliente, alinea timeouts de test con el proxy, y correlaciona rampas de k6 con señales del plano de control.
Programa la próxima corrida contra el FQDN de staging con una rampa de 20→50 req/s y anota si el p99 sube antes de que el HPA añada réplicas—esa respuesta vale más que otro test contra IP interna.
Try Performate free | Book a demo | k6 running in Kubernetes
¿Listo para optimizar el rendimiento de tu API?
Usa Performate para convertir este playbook en escenarios k6 ejecutables, umbrales y reportes compartibles sin perder días en código de integración.