欢迎光临
我们一直在努力

Jenkins分布式构建完全指南:从原理到实践步骤

Jenkins分布式构建完全指南:从原理到实践步骤

    • 一、分布式构建的核心架构
      • 1.1 🟢 什么是分布式构建?
      • 1.2 🔵 三大核心组件
      • 1.3 🟡 分布式构建的工作流程
    • 二、配置分布式构建:完整步骤
      • 2.1 🟠 环境准备
      • 2.2 🔴 方式一:SSH连接添加Agent(推荐)
      • 2.3 🟣 方式二:JNLP方式连接(跨平台场景)
      • 2.4 🔵 Docker容器化Agent(云原生方式)
    • 三、将任务调度到Agent节点
      • 3.1 🟢 Freestyle项目配置
      • 3.2 🟡 Pipeline项目配置
    • 四、最佳实践与优化建议
      • 4.1 🔴 Master轻量化
      • 4.2 🟣 负载均衡与并发
      • 4.3 🟠 安全性加固
    • 五、常见问题排查
    • 六、总结

🌺The Begin🌺点点关注,收藏不迷路🌺

⬇ ⬇ 底部 ⬇ ⬇

🌐 当项目规模扩大、构建任务激增时,单台Jenkins服务器往往成为性能瓶颈。Jenkins的分布式构建能力可以将任务分散到多台机器上并行执行,大幅提升CI/CD效率。本文将详细解析Master-Agent架构原理,并手把手带你完成分布式构建的完整配置。

一、分布式构建的核心架构

1.1 🟢 什么是分布式构建?

Jenkins的分布式构建是指将构建任务分配到多台机器上执行,而不是仅依赖单台Jenkins主节点(Master)。通过这种方式,可以显著提高构建效率,特别是在大型项目中,构建任务可能需要大量的计算资源。

💡 形象理解:可以把Master比作“项目总指挥”,负责派发任务和收集结果;而Agent则是“施工队”,在各自的工地上真正完成建造工作。

1.2 🔵 三大核心组件

#mermaid-svg-atfKVx4MyXXGMdWm{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-atfKVx4MyXXGMdWm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-atfKVx4MyXXGMdWm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-atfKVx4MyXXGMdWm .error-icon{fill:#552222;}#mermaid-svg-atfKVx4MyXXGMdWm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-atfKVx4MyXXGMdWm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-atfKVx4MyXXGMdWm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-atfKVx4MyXXGMdWm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-atfKVx4MyXXGMdWm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-atfKVx4MyXXGMdWm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-atfKVx4MyXXGMdWm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-atfKVx4MyXXGMdWm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-atfKVx4MyXXGMdWm .marker.cross{stroke:#333333;}#mermaid-svg-atfKVx4MyXXGMdWm svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-atfKVx4MyXXGMdWm p{margin:0;}#mermaid-svg-atfKVx4MyXXGMdWm .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-atfKVx4MyXXGMdWm .cluster-label text{fill:#333;}#mermaid-svg-atfKVx4MyXXGMdWm .cluster-label span{color:#333;}#mermaid-svg-atfKVx4MyXXGMdWm .cluster-label span p{background-color:transparent;}#mermaid-svg-atfKVx4MyXXGMdWm .label text,#mermaid-svg-atfKVx4MyXXGMdWm span{fill:#333;color:#333;}#mermaid-svg-atfKVx4MyXXGMdWm .node rect,#mermaid-svg-atfKVx4MyXXGMdWm .node circle,#mermaid-svg-atfKVx4MyXXGMdWm .node ellipse,#mermaid-svg-atfKVx4MyXXGMdWm .node polygon,#mermaid-svg-atfKVx4MyXXGMdWm .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-atfKVx4MyXXGMdWm .rough-node .label text,#mermaid-svg-atfKVx4MyXXGMdWm .node .label text,#mermaid-svg-atfKVx4MyXXGMdWm .image-shape .label,#mermaid-svg-atfKVx4MyXXGMdWm .icon-shape .label{text-anchor:middle;}#mermaid-svg-atfKVx4MyXXGMdWm .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-atfKVx4MyXXGMdWm .rough-node .label,#mermaid-svg-atfKVx4MyXXGMdWm .node .label,#mermaid-svg-atfKVx4MyXXGMdWm .image-shape .label,#mermaid-svg-atfKVx4MyXXGMdWm .icon-shape .label{text-align:center;}#mermaid-svg-atfKVx4MyXXGMdWm .node.clickable{cursor:pointer;}#mermaid-svg-atfKVx4MyXXGMdWm .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-atfKVx4MyXXGMdWm .arrowheadPath{fill:#333333;}#mermaid-svg-atfKVx4MyXXGMdWm .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-atfKVx4MyXXGMdWm .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-atfKVx4MyXXGMdWm .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-atfKVx4MyXXGMdWm .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-atfKVx4MyXXGMdWm .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-atfKVx4MyXXGMdWm .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-atfKVx4MyXXGMdWm .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-atfKVx4MyXXGMdWm .cluster text{fill:#333;}#mermaid-svg-atfKVx4MyXXGMdWm .cluster span{color:#333;}#mermaid-svg-atfKVx4MyXXGMdWm div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-atfKVx4MyXXGMdWm .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-atfKVx4MyXXGMdWm rect.text{fill:none;stroke-width:0;}#mermaid-svg-atfKVx4MyXXGMdWm .icon-shape,#mermaid-svg-atfKVx4MyXXGMdWm .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-atfKVx4MyXXGMdWm .icon-shape p,#mermaid-svg-atfKVx4MyXXGMdWm .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-atfKVx4MyXXGMdWm .icon-shape .label rect,#mermaid-svg-atfKVx4MyXXGMdWm .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-atfKVx4MyXXGMdWm .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-atfKVx4MyXXGMdWm .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-atfKVx4MyXXGMdWm :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

