Dominando la optimización de ejecutores de Jenkins para compilaciones más rápidas
Optimiza el rendimiento de tu CI/CD dominando la configuración de ejecutores de Jenkins. Esta guía experta explica cómo calcular la cantidad óptima de ejecutores según las restricciones de CPU y E/S, reduciendo los tiempos de cola de compilación y maximizando el rendimiento de los agentes. Aprende estrategias de configuración esenciales, incluyendo el uso de paralelismo en Pipeline, la gestión de agentes estáticos vs. dinámicos, y la identificación de cuellos de botella mediante métricas clave como la longitud de la cola y la espera de E/S. Implementa estos pasos prácticos para lograr compilaciones más rápidas y un entorno Jenkins más eficiente.
Dominando la optimización de ejecutores de Jenkins para compilaciones más rápidas
La optimización de ejecutores de Jenkins es, en realidad, planificación de capacidad en pequeñas piezas. Un ejecutor es un espacio donde Jenkins puede ejecutar trabajo en un nodo. Agrega muy pocos espacios y los trabajos esperan en la cola. Agrega demasiados y cada compilación lucha por CPU, memoria, disco, red y, a veces, la misma caché de dependencias.
El objetivo no es "más ejecutores". El objetivo es un tiempo de retroalimentación total más corto sin hacer que las compilaciones individuales sean poco confiables.
Mantén los ejecutores del controlador en cero
Para la mayoría de las instalaciones modernas de Jenkins, el controlador debe programar trabajo, servir la interfaz de usuario, almacenar la configuración del trabajo y coordinar agentes. No debe compilar código ni ejecutar suites de pruebas.
Establece los ejecutores del controlador en 0 a menos que tengas un trabajo administrativo pequeño y deliberado que deba ejecutarse allí. Una compilación ocupada en el controlador puede privar a la interfaz de usuario, retrasar la programación de la cola y hacer que los problemas de los complementos sean más difíciles de diagnosticar. Si el controlador se vuelve inestable, todos los equipos que usan Jenkins lo sienten.
Mueve el trabajo de compilación a agentes con etiquetas claras:
linux && docker
linux && maven
windows && visualstudio
large-memory
Las etiquetas son parte de la optimización de ejecutores porque un trabajo que espera linux && docker no le importa que tengas ejecutores de Windows inactivos.
Comienza con el tipo de carga de trabajo, no con una fórmula universal
Para compilaciones con uso intensivo de CPU, comienza cerca del número de núcleos de CPU físicos o virtuales. Una máquina virtual de compilación de 8 núcleos que ejecuta compilación de C++ o grandes suites de pruebas de Java podría comenzar con 6 a 8 ejecutores, luego bajar o subir según las mediciones.
Para compilaciones con uso intensivo de E/S, es posible que ejecutes más ejecutores que núcleos de CPU porque los trabajos pasan tiempo esperando descargas de red, cargas de artefactos o servicios de prueba. Un agente de 8 núcleos con muchas dependencias podría manejar bien de 10 a 12 ejecutores. También podría colapsar con 6 si el disco es lento o la memoria es escasa.
La memoria a menudo establece el límite real. Si cada compilación puede usar 2 GB de RAM y el agente tiene 16 GB, ocho ejecutores no dejan espacio para el sistema operativo, el demonio Docker, los tiempos de ejecución del lenguaje, las pruebas del navegador o la caché del sistema de archivos. En ese caso, cuatro o cinco ejecutores pueden ser más rápidos que ocho porque la máquina evita el intercambio.
Usa una hoja de trabajo como esta:
RAM del agente: 32 GB
reserva para SO y demonios: 4 GB
utilizable para compilaciones: 28 GB
pico típico de compilación: 3 GB
ejecutores iniciales: 8 o 9, luego validar bajo carga
Los números no necesitan ser perfectos. Deben ser lo suficientemente explícitos para que puedas ajustarlos después de observar compilaciones reales.
Observa las razones de la cola
La cola de compilación de Jenkins te dice por qué el trabajo está esperando. "Esperando el próximo ejecutor disponible" es diferente de "No hay nodos con la etiqueta". El primero sugiere presión de capacidad. El segundo sugiere problemas de etiquetado o aprovisionamiento de agentes.
Cuando los desarrolladores se quejan de que Jenkins es lento, verifica:
- Longitud de la cola por etiqueta.
- Tiempo promedio de espera en la cola.
- Cambio de estado en línea/fuera de línea del agente.
- Compilaciones atascadas esperando recursos bloqueados.
- Etapas de pipeline paralelas que consumen más ejecutores de lo esperado.
Un solo pipeline con diez ramas paralelas puede consumir diez espacios de ejecutor. Eso puede ser exactamente lo que deseas para una matriz de pruebas. También puede privar a todos los demás trabajos en una instalación pequeña de Jenkins.
Usa un ejecutor por agente desechable
Para agentes de Kubernetes y muchos agentes creados en la nube, un ejecutor por pod o instancia suele ser el modelo más limpio. El pod es la unidad de aislamiento. Si necesitas más concurrencia, crea más pods en lugar de empaquetar compilaciones no relacionadas en el mismo espacio de trabajo desechable.
Ese modelo hace que las solicitudes de recursos sean importantes:
resources:
requests:
cpu: "2"
memory: "4Gi"
limits:
memory: "6Gi"
Si las solicitudes son demasiado bajas, Kubernetes puede empaquetar demasiados agentes de Jenkins en un solo nodo. Jenkins ve ejecutores disponibles, pero el nodo del clúster está sobrecargado. Si los límites son demasiado ajustados, las compilaciones fallan con errores de memoria que parecen problemas de la aplicación.
Para agentes VM estáticos, múltiples ejecutores pueden estar bien. Solo mantén el diseño del espacio de trabajo, los directorios de caché y las instalaciones de herramientas diseñadas para trabajos concurrentes.
Limita los trabajos ruidosos
Algunos trabajos no deberían ejecutar tantas copias como Jenkins pueda programar. Las pruebas de integración de bases de datos, las pruebas de navegador, las pruebas de carga y las compilaciones de imágenes pueden saturar rápidamente los sistemas compartidos.
Usa limitaciones a nivel de trabajo, recursos bloqueables o controles de pipeline:
pipeline {
agent { label 'linux && docker' }
options {
disableConcurrentBuilds()
}
stages {
stage('Build Image') {
steps {
sh 'docker build -t app:${BUILD_NUMBER} .'
}
}
}
}
Para una base de datos de staging compartida, un bloqueo es más claro:
lock('staging-db') {
sh './run-integration-tests.sh'
}
Esto puede hacer que un trabajo espere, pero evita que cinco trabajos fallen juntos y desperdicien todo su tiempo de ejecutor.
Mide el agente, no solo Jenkins
Jenkins puede informarte sobre el tiempo de cola y el uso del ejecutor. El sistema operativo te dice si el número de ejecutores es razonable.
En agentes Linux, verifica:
uptime
mpstat 1
iostat -xz 1
free -h
df -h
docker system df
CPU alta con baja espera de E/S significa trabajo intensivo en CPU. Espera de E/S alta significa que agregar ejecutores probablemente hará que las compilaciones sean más lentas. El uso de intercambio durante las compilaciones es una señal fuerte para reducir los ejecutores o aumentar la memoria. Un disco casi lleno puede hacer que la verificación, el archivado y las compilaciones de Docker sean lentos.
Observa también la duración de la compilación individual. Si el tiempo de cola disminuye en un minuto pero cada compilación se vuelve cinco minutos más lenta, el mayor número de ejecutores no es una victoria.
Ajusta en cambios pequeños
Cambia los recuentos de ejecutores gradualmente. Mueve un agente de 4 a 6, observa durante unos días ocupados, luego decide. Los saltos grandes ocultan la causa de las regresiones.
Mantén notas:
2026-05-24: linux-build-03 ejecutores 4 -> 6
Motivo: cola para linux && maven con un promedio de 12 minutos
Observar: CPU, iowait, contención de bloqueo de caché de Maven, duración de compilación
Revertir: establecer en 4 si la duración de compilación p95 aumenta más de lo esperado
Ese breve registro ayuda cuando alguien pregunta por qué el agente es lento dos semanas después.
El objetivo práctico
Una configuración saludable de Jenkins tiene la mayoría de los agentes ocupados durante los períodos pico, colas cortas para etiquetas comunes, sin intercambio, duración de compilación predecible y sin compilaciones del controlador. También tiene suficiente capacidad específica de etiqueta para que la falta de un agente Docker no deje trabajos Maven no relacionados esperando.
La optimización de ejecutores no es una configuración única. Cambia cuando tus equipos agreguen etapas paralelas, se muevan a suites de pruebas más grandes, adopten compilaciones Docker o migren de VM estáticas a agentes Kubernetes. Revísala cuando el tiempo de cola se vuelva visible, cuando los agentes comiencen a intercambiar, o cuando la solución más rápida que la gente sugiera sea "solo agrega más ejecutores". A veces eso es correcto. A menudo, la mejor solución es un nuevo grupo de agentes, mejores etiquetas o menos copias concurrentes del trabajo que perjudica a todos los demás.
Las etapas paralelas necesitan un presupuesto
El paralelismo de Pipeline puede ser una gran ventaja, pero gasta ejecutores rápidamente. Una compilación de matriz en cuatro versiones de Java y tres sistemas operativos puede crear doce ramas. Si cada rama se ejecuta en un agente separado, esa única compilación puede consumir doce ejecutores antes de que las etapas de implementación siquiera comiencen.
Eso es aceptable cuando el equipo lo ha planeado. Es doloroso cuando una sola solicitud de extracción priva de recursos a las compilaciones de lanzamiento. Pon límites alrededor de los trabajos de gran expansión:
options {
parallelsAlwaysFailFast()
}
Usa etiquetas que envíen ramas costosas al grupo correcto, y considera ejecutar la matriz completa en main mientras ejecutas una matriz más pequeña en las solicitudes de extracción. El objetivo es una retroalimentación rápida donde importa, no la máxima concurrencia en todas partes.
Separa las expectativas interactivas y por lotes
No todos los trabajos de Jenkins merecen el mismo objetivo de cola. Una compilación de hotfix de producción, un trabajo de validación de solicitud de extracción, un escaneo de seguridad nocturno y un trabajo de limpieza semanal pueden ejecutarse en Jenkins, pero no deberían competir por igual.
Puedes separarlos con etiquetas, períodos de silencio, limitaciones y ventanas programadas. Los trabajos nocturnos pesados deben ejecutarse cuando el tráfico de PR interactivo es bajo. Las pruebas de carga de larga duración deben tener sus propios agentes. Los trabajos de lanzamiento pueden merecer capacidad reservada o una etiqueta que los trabajos de rama ordinarios no puedan usar.
Esto es menos sobre política que sobre confiabilidad. Si cada carga de trabajo comparte un grupo de ejecutores, la carga de trabajo más ruidosa establece la experiencia para todos.
Qué documentar
Para cada grupo de agentes, mantén un pequeño registro:
etiqueta: linux && docker
tipo de agente: VM estática
ejecutores por agente: 4
cargas de trabajo principales: compilaciones de imágenes Docker, pruebas de integración
límites conocidos: E/S de disco y crecimiento de capas de Docker
limpieza: docker prune nocturno, limpieza del espacio de trabajo después de la compilación
propietario: equipo de plataforma
Ese registro facilita mucho el ajuste futuro. Cuando el tiempo de cola crezca, puedes decidir si agregar más agentes del mismo tipo, dividir una carga de trabajo en un nuevo grupo o reducir la concurrencia en los trabajos que causan contención.