【CI/CD·Jenkins篇】多节点构建:Agent 配置与任务分发策略

前言

当团队规模扩大到几十个微服务、几十条流水线时,单个 Jenkins Agent 就成了瓶颈------构建排队、资源争抢、环境冲突。本篇讲清楚如何规划多节点构建集群,让构建任务高效分发到合适的 Agent 上。


一、为什么需要多节点

单节点的瓶颈

复制代码
单节点场景:
  10个流水线同时触发 → 排队 → 第1个跑完(15分钟) → 第2个开始...
  → 最后一个等了150分钟才开始

多节点场景:
  10个流水线 → 分散到5个Agent → 每个节点跑2个 → 30分钟全部完成

多节点规划原则

| 原则 | 说明 |

|------|------|

| 按技术栈分组 | Java 节点、Go 节点、前端节点分离 |

| 按任务类型分组 | 构建节点、部署节点、测试节点分离 |

| 按环境隔离 | 生产部署节点与构建节点网络隔离 |

| 按负载弹性 | 基础节点常驻 + 弹性节点按需扩缩 |


二、Agent 标签策略

标签设计规范

复制代码
命名规则: <技术栈>-<任务类型>-<序号>

示例标签:
  java-build-01     # Java 构建
  java-build-02
  go-build-01       # Go 构建
  frontend-build-01 # 前端构建
  docker-build-01   # Docker 镜像构建
  k8s-deploy-01     # K8s 部署(有 kubectl)
  k8s-deploy-02
  e2e-test-01       # E2E 测试(有浏览器)

Jenkins 中配置 Agent 标签

在 Manage Jenkins → Nodes → 节点配置中设置 Labels:

复制代码
agent-java-build-01:
  Labels: java-build,maven,gradle
  # 多个标签用逗号分隔,Pipeline 中可以用任意一个匹配

agent-docker-build-01:
  Labels: docker-build,docker
  # 这个节点有 Docker daemon

agent-k8s-deploy-01:
  Labels: k8s-deploy,kubectl
  # 这个节点有 kubectl 和集群 kubeconfig

Pipeline 中使用标签

复制代码
pipeline {
    // 精确匹配:必须有 java-build 标签
    agent { label 'java-build' }
    
    stages {
        stage('Build') {
            steps { sh 'mvn clean package' }
        }
        
        stage('Docker Build') {
            // 切换到有 docker 标签的节点
            agent { label 'docker-build' }
            steps {
                sh 'docker build -t myapp:${BUILD_NUMBER} .'
                sh 'docker push registry.com/myapp:${BUILD_NUMBER}'
            }
        }
        
        stage('Deploy') {
            // 切换到有 k8s-deploy 标签的节点
            agent { label 'k8s-deploy' }
            steps {
                sh 'kubectl set image deployment/myapp app=registry.com/myapp:${BUILD_NUMBER} -n prod'
                sh 'kubectl rollout status deployment/myapp -n prod'
            }
        }
    }
}

**踩坑提示**:`stage` 级别的 `agent` 指令会导致工作空间切换。每个 stage 切换节点后,工作空间是新的,之前构建的产物不会自动带过去。需要用 `stash`/`unstash` 或共享存储来传递产物。

使用 stash 传递产物

复制代码
pipeline {
    agent { label 'java-build' }
    
    stages {
        stage('Build') {
            steps {
                sh 'mvn clean package -DskipTests'
                // 打包产物
                stash includes: 'target/*.jar', name: 'app-jar'
            }
        }
        
        stage('Docker Build') {
            agent { label 'docker-build' }
            steps {
                // 取回产物
                unstash 'app-jar'
                sh 'docker build -t myapp:${BUILD_NUMBER} .'
                sh 'docker push registry.com/myapp:${BUILD_NUMBER}'
            }
        }
        
        stage('Deploy') {
            agent { label 'k8s-deploy' }
            steps {
                sh "kubectl set image deployment/myapp app=registry.com/myapp:${BUILD_NUMBER} -n prod"
            }
        }
    }
}