SSH / JNLP / WebSocket

SSH / JNLP / WebSocket

返回构建结果

返回构建结果

🤖 Agent 节点 2

执行器1

执行器2

🤖 Agent 节点 1

执行器1

执行器2

执行器3

🎯 Jenkins Master(控制器)

任务调度与分配

配置与插件管理

构建状态监控

Web UI与API服务

各组件职责:

组件核心职责关键特性
Master(控制器) 管理任务调度、插件与系统设置、Web UI服务 构建的“大脑”,负责决策与调度
Agent(代理节点) 执行具体的构建、测试、部署任务 构建的“手脚”,实际干活
Executor(执行器) Agent上的执行线程,决定并发构建数 一个Executor就是一个任务执行槽位

1.3 🟡 分布式构建的工作流程

Jenkins Agent

任务队列

Jenkins Master

用户/开发者

Jenkins Agent

任务队列

Jenkins Master

用户/开发者

#mermaid-svg-pMeFXRkA6EuW2Wps{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-pMeFXRkA6EuW2Wps .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pMeFXRkA6EuW2Wps .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pMeFXRkA6EuW2Wps .error-icon{fill:#552222;}#mermaid-svg-pMeFXRkA6EuW2Wps .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pMeFXRkA6EuW2Wps .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pMeFXRkA6EuW2Wps .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pMeFXRkA6EuW2Wps .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pMeFXRkA6EuW2Wps .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pMeFXRkA6EuW2Wps .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pMeFXRkA6EuW2Wps .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pMeFXRkA6EuW2Wps .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pMeFXRkA6EuW2Wps .marker.cross{stroke:#333333;}#mermaid-svg-pMeFXRkA6EuW2Wps svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pMeFXRkA6EuW2Wps p{margin:0;}#mermaid-svg-pMeFXRkA6EuW2Wps .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-pMeFXRkA6EuW2Wps text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-pMeFXRkA6EuW2Wps .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-pMeFXRkA6EuW2Wps .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-pMeFXRkA6EuW2Wps .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-pMeFXRkA6EuW2Wps .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-pMeFXRkA6EuW2Wps #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-pMeFXRkA6EuW2Wps .sequenceNumber{fill:white;}#mermaid-svg-pMeFXRkA6EuW2Wps #sequencenumber{fill:#333;}#mermaid-svg-pMeFXRkA6EuW2Wps #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-pMeFXRkA6EuW2Wps .messageText{fill:#333;stroke:none;}#mermaid-svg-pMeFXRkA6EuW2Wps .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-pMeFXRkA6EuW2Wps .labelText,#mermaid-svg-pMeFXRkA6EuW2Wps .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-pMeFXRkA6EuW2Wps .loopText,#mermaid-svg-pMeFXRkA6EuW2Wps .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-pMeFXRkA6EuW2Wps .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-pMeFXRkA6EuW2Wps .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-pMeFXRkA6EuW2Wps .noteText,#mermaid-svg-pMeFXRkA6EuW2Wps .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-pMeFXRkA6EuW2Wps .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-pMeFXRkA6EuW2Wps .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-pMeFXRkA6EuW2Wps .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-pMeFXRkA6EuW2Wps .actorPopupMenu{position:absolute;}#mermaid-svg-pMeFXRkA6EuW2Wps .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-pMeFXRkA6EuW2Wps .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-pMeFXRkA6EuW2Wps .actor-man circle,#mermaid-svg-pMeFXRkA6EuW2Wps line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-pMeFXRkA6EuW2Wps :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

