Padroneggiare l'ottimizzazione degli executor di Jenkins per build più veloci

Ottimizza le prestazioni della tua CI/CD padroneggiando la configurazione degli executor di Jenkins. Questa guida esperta spiega come calcolare il numero ottimale di executor in base ai vincoli di CPU e I/O, riducendo i tempi di coda delle build e massimizzando il throughput degli agenti. Impara strategie di configurazione essenziali, tra cui l'utilizzo del parallelismo delle pipeline, la gestione di agenti statici vs. dinamici e l'identificazione dei colli di bottiglia utilizzando metriche chiave come la lunghezza della coda e l'attesa I/O. Implementa questi passaggi pratici per ottenere build più veloci e un ambiente Jenkins più efficiente.

Padroneggiare l'ottimizzazione degli executor di Jenkins per build più veloci

L'ottimizzazione degli executor di Jenkins è essenzialmente una pianificazione della capacità in piccoli pezzi. Un executor è uno slot in cui Jenkins può eseguire lavoro su un nodo. Aggiungi troppo pochi slot e i lavori aspettano in coda. Aggiungine troppi e ogni build combatte per CPU, memoria, disco, rete e talvolta la stessa cache delle dipendenze.

L'obiettivo non è "più executor". L'obiettivo è un tempo di feedback totale più breve senza rendere le singole build inaffidabili.

Mantieni gli executor del controller a zero

Per la maggior parte delle installazioni moderne di Jenkins, il controller dovrebbe pianificare il lavoro, servire l'interfaccia utente, memorizzare la configurazione dei lavori e coordinare gli agenti. Non dovrebbe compilare codice o eseguire suite di test.

Imposta gli executor del controller a 0 a meno che tu non abbia un piccolo lavoro amministrativo deliberato che deve essere eseguito lì. Una build intensa sul controller può affamare l'interfaccia utente, ritardare la pianificazione della coda e rendere più difficili da diagnosticare i problemi dei plugin. Se il controller diventa instabile, ogni team che utilizza Jenkins lo sente.

Sposta il lavoro di build sugli agenti con etichette chiare:

linux && docker
linux && maven
windows && visualstudio
large-memory

Le etichette fanno parte dell'ottimizzazione degli executor perché un lavoro in attesa di linux && docker non si preoccupa che tu abbia executor Windows inattivi.

Inizia dal tipo di carico di lavoro, non da una formula universale

Per build pesanti sulla CPU, inizia vicino al numero di core CPU fisici o virtuali. Una VM di build a 8 core che esegue compilazione C++ o grandi suite di test Java potrebbe iniziare con 6-8 executor, poi scendere o salire in base alle misurazioni.

Per build pesanti sull'I/O, potresti eseguire più executor dei core CPU perché i lavori passano tempo in attesa di download di rete, caricamenti di artefatti o servizi di test. Un agente a 8 core con molte dipendenze potrebbe gestire bene 10-12 executor. Potrebbe anche collassare a 6 se il disco è lento o la memoria è scarsa.

La memoria spesso imposta il limite reale. Se ogni build può utilizzare 2 GB di RAM e l'agente ha 16 GB, otto executor non lasciano spazio per il sistema operativo, il demone Docker, i runtime dei linguaggi, i test del browser o la cache del filesystem. In tal caso, quattro o cinque executor potrebbero essere più veloci di otto perché la macchina evita lo swapping.

Usa un foglio di lavoro come questo:

RAM agente: 32 GB
riserva per OS e demoni: 4 GB
utilizzabile per build: 28 GB
picco tipico di build: 3 GB
executor iniziali: 8 o 9, poi convalida sotto carico

I numeri non devono essere perfetti. Devono essere abbastanza espliciti da poterli regolare dopo aver osservato le build reali.

Osserva i motivi della coda

La coda di build di Jenkins ti dice perché il lavoro è in attesa. "In attesa del prossimo executor disponibile" è diverso da "Non ci sono nodi con l'etichetta". Il primo suggerisce pressione sulla capacità. Il secondo suggerisce problemi di etichettatura o provisioning degli agenti.

Quando gli sviluppatori si lamentano che Jenkins è lento, controlla:

  • Lunghezza della coda per etichetta.
  • Tempo medio di attesa in coda.
  • Agitazione online/offline degli agenti.
  • Build bloccate in attesa di risorse bloccate.
  • Fasi di pipeline parallele che consumano più executor del previsto.

Una singola pipeline con dieci rami paralleli può consumare dieci slot executor. Questo potrebbe essere esattamente ciò che desideri per una matrice di test. Potrebbe anche affamare ogni altro lavoro su una piccola installazione Jenkins.

Usa un executor per agente usa e getta

Per agenti Kubernetes e molti agenti creati nel cloud, un executor per pod o istanza è di solito il modello più pulito. Il pod è l'unità di isolamento. Se hai bisogno di più concorrenza, crea più pod invece di impacchettare build non correlate nello stesso spazio di lavoro usa e getta.

Questo modello rende importanti le richieste di risorse:

resources:
  requests:
    cpu: "2"
    memory: "4Gi"
  limits:
    memory: "6Gi"

Se le richieste sono troppo basse, Kubernetes potrebbe impacchettare troppi agenti Jenkins su un singolo nodo. Jenkins vede executor disponibili, ma il nodo del cluster è sovraccarico. Se i limiti sono troppo stretti, le build falliscono con errori di memoria che sembrano problemi dell'applicazione.

Per agenti VM statici, più executor possono andare bene. Mantieni solo il layout dello spazio di lavoro, le directory della cache e le installazioni degli strumenti progettati per lavori concorrenti.