三、Kubernetes 动态 Agent

为什么用动态 Agent

静态 Agent 的问题:

复制代码
固定 5 个 Agent → 平时利用率 20% → 浪费资源
                  上线日不够用 → 构建排队

动态 Agent 的优势:

复制代码
Pod 按需创建 → 高峰期自动扩容到 20 个
              空闲期自动缩到 0
              每次构建都是全新环境 → 无环境污染

安装 K8s 插件并配置

Manage Jenkins → System → Cloud → Kubernetes:

复制代码
# 关键配置
Kubernetes URL: https://k8s-api:6443
Kubernetes Namespace: jenkins
Jenkins URL: http://jenkins-master:8080
Jenkins tunnel: jenkins-master:50000

# Pod Template 配置:
Name: maven-pod
Namespace: jenkins
Labels: k8s-maven
# Container Template:
  Name: maven
  Docker image: maven:3.9-eclipse-temurin-17
  Command: cat
  Working directory: /home/jenkins/agent
  # 资源限制:
    CPU request: 1
    CPU limit: 2
    Memory request: 2Gi
    Memory limit: 4Gi
  # Volume:
    /root/.m2 → PVC(maven-cache)

Pipeline 使用 K8s 动态 Agent

复制代码
pipeline {
    agent {
        kubernetes {
            label 'maven-pod'
            yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: maven
    image: maven:3.9-eclipse-temurin-17
    command: ['cat']
    tty: true
    volumeMounts:
    - name: maven-cache
      mountPath: /root/.m2
  - name: docker
    image: docker:24
    command: ['cat']
    tty: true
    securityContext:
      privileged: true  # 需要构建 Docker 镜像
  volumes:
  - name: maven-cache
    persistentVolumeClaim:
      claimName: maven-cache-pvc
  - name: docker-sock
    hostPath:
      path: /var/run/docker.sock
'''
        }
    }
    
    stages {
        stage('Build') {
            steps {
                container('maven') {
                    sh 'mvn clean package -DskipTests'
                    stash includes: 'target/*.jar', name: 'app-jar'
                }
            }
        }
        
        stage('Docker Build') {
            steps {
                container('docker') {
                    unstash 'app-jar'
                    sh 'docker build -t myapp:${BUILD_NUMBER} .'
                    sh 'docker push registry.com/myapp:${BUILD_NUMBER}'
                }
            }
        }
    }
}

**踩坑提示**:K8s 动态 Agent 的 Pod 默认有 5 分钟空闲超时。如果 Pipeline 中有长时间等待(如等待人工审批),Pod 会被回收导致 Pipeline 失败。在 Pod Template 中设置 `idleMinutes: 30` 延长超时时间。


四、任务分发策略

1. 标签表达式

复制代码
// AND 表达式:同时拥有两个标签
agent { label 'java && docker' }

// OR 表达式:任一标签
agent { label 'java-build || go-build' }

// 排除表达式
agent { label 'build && !e2e-test' }

2. 负载均衡

Jenkins 内置的负载均衡策略:

| 策略 | 说明 | 配置方式 |

|------|------|---------|

| Round Robin | 轮询分发 | 默认 |

| Load | 优先选负载低的 | Node 配置 → Usage → "Use this node as much as possible" |

| Specific | 指定节点 | agent { label 'agent-01' } |

3. 优先级队列

复制代码
// 在 Job 配置中设置优先级
properties([
    buildDiscarder(logRotator(numToKeepStr: '20')),
    [$class: 'JiraProjectProperty'],
    pipelineTriggers([cron('@daily')])
])

// 通过 Priority Sorter 插件设置优先级
// 安装 Priority Sorter Plugin 后:
// Manage Jenkins → System → Priority Sorter
//   → Priority Strategy → Absolute Priority
//   → Job Group: 
//     - 'deploy-*' → Priority 1 (最高)
//     - 'build-*' → Priority 5
//     - 'test-*' → Priority 10

4. 资源互斥

避免多个 Job 同时操作同一资源:

复制代码
pipeline {
    agent any
    options {
        // 同一资源组同时只允许一个构建
        lock(resource: 'production-deploy', inversePrecedence: true)
    }
    stages {
        stage('Deploy') {
            steps {
                sh 'kubectl apply -f deploy/ -n prod'
            }
        }
    }
}

五、监控 Agent 健康状态

健康检查脚本

复制代码
#!/bin/bash
# 定期检查所有 Agent 的磁盘空间
for agent in $(java -jar jenkins-cli.jar -s http://localhost:8080 list-nodes 2>/dev/null | awk '{print $1}'); do
    DISK_USAGE=$(java -jar jenkins-cli.jar -s http://localhost:8080 node $agent run-script 'println "df -h".execute().text' 2>/dev/null | grep '/$' | awk '{print $5}' | tr -d '%')
    
    if [ "$DISK_USAGE" -gt 80 ]; then
        echo "WARNING: Agent $agent disk usage: ${DISK_USAGE}%"
        # 推送到 Prometheus
        echo "jenkins_agent_disk_usage{agent=\"$agent\"} $DISK_USAGE" | curl --data-binary @- http://pushgateway:9091/metrics/job/jenkins-agent
    fi
done

Agent 自动清理

复制代码
# 定时清理 Agent 上的旧构建产物
#!/bin/bash
# 在每个 Agent 上配置 crontab
find /home/jenkins/workspace -mindepth 1 -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \;
find /tmp -name "jenkins*" -mtime +1 -exec rm -f {} \;
docker system prune -f --filter "until=24h"

六、本篇要点回顾

  1. Agent 按"技术栈+任务类型"规划标签,Pipeline 中用标签精确匹配

  2. 跨节点传递产物用 stash/unstash,不能依赖工作空间

  3. K8s 动态 Agent 按需创建、用完即删,配合 PVC 缓存依赖

  4. lock 指令实现资源互斥,防止多个 Job 同时操作生产环境

  5. 监控 Agent 磁盘和状态,定期清理旧产物

下一篇预告:《插件生态:必装插件清单与安全加固》------盘点 Jenkins 生态中真正好用的插件,以及如何避免"插件地狱"。

相关推荐
xiaoxiangsiyan19 小时前
GitLab CI/CD 自托管(EE 企业版)+ Kubernetes Runner 集群 + ArgoCD(GitOps 部署)
运维·网络·ci/cd·容器·kubernetes·gitlab·argocd
heimeiyingwang19 小时前
【CI/CD·Jenkins篇】环境搭建:从零部署 Jenkins 主从架构
ci/cd·jenkins
众人皆醒我独醉20 小时前
KServe:Kubernetes 原生的模型推理平台——把 vLLM/TGI/Triton 变成 Serverless
人工智能·ci/cd·面试
heimeiyingwang21 小时前
【CI/CD·Jenkins篇】Pipeline 基础:Declarative 与 Scripted 语法详解
ci/cd·pipeline·jenkins
测试者家园2 天前
Harness由浅入深:CI/CD流水线里的质量门禁怎么设计
软件测试·人工智能·ci/cd·混沌测试·智能化测试·harness·质量门禁
超爱西西鸭2 天前
鸿蒙企业级CI/CD高级工程化搭建:自动化构建流水线/多环境配置/自动化测试集成/签名打包发布
android·学习·ci/cd·华为·自动化·harmonyos·鸿蒙
遨游DATA2 天前
Jenkins 修改 config.xml 后页面仍是旧配置:让 live job 配置真正生效
ci/cd·jenkins·devops·故障排查·config.xml
ZeroNews内网穿透2 天前
无公网 IP 打通 CI/CD:内网穿透对接 GitHub Actions 自动部署内网服务
运维·tcp/ip·ci/cd·github·远程工作·内网穿透
Dobby_052 天前
【CICD】Jenkins Pipeline 快速学习入门
运维·学习·jenkins