Agent保持与Master的长连接

触发构建任务

根据标签匹配可用Agent

任务进入队列等待

主动拉取或等待分配任务

分配构建任务

拉取代码、执行构建

实时反馈日志

返回构建结果与制品

展示构建状态

执行步骤分解:

  • 任务触发:用户通过Web界面、Webhook或定时任务触发构建
  • 任务调度:Master根据节点标签、负载情况选择最合适的Agent
  • 任务分配:将构建任务发送到选中的Agent
  • 任务执行:Agent拉取代码、执行构建脚本、运行测试
  • 结果反馈:Agent将日志、测试报告、构建产物实时返回给Master
  • 二、配置分布式构建:完整步骤

    2.1 🟠 环境准备

    在开始配置之前,确保满足以下前置条件:

    准备项说明
    Java环境 所有节点安装OpenJDK 11或17(推荐)
    网络互通 Master与Agent之间网络可达,开放必要端口
    SSH服务 如使用SSH连接方式,Agent需开启sshd服务
    工具链统一 JDK、Maven、Git、Docker等在各节点版本一致或兼容

    # 在所有节点安装Java(以Ubuntu/Debian为例)
    sudo apt update
    sudo apt install -y openjdk-11-jdk
    java -version # 验证安装

    2.2 🔴 方式一:SSH连接添加Agent(推荐)

    这是最常用的方式,Master主动通过SSH连接Agent并启动代理进程。

    步骤1:在Agent节点创建专用用户并配置SSH免密登录

    # 在Agent节点
    sudo useradd -m jenkins
    sudo -u jenkins ssh-keygen -t ed25519 -f /home/jenkins/.ssh/id_ed25519 -N ""
    cat /home/jenkins/.ssh/id_ed25519.pub

    将公钥内容添加到Master节点的 ~/.ssh/authorized_keys 中,确保Master能免密登录Agent。

    步骤2:在Jenkins中添加Agent节点

  • 登录Jenkins → Manage Jenkins → Manage Nodes and Clouds → New Node
  • 输入节点名称(如 linux-agent-01),类型选择 Permanent Agent
  • 配置节点参数:
  • 参数配置建议说明
    Number of executors 与CPU核数相近 控制该节点并发构建数
    Remote root directory /home/jenkins/agent Agent工作目录
    Labels linux jdk11 maven 标签用于任务匹配
    Usage 按需选择 “尽可能使用”或“仅匹配标签”
  • Launch method 选择 Launch agent via SSH,填写:

    • Host:Agent的IP地址
    • Credentials:添加SSH私钥凭证
    • JavaPath:如 /usr/bin/java
  • 点击 Save,Jenkins会自动通过SSH连接并启动Agent

  • 2.3 🟣 方式二:JNLP方式连接(跨平台场景)

    适用于Agent无法被Master主动SSH连接的环境(如Windows节点或网络受限场景)。

    步骤1:在Master配置JNLP端口

    • Manage Jenkins → Global Security → 代理配置(Agents)
    • TCP port for JNLP agents:选择 固定端口(如50000)

    步骤2:创建Agent节点

    • Launch method 选择 Launch agent by connecting it to the controller
    • 保存后,页面会显示一个 Secret 密钥和连接命令

    步骤3:在Agent节点下载并启动agent.jar

    # 下载agent.jar
    wget http://<MASTER_IP>:8080/jnlpJars/agent.jar

    # 执行连接命令(替换SECRET和AGENT_NAME)
    java -jar agent.jar -url http://<MASTER_IP>:8080/ \\
    -secret <YOUR_SECRET> \\
    -name <AGENT_NAME> \\
    -workDir "/var/lib/jenkins"

    确认连接成功:在 Manage Nodes 页面,节点状态应显示为 已同步/在线

    2.4 🔵 Docker容器化Agent(云原生方式)

    使用Docker可以快速创建隔离的Agent环境,特别适合动态伸缩场景。

    运行一个固定的Agent容器:

    docker run -d –name jenkins-agent \\
    -e JENKINS_URL=http://<MASTER_IP>:8080 \\
    -e JENKINS_AGENT_NAME=my-agent \\
    -e JENKINS_SECRET=<YOUR_SECRET> \\
    -v /var/run/docker.sock:/var/run/docker.sock \\
    jenkins/inbound-agent:latest

    💡 进阶提示:结合Kubernetes插件可以实现动态Agent——每个构建任务按需创建一个Pod,完成后自动销毁,实现资源零闲置。

    三、将任务调度到Agent节点

    3.1 🟢 Freestyle项目配置

    在任务的 General 配置中:

    • 勾选 Restrict where this project can be run
    • 输入 Label Expression,如 linux && jdk11

    3.2 🟡 Pipeline项目配置

    在 Jenkinsfile 中通过 agent 指令指定:

    pipeline {
    agent {
    label 'linux && jdk11' // 匹配标签的Agent执行
    }
    stages {
    stage('Build') {
    steps {
    sh 'mvn clean package'
    }
    }
    stage('Test') {
    steps {
    sh 'mvn test'
    }
    }
    }
    post {
    success {
    echo '构建成功!'
    }
    failure {
    echo '构建失败!'
    }
    }
    }

    四、最佳实践与优化建议

    4.1 🔴 Master轻量化

    • 强烈建议将Master的Executor数量设为0,避免在Master上直接运行构建任务
    • Master应专注于调度、UI服务和插件管理,保证核心功能的稳定性

    4.2 🟣 负载均衡与并发

    • 为每个Agent配置合理的 Executor数量(建议与CPU核数相当)
    • 使用 标签 将不同环境(JDK版本、操作系统)的任务隔离到对应的Agent

    4.3 🟠 安全性加固

    • 使用 SSH密钥 认证替代密码认证
    • 避免使用root用户运行Agent,创建专用 jenkins 用户并设置最小权限
    • 为Master与Agent通信启用SSL加密

    五、常见问题排查

    问题现象可能原因解决方案
    Agent状态显示“离线” SSH连接失败或JNLP端口不通 检查网络、防火墙和SSH配置
    构建任务未落到指定Agent 标签拼写错误或Usage策略不当 检查任务配置和节点标签
    Agent上找不到构建工具 工具路径未配置 在Global Tool Configuration统一配置工具路径
    Agent节点负载过高 Executor数量设置过多 减少Executor数量或增加Agent节点

    六、总结

    步骤关键操作
    🟢 准备阶段 所有节点安装Java、确保网络互通
    🔵 添加Agent 通过SSH或JNLP方式连接Agent节点
    🟡 任务分发 使用标签将构建任务调度到指定Agent
    🟠 维护优化 监控节点状态,合理配置Executor和标签

    🔑 核心启示:Jenkins分布式构建的本质是将任务调度能力与执行能力分离——Master专注管理,Agent专注执行。无论是通过SSH连接物理机、使用JNLP连接Windows节点,还是采用Kubernetes动态创建Pod,核心都是实现负载分摊和环境隔离。掌握Agent的配置方法后,建议优先使用 标签(Label) 机制将不同技术栈的任务精准调度到对应的Agent节点,以最大化资源利用率。

    在这里插入图片描述

    🌺The End🌺点点关注,收藏不迷路🌺

    ⬆ ⬆ 顶部 ⬆ ⬆

    赞(0)
    未经允许不得转载:171主机测评 » Jenkins分布式构建完全指南:从原理到实践步骤
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址