Limita i lavori rumorosi

Alcuni lavori non dovrebbero eseguire tante copie quante Jenkins può pianificare. Test di integrazione del database, test del browser, test di carico e build di immagini possono saturare rapidamente i sistemi condivisi.

Usa limitazioni a livello di lavoro, risorse bloccabili o controlli della pipeline:

pipeline {
  agent { label 'linux && docker' }
  options {
    disableConcurrentBuilds()
  }
  stages {
    stage('Build Image') {
      steps {
        sh 'docker build -t app:${BUILD_NUMBER} .'
      }
    }
  }
}

Per un database di staging condiviso, un blocco è più chiaro:

lock('staging-db') {
  sh './run-integration-tests.sh'
}

Questo potrebbe far aspettare un lavoro, ma impedisce a cinque lavori di fallire insieme e sprecare tutto il loro tempo executor.

Misura l'agente, non solo Jenkins

Jenkins può dirti il tempo di coda e l'uso degli executor. Il sistema operativo ti dice se il numero di executor è ragionevole.

Su agenti Linux, controlla:

uptime
mpstat 1
iostat -xz 1
free -h
df -h
docker system df

CPU alta con bassa attesa I/O significa lavoro vincolato alla CPU. Alta attesa I/O significa che aggiungere executor probabilmente rallenterà le build. L'uso di swap durante le build è un forte segnale per ridurre gli executor o aumentare la memoria. Un disco quasi pieno può far strisciare il checkout, l'archiviazione e le build Docker.

Guarda anche la durata delle singole build. Se il tempo di coda diminuisce di un minuto ma ogni build diventa cinque minuti più lenta, il numero più alto di executor non è un vantaggio.

Ottimizza con piccole modifiche

Cambia il numero di executor gradualmente. Sposta un agente da 4 a 6, osserva per alcuni giorni intensi, poi decidi. Grandi salti nascondono la causa delle regressioni.

Tieni appunti:

2026-05-24: linux-build-03 executor 4 -> 6
Motivo: coda per linux && maven in media 12 minuti
Osserva: CPU, iowait, contesa cache Maven, durata build
Ripristino: imposta a 4 se la durata p95 della build aumenta più del previsto

Quel breve record aiuta quando qualcuno chiede perché l'agente è lento due settimane dopo.

L'obiettivo pratico

Una configurazione Jenkins sana ha la maggior parte degli agenti occupati durante i periodi di punta, code brevi per etichette comuni, nessuno swap, durata delle build prevedibile e nessuna build del controller. Ha anche capacità sufficiente specifica per etichetta in modo che un agente Docker mancante non lasci in attesa lavori Maven non correlati.

L'ottimizzazione degli executor non è un'impostazione una tantum. Cambia quando i tuoi team aggiungono fasi parallele, passano a suite di test più grandi, adottano build Docker o migrano da VM statiche ad agenti Kubernetes. Rivedila quando il tempo di coda diventa visibile, quando gli agenti iniziano a fare swap, o quando la soluzione più veloce che le persone suggeriscono è "basta aggiungere più executor". A volte è corretto. Spesso, la soluzione migliore è un nuovo pool di agenti, etichette migliori o meno copie concorrenti del lavoro che danneggia tutti gli altri.

Le fasi parallele hanno bisogno di un budget

Il parallelismo delle pipeline può essere un grande vantaggio, ma consuma rapidamente gli executor. Una build a matrice su quattro versioni Java e tre sistemi operativi può creare dodici rami. Se ogni ramo viene eseguito su un agente separato, quella singola build può consumare dodici executor prima ancora che inizino le fasi di distribuzione.

Ciò è accettabile quando il team lo ha pianificato. È doloroso quando una singola richiesta pull affama le build di rilascio. Metti limiti attorno ai lavori con grande fan-out:

options {
  parallelsAlwaysFailFast()
}

Usa etichette che inviano rami costosi al pool giusto e considera di eseguire la matrice completa su main mentre si esegue una matrice più piccola sulle richieste pull. L'obiettivo è un feedback rapido dove conta, non la massima concorrenza ovunque.

Separa le aspettative interattive e batch

Non tutti i lavori Jenkins meritano lo stesso obiettivo di coda. Una build di hotfix di produzione, un lavoro di convalida di richiesta pull, una scansione di sicurezza notturna e un lavoro di pulizia settimanale possono tutti essere eseguiti in Jenkins, ma non dovrebbero competere allo stesso modo.

Puoi separarli con etichette, periodi di quiete, limitazioni e finestre programmate. I lavori notturni pesanti dovrebbero essere eseguiti quando il traffico PR interattivo è basso. I test di carico di lunga durata dovrebbero avere i propri agenti. I lavori di rilascio potrebbero meritare capacità riservata o un'etichetta che i lavori di ramo ordinari non possono utilizzare.

Questo è più una questione di affidabilità che di politica. Se ogni carico di lavoro condivide un pool di executor, il carico di lavoro più rumoroso imposta l'esperienza per tutti.

Cosa documentare

Per ogni pool di agenti, mantieni un piccolo record:

etichetta: linux && docker
tipo agente: VM statico
executor per agente: 4
carichi di lavoro principali: build immagini Docker, test di integrazione
limiti noti: I/O disco e crescita layer Docker
pulizia: docker prune notturno, pulizia spazio di lavoro dopo la build
proprietario: team piattaforma

Questo record rende molto più facile l'ottimizzazione futura. Quando il tempo di coda cresce, puoi decidere se aggiungere più agenti dello stesso tipo, dividere un carico di lavoro in un nuovo pool o ridurre la concorrenza sui lavori che causano contesa.