Cuellos de Botella Comunes en Jenkins y Cómo Solucionarlos
¿Tu instancia de Jenkins va lenta? Esta guía completa analiza los cuellos de botella comunes de rendimiento en Jenkins, incluyendo fugas de memoria, problemas de espacio en disco y registro excesivo. Aprende a identificar síntomas, comprender las causas raíz e implementar soluciones prácticas como ajuste de JVM, gestión inteligente del historial de compilaciones, optimización de registros y codificación eficiente de pipelines. Descubre herramientas de monitoreo esenciales y mejores prácticas para mantener tus pipelines CI/CD funcionando sin problemas, garantizando compilaciones más rápidas, una interfaz de usuario receptiva y un proceso de entrega de software más eficiente en general.
Cuellos de Botella Comunes en Jenkins y Cómo Solucionarlos
Una instancia lenta de Jenkins generalmente no tiene una sola causa. La interfaz de usuario se siente pesada, las compilaciones esperan en la cola, los agentes se desconectan, los registros tardan una eternidad en abrirse y alguien dice: "Jenkins se cayó otra vez". Detrás de esa queja, el problema suele ser uno de los pocos cuellos de botella comunes: presión del heap del controlador, disco lento, agentes sobrecargados, problemas con plugins, mal comportamiento de pipelines o retrasos en la red hacia los sistemas de control de código fuente y artefactos.
La forma más rápida de solucionar el rendimiento de Jenkins es separar los problemas del controlador de los problemas de compilación. Si la interfaz de usuario de Jenkins, la cola y las páginas de trabajos están lentas incluso cuando no se están ejecutando compilaciones, comienza con el controlador. Si la interfaz de usuario está bien pero las compilaciones tardan demasiado, comienza con los agentes, los espacios de trabajo, los cachés y los sistemas externos.
Memoria del controlador y recolección de basura
El controlador de Jenkins es un proceso Java. Necesita suficiente heap para la configuración de trabajos, plugins, metadatos de compilación, estado de la cola y solicitudes web. Cuando el heap es demasiado pequeño, el controlador dedica demasiado tiempo a la recolección de basura. Cuando un plugin pierde memoria o almacena demasiados datos en memoria, aumentar el heap solo puede retrasar el próximo incidente.
Los síntomas incluyen una interfaz de usuario lenta, pausas largas, OutOfMemoryError, desconexiones frecuentes de agentes o retrasos en la cola de compilación que no coinciden con los ejecutores disponibles.
Primero verifica el proceso y los registros:
ps -o pid,rss,vsz,etime,cmd -C java
journalctl -u jenkins --since "2 hours ago" | grep -Ei 'OutOfMemory|GC overhead|heap|killed'
Para un controlador moderado, un heap de 2 a 4 GB puede ser suficiente. Las instalaciones con mucha actividad pueden necesitar más. No establezcas ciegamente el heap a la mayor parte de la RAM de la máquina. El sistema operativo aún necesita memoria para el caché del sistema de archivos, la sobrecarga del proceso y los agentes de monitoreo.
Las opciones de servicio típicas se ven así:
JENKINS_JAVA_OPTS="-Xms1g -Xmx4g -XX:+UseG1GC"
Después de cambiar las opciones de JVM, reinicia Jenkins durante una ventana de mantenimiento y observa el comportamiento bajo carga normal. Si la memoria aumenta constantemente durante días y nunca se estabiliza, toma un volcado de heap y revisa los plugins instalados o actualizados recientemente. Mantén los plugins actualizados, pero evita actualizar un conjunto grande de plugins sin un plan de reversión.
Espacio en disco y E/S de disco
Jenkins usa el disco constantemente. JENKINS_HOME almacena la configuración de trabajos, registros de compilación, huellas digitales, datos de plugins, secretos, registros y, a veces, demasiados artefactos. Los agentes usan el disco para espacios de trabajo, cachés de dependencias, capas de Docker, informes de pruebas y archivos temporales.
Un disco lleno es obvio. Un disco lento es más molesto porque nada parece estar roto; todo solo espera.
Verifica tanto la capacidad como la latencia:
df -h
du -sh /var/lib/jenkins/* 2>/dev/null | sort -h | tail
iostat -xz 1
Si %util y los tiempos de espera son altos durante las compilaciones, el disco es un cuello de botella. Las soluciones comunes son mover los espacios de trabajo a un almacenamiento más rápido, podar las capas antiguas de Docker, reducir la retención de artefactos y detener los trabajos que archivan directorios completos cuando solo se necesitan informes o paquetes.
Establece políticas de descarte de compilaciones en los trabajos:
options {
buildDiscarder(logRotator(numToKeepStr: '30', artifactNumToKeepStr: '10'))
}
Ten cuidado con la limpieza manual en JENKINS_HOME. No elimines archivos XML aleatorios o directorios de plugins mientras Jenkins se está ejecutando. Usa la configuración de retención de Jenkins, herramientas de limpieza específicas de plugins y copias de seguridad.
Demasiado trabajo en el controlador
Una de las configuraciones más dañinas es ejecutar compilaciones en el controlador. El controlador no debería estar compilando, ejecutando pruebas, construyendo imágenes Docker o haciendo checkouts grandes.
Establece los ejecutores del controlador en 0 en la mayoría de las instalaciones. Pon las compilaciones en los agentes. Si ya ejecutas compilaciones en el controlador, muévelas gradualmente y busca suposiciones ocultas como rutas de herramientas locales, enlaces de credenciales o archivos que solo existen en el controlador.
También verifica los pipelines en busca de código Groovy pesado en el controlador. Los pasos del pipeline como sh se ejecutan en los agentes, pero la lógica Groovy en el Jenkinsfile puede ejecutarse en el controlador. Evita leer archivos grandes en variables Groovy, construir mapas masivos o hacer procesamiento JSON grande en el script del pipeline. Usa shell, Python, jq o tu herramienta de compilación en el agente para trabajos de datos pesados.
Agentes sobrecargados o no coincidentes
Si el tiempo de cola es alto para una etiqueta, agregar ejecutores genéricos no ayudará. Un trabajo que requiere linux && docker && large-memory necesita esa capacidad exacta.
Mira las razones de la cola y el uso de etiquetas. Luego verifica el sistema operativo del agente:
uptime
free -h
mpstat 1
iostat -xz 1
docker system df
Si un agente está haciendo swapping, reduce los ejecutores o aumenta la memoria. Si la CPU está al máximo y la duración de la compilación aumenta durante los períodos de alta actividad, reduce la concurrencia o agrega agentes. Si la espera de E/S es alta, mueve los cachés y espacios de trabajo a un almacenamiento más rápido o reduce el número de trabajos concurrentes en ese nodo.
Para agentes de Kubernetes, las solicitudes de recursos importan tanto como el recuento de ejecutores de Jenkins. Un pod que solicita muy poca CPU o memoria puede programarse en un nodo ya ocupado, y luego Jenkins ve un agente listo mientras la compilación avanza lentamente. Para pods desechables, un ejecutor por pod suele ser más fácil de razonar que múltiples ejecutores compartiendo el mismo contenedor.
Problemas con plugins
Los plugins son uno de los puntos fuertes de Jenkins y también una fuente común de problemas de rendimiento. Un plugin puede agregar costo de renderizado de página, ralentizar la carga de trabajos, retener demasiado historial de compilaciones o hacer llamadas externas durante acciones normales de la interfaz de usuario.
Cuando el rendimiento cambia repentinamente, pregunta qué cambió recientemente:
- Actualización del núcleo de Jenkins.
- Actualización de plugin.
- Instalación de nuevo plugin.
- Nueva configuración global.
- Nueva versión de biblioteca de pipeline.
Usa la información de salud de "Administrar Jenkins", los registros y los registros de cambios de plugins. Si la interfaz de usuario se volvió lenta después de una actualización de plugin, prueba la reversión en un controlador de prueba si tienes uno. Mantén una copia de seguridad de JENKINS_HOME y las versiones de los plugins antes de grandes actualizaciones.
No mantengas plugins "por si acaso". Cada plugin instalado agrega superficie de mantenimiento. Elimina los plugins no utilizados después de verificar las dependencias de los trabajos.
Retrasos en SCM y repositorios de artefactos
Muchos informes de "Jenkins está lento" son en realidad problemas de Git, registro de paquetes, registro de contenedores o repositorio de artefactos.
Revisa los registros de compilación en busca de pasos lentos repetidos:
git fetch
mvn dependency:resolve
npm ci
docker pull
docker push
archiveArtifacts
Si cada trabajo espera en las descargas de dependencias, agrega un proxy o caché cercano. Si git fetch es lento, verifica el tamaño del repositorio, la detección de ramas, la configuración de clonación superficial y la ruta de red desde los agentes al servidor Git. Si las extracciones de Docker son lentas en agentes efímeros, usa un espejo de registro o un caché de registro de BuildKit.
Mantén el diagnóstico honesto: Jenkins programa el trabajo, pero no puede hacer que un registro de paquetes distante sea rápido.
Hinchazón de registros e historial de compilaciones
Los registros de consola grandes ralentizan el renderizado de páginas y ocupan almacenamiento. Los trabajos que imprimen cada fixture de prueba, cada respuesta HTTP o registros de depuración completos durante compilaciones normales eventualmente hacen que Jenkins sea doloroso de usar.
Primero arregla el trabajo. Reduce la verbosidad del registro normal y archiva los registros detallados como artefactos comprimidos solo cuando sea necesario. Mantén la salida de la consola centrada en el progreso y el contexto de fallos.
Luego establece la retención:
options {
buildDiscarder(logRotator(daysToKeepStr: '30', numToKeepStr: '50'))
}
Para entornos con altos requisitos de cumplimiento, mueve los artefactos y registros a largo plazo a un sistema de almacenamiento externo diseñado para retención, búsqueda y políticas de ciclo de vida.
Una ruta de incidente práctica
Cuando Jenkins está lento en este momento, usa este orden:
- Verifica si la interfaz de usuario del controlador está lenta.
- Verifica la CPU, memoria, síntomas de GC y disco del controlador.
- Verifica las razones de la cola y qué etiquetas están esperando.
- Verifica los agentes más ocupados en cuanto a CPU, memoria, disco y crecimiento del espacio de trabajo.
- Compara cambios recientes en plugins, trabajos y bibliotecas compartidas.
- Lee un registro de compilación lento e identifica el paso costoso repetido.
Ese camino evita el ajuste aleatorio. Aumentar el heap no solucionará un agente Docker saturado. Agregar ejecutores no solucionará un disco lleno. Podar espacios de trabajo no solucionará un plugin que causa pausas en el controlador.
Mantén Jenkins mantenible
Las instalaciones saludables de Jenkins tienen hábitos aburridos: ejecutores del controlador en cero, agentes dimensionados para su carga de trabajo, retención de compilaciones configurada, cachés de dependencias intencionales, actualizaciones de plugins rastreadas y métricas básicas exportadas a Prometheus, Grafana, CloudWatch o cualquier sistema de monitoreo que el equipo ya use.
La mejor solución suele ser pequeña y específica. Mueve las compilaciones de Docker a agentes dedicados. Reduce la salida de registro de un trabajo ruidoso. Agrega un proxy de Maven. Reduce los ejecutores en un nodo que está haciendo swapping. Elimina un plugin no utilizado. Pon retención en un trabajo que ha mantenido cada compilación durante años.
El rendimiento de Jenkins mejora cuando dejas de tratarlo como una caja negra y comienzas a seguir el trabajo: desde la cola, hasta el controlador, hasta el agente, hasta el sistema de archivos, hasta la dependencia de red, y de vuelta al registro de compilación.
Ejemplo: la compilación es lenta pero Jenkins está bien
Supón que los desarrolladores informan que las comprobaciones de solicitudes de extracción tardan 25 minutos. La interfaz de usuario de Jenkins es receptiva. La cola es corta. Los agentes están en línea. El registro lento muestra:
git fetch: 20 segundos
npm ci: 9 minutos
pruebas unitarias: 4 minutos
docker build: 10 minutos
archivar artefactos: 1 minuto
Esto no es principalmente un problema del controlador de Jenkins. Las soluciones probables son el almacenamiento en caché de paquetes, el orden de las capas de Dockerfile, el caché de BuildKit y quizás dividir las pruebas. Aumentar el heap del controlador no cambiaría nada.
Ejemplo: todo espera pero los agentes están inactivos
Si los trabajos están en cola mientras los agentes parecen inactivos, lee la razón de la cola. Puede que descubras que los trabajos requieren linux && docker, mientras que los agentes inactivos solo tienen linux. O los trabajos pueden estar bloqueados por disableConcurrentBuilds, un recurso bloqueable o un plugin de nube que no puede aprovisionar agentes coincidentes.
Ese tipo de cuello de botella es de configuración, no de capacidad bruta. Agregar dos agentes no coincidentes no ayudará.
Ejemplo: el controlador se ralentiza cada tarde
Si la interfaz de usuario se degrada a la misma hora cada día, busca trabajos programados: indexación de ramas, copias de seguridad, limpieza de artefactos grandes, escaneos de vulnerabilidades o pipelines nocturnos que comienzan demasiado temprano. Verifica la CPU, el heap y la E/S de disco del controlador durante esa ventana. También verifica si muchos trabajos comienzan exactamente al mismo minuto debido a expresiones cron como 0 2 * * *.
En los horarios de Jenkins, prefiere el tiempo hash cuando sea posible:
H 2 * * *
Eso distribuye los trabajos en lugar de comenzar todo a la hora en punto.
Lo que un buen monitoreo debería responder
Como mínimo, el monitoreo debería responder estas preguntas sin iniciar sesión en el servidor:
- ¿El proceso del controlador está vivo y receptivo?
- ¿Cuánto heap se está usando y con qué frecuencia se ejecuta la recolección de basura?
- ¿Cuánto tiempo están esperando los trabajos en la cola por etiqueta?
- ¿Qué agentes están fuera de línea o reconectándose repetidamente?
- ¿Los discos del controlador y los agentes están cerca de llenarse?
- ¿Las compilaciones se están volviendo más lentas con el tiempo para los mismos trabajos?
No necesitas un panel perfecto para empezar. Incluso unas pocas métricas y alertas para disco, heap, longitud de cola y disponibilidad de agentes detectarán muchas fallas antes de que los desarrolladores las informen.