如何在Jenkins Pipeline中并行执行脚本以充分利用所有节点
Jenkins 节点动态分配优化实现
前置条件
- 4个节点已绑定同一标签
Autolabel,全部接入Jenkins服务器并处于运行状态 - Jenkins Pipeline当前包含三个并行阶段:
sanitylist1、sanitylist2、sanitylist3 - 当前使用的Groovy脚本如下:
def sanitylist1 = script1.sh, script2.sh, script3.sh //All these are read from string parameter def sanitylist2 = script4.sh, script5.sh, script6.sh def sanitylist3 = script7.sh, script8.sh, script9.sh stage('Santiy tests') { parallel { stage('SanityList1') { options { timestamps() timeout(time: 6, unit: 'HOURS') } agent { node { label 'Autolabel' customWorkspace 'C:/git_repository' } } steps { script { for (i in sanitylist1) { echo "running : ${i}" bat "test.bat ${i}" //takes one script from sanitylist1 and replays sleep(10) } } } } stage('SanityList2') { options { timestamps() timeout(time: 6, unit: 'HOURS') } agent { node { label 'Autolabel' customWorkspace 'C:/git_repository' } } steps { script { for (i in sanitylist2) { echo "running : ${i}" bat "test.bat ${i}" //takes one script from sanitylist1 and replays sleep(10) } } } } stage('SanityList3') { options { timestamps() timeout(time: 6, unit: 'HOURS') } agent { node { label 'Autolabel' customWorkspace 'C:/git_repository' } } steps { script { for (i in sanitylist3) { echo "running : ${i}" bat "test.bat ${i}" //takes one script from sanitylist1 and replays sleep(10) } } } } } //parallel } //parallel stage
需求
现有4个可用节点,但当前仅3个被占用,1个处于闲置状态。需实现动态分配闲置节点执行sanitylist1、sanitylist2或sanitylist3中的下一个脚本,提升执行效率,且无需新建SanityList4阶段。
实现方案
方案1:全局任务池动态并行(推荐)
打破原有阶段绑定,将所有脚本合并为一个任务池,让Jenkins自动根据可用节点数量分配任务,最大化利用4个节点资源。
修改后的脚本:
// 修正原脚本的数组定义(从字符串参数读取时需确保为数组格式) def sanitylist1 = ['script1.sh', 'script2.sh', 'script3.sh'] def sanitylist2 = ['script4.sh', 'script5.sh', 'script6.sh'] def sanitylist3 = ['script7.sh', 'script8.sh', 'script9.sh'] // 合并所有脚本为统一任务池 def allSanityTasks = sanitylist1 + sanitylist2 + sanitylist3 stage('Sanity tests') { // 为每个脚本创建独立并行任务,Jenkins自动分配空闲节点 parallel allSanityTasks.collectEntries { script -> ["Execute ${script}": { options { timestamps() timeout(time: 6, unit: 'HOURS') } agent { node { label 'Autolabel' customWorkspace 'C:/git_repository' } } steps { script { echo "running : ${script}" bat "test.bat ${script}" sleep(10) } } }] } }
方案优势:
- 完全释放节点资源,4个节点会同时执行不同脚本,直到所有任务完成
- 无需维护固定阶段数量,脚本数量变化时自动适配
- 保留原有的超时、时间戳、工作区配置
方案2:保留原阶段,动态申请节点
如果需要保留原有的sanitylist1/2/3阶段分组,可让每个脚本执行时单独申请空闲节点,避免整个阶段占用节点导致资源浪费。
修改后的脚本:
def sanitylist1 = ['script1.sh', 'script2.sh', 'script3.sh'] def sanitylist2 = ['script4.sh', 'script5.sh', 'script6.sh'] def sanitylist3 = ['script7.sh', 'script8.sh', 'script9.sh'] // 封装通用执行逻辑 def runSanityScript(String script) { node('Autolabel') { customWorkspace 'C:/git_repository' timestamps { timeout(time: 6, unit: 'HOURS') { echo "running : ${script}" bat "test.bat ${script}" sleep(10) } } } } stage('Sanity tests') { parallel { stage('SanityList1') { steps { script { sanitylist1.each { script -> runSanityScript(script) } } } } stage('SanityList2') { steps { script { sanitylist2.each { script -> runSanityScript(script) } } } } stage('SanityList3') { steps { script { sanitylist3.each { script -> runSanityScript(script) } } } } } }
方案优势:
- 保留原有阶段分组逻辑,便于查看各分组执行状态
- 每个脚本执行完成后立即释放节点,其他阶段的待执行脚本可抢占空闲节点,避免资源闲置
内容的提问来源于stack exchange,提问作者sridattas
相关产品推荐
相关产品推荐

