Jenkins分布式构建与Agent管理:构建弹性扩展的CI/CD基础设施

1. 分布式架构设计原理

1.1 Master-Agent架构

Jenkins采用经典的Master-Agent分布式架构,实现构建任务的分布式执行。

云平台

Agent集群

Jenkins Master (控制器)

动态Agent

静态Agent

Agent管理

核心服务

存储层

配置存储

构建历史

日志存储

Web服务器

任务调度器

队列管理器

插件管理器

连接管理器

心跳检测

负载监控

SSH Agent 1

JNLP Agent 1

Kubernetes Pod

Docker Container

EC2 Instance

Kubernetes

AWS EC2

Azure VMs

1.2 通信协议架构

Kubernetes AgentJNLP AgentSSH AgentMasterKubernetes AgentJNLP AgentSSH AgentMasterSSH协议连接流程JNLP协议连接流程Kubernetes动态AgentSSH连接请求认证握手发送slave.jar启动Agent进程建立双向通道发送任务返回结果HTTP下载agent.jar返回agent.jarTCP连接请求返回密钥验证建立双向通道发送任务返回结果创建Pod请求调度PodPod就绪通知JNLP连接建立通道发送任务返回结果删除Pod

1.3 分布式构建优势

特性说明优势
负载分散构建任务分发到多个Agent提高吞吐量,避免Master过载
环境隔离不同Agent可配置不同环境支持多平台、多版本构建
弹性扩展动态Agent按需创建/销毁资源按需分配,降低成本
高可用Agent故障不影响Master提高系统稳定性
安全隔离敏感操作在隔离环境执行降低安全风险

2. Agent类型与连接协议

2.1 Agent类型对比

特性对比

Agent类型

动态Agent

Kubernetes Pod

Docker Container

EC2 Instance

Azure VM

静态Agent

SSH Agent

JNLP Agent

Windows Service

静态Agent:
- 固定资源
- 持久运行
- 手动管理

动态Agent:
- 按需创建
- 自动销毁
- 弹性扩展

2.2 连接协议详解

协议连接方向适用场景安全性穿透性
SSHMaster→AgentAgent在公网、有SSH服务高(密钥认证)需开放SSH端口(22)
JNLPAgent→MasterAgent在内网、防火墙后中(密钥认证)仅需出站HTTP/HTTPS
WebSocketAgent→Master网络受限环境高(TLS加密)穿透NAT/防火墙

2.3 协议配置示例

/**
 * 不同连接协议的Agent配置示例
 */

// ==================== SSH Agent配置 ====================
// Master主动连接Agent,适用于Agent有公网IP的情况

pipeline {
    agent {
        label 'ssh-agent'
    }
    stages {
        stage('Build') {
            steps {
                sh 'echo "Running on SSH Agent"'
            }
        }
    }
}

// SSH Agent在Jenkins配置中的XML表示:
/*
<hudson.plugins.sshslaves.SSHSlave>
    <name>ssh-agent-01</name>
    <remoteFS>/home/jenkins/agent</remoteFS>
    <numExecutors>2</numExecutors>
    <mode>NORMAL</mode>
    <launcher class="hudson.plugins.sshslaves.SSHLauncher">
        <host>192.168.1.100</host>
        <port>22</port>
        <credentialsId>ssh-credentials</credentialsId>
        <launchTimeoutSeconds>60</launchTimeoutSeconds>
        <maxNumRetries>3</maxNumRetries>
        <retryWaitTime>10</retryWaitTime>
    </launcher>
    <label>linux docker maven</label>
</hudson.plugins.sshslaves.SSHSlave>
*/

// ==================== JNLP Agent配置 ====================
// Agent主动连接Master,适用于Agent在内网的情况

pipeline {
    agent {
        label 'jnlp-agent'
    }
    stages {
        stage('Build') {
            steps {
                sh 'echo "Running on JNLP Agent"'
            }
        }
    }
}

// JNLP Agent启动命令:
/*
java -jar agent.jar \
    -jnlpUrl http://jenkins.example.com/computer/jnlp-agent/slave-agent.jnlp \
    -secret <secret-key> \
    -workDir /home/jenkins/agent
*/

// ==================== WebSocket Agent配置 ====================
// 使用WebSocket协议,适用于网络受限环境

// 在Jenkins配置中启用WebSocket:
/*
<hudson.slaves.JNLPLauncher>
    <workDirSettings>
        <disabled>false</disabled>
        <internalDir>remoting</internalDir>
    </workDirSettings>
    <webSocket>true</webSocket>
</hudson.slaves.JNLPLauncher>
*/

// WebSocket Agent启动命令:
/*
java -jar agent.jar \
    -webSocket \
    -url http://jenkins.example.com \
    -secret <secret-key> \
    -name websocker-agent \
    -workDir /home/jenkins/agent
*/

3. 静态Agent配置管理

3.1 SSH Agent完整配置

<!-- 
  文件: JENKINS_HOME/config.xml (SSH Agent配置部分)
  描述: SSH Agent完整配置示例
-->
<hudson.plugins.sshslaves.SSHSlave>
    <!-- 基本信息 -->
    <name>linux-build-agent-01</name>
    <description>Linux构建节点 - Docker环境</description>
    <remoteFS>/home/jenkins/agent</remoteFS>
    <numExecutors>4</numExecutors>
    <mode>NORMAL</mode>
    
    <!-- 启动器配置 -->
    <launcher class="hudson.plugins.sshslaves.SSHLauncher">
        <host>192.168.1.100</host>
        <port>22</port>
        <credentialsId>ssh-agent-credentials</credentialsId>
        
        <!-- 启动超时配置 -->
        <launchTimeoutSeconds>120</launchTimeoutSeconds>
        <maxNumRetries>5</maxNumRetries>
        <retryWaitTime>15</retryWaitTime>
        
        <!-- SSH主机密钥验证策略 -->
        <sshHostKeyVerificationStrategy class="hudson.plugins.sshslaves.verifiers.KnownHostsFileKeyVerificationStrategy"/>
        
        <!-- TCP保活 -->
        <tcpKeepAlive>true</tcpKeepAlive>
        
        <!-- 启动前检查 -->
        <sshLauncherBuilder class="hudson.plugins.sshslaves.SSHLauncher$Builder">
            <javaPath>/usr/lib/jvm/java-11-openjdk/bin/java</javaPath>
            <jvmOptions>-Xmx2g -XX:+UseG1GC</jvmOptions>
            <prefixStartSlaveCmd></prefixStartSlaveCmd>
            <suffixStartSlaveCmd></suffixStartSlaveCmd>
        </sshLauncherBuilder>
        
        <!-- Agent启动命令 -->
        <agentUser>jenkins</agentUser>
        <agentJVMOptions>-Xmx4g -XX:+UseG1GC</agentJVMOptions>
    </launcher>
    
    <!-- 保留策略 -->
    <retentionStrategy class="hudson.slaves.RetentionStrategy$Always"/>
    
    <!-- 标签 -->
    <label>linux docker maven gradle node18 python3</label>
    
    <!-- 节点属性 -->
    <nodeProperties>
        <!-- 环境变量 -->
        <hudson.slaves.EnvironmentVariablesNodeProperty>
            <envVars serialization="custom">
                <tree-map>
                    <entry>
                        <string>JAVA_HOME</string>
                        <string>/usr/lib/jvm/java-11-openjdk</string>
                    </entry>
                    <entry>
                        <string>MAVEN_HOME</string>
                        <string>/usr/share/maven</string>
                    </entry>
                    <entry>
                        <string>DOCKER_HOST</string>
                        <string>unix:///var/run/docker.sock</string>
                    </entry>
                </tree-map>
            </envVars>
        </hudson.slaves.EnvironmentVariablesNodeProperty>
        
        <!-- 工具位置 -->
        <hudson.tools.ToolLocationNodeProperty>
            <locations>
                <hudson.tools.ToolLocation>
                    <key>hudson.model.JDK$DescriptorImpl@JDK-11</key>
                    <home>/usr/lib/jvm/java-11-openjdk</home>
                </hudson.tools.ToolLocation>
                <hudson.tools.ToolLocation>
                    <key>hudson.tasks.Maven$MavenInstallation$DescriptorImpl@Maven-3.8</key>
                    <home>/usr/share/maven</home>
                </hudson.tools.ToolLocation>
            </locations>
        </hudson.tools.ToolLocationNodeProperty>
    </nodeProperties>
</hudson.plugins.sshslaves.SSHSlave>

3.2 JNLP Agent配置

/**
 * JNLP Agent配置与管理
 */

// ==================== Jenkins中配置JNLP Agent ====================
// 使用JCasC配置
jenkins:
  nodes:
    - permanent:
        name: "jnlp-agent-01"
        remoteFS: "/home/jenkins/agent"
        numExecutors: 2
        mode: NORMAL
        retentionStrategy:
          onDemand:
            idleMinutes: 30
        launcher:
          jnlp:
            workDirSettings:
              disabled: false
              internalDir: "remoting"
              failIfWorkDirIsMissing: false
        labelString: "linux maven gradle"
        nodeProperties:
          - envVars:
              env:
                - key: "JAVA_HOME"
                  value: "/usr/lib/jvm/java-11-openjdk"

// ==================== JNLP Agent启动脚本 ====================
#!/bin/bash

# JNLP Agent启动脚本
# 文件: start-agent.sh

JENKINS_URL="http://jenkins.example.com"
AGENT_NAME="jnlp-agent-01"
SECRET_KEY="your-secret-key"
WORK_DIR="/home/jenkins/agent"
JVM_OPTS="-Xmx2g -XX:+UseG1GC"

# 下载agent.jar
curl -sSL ${JENKINS_URL}/jnlpJars/agent.jar -o agent.jar

# 启动Agent
java ${JVM_OPTS} -jar agent.jar \
    -jnlpUrl ${JENKINS_URL}/computer/${AGENT_NAME}/slave-agent.jnlp \
    -secret ${SECRET_KEY} \
    -workDir ${WORK_DIR} \
    -noReconnectAfter 10m

// ==================== JNLP Agent作为系统服务 ====================
# 文件: /etc/systemd/system/jenkins-agent.service

[Unit]
Description=Jenkins JNLP Agent
After=network.target

[Service]
Type=simple
User=jenkins
Group=jenkins
WorkingDirectory=/home/jenkins/agent
ExecStart=/usr/bin/java -Xmx2g -jar /home/jenkins/agent/agent.jar \
    -jnlpUrl http://jenkins.example.com/computer/jnlp-agent-01/slave-agent.jnlp \
    -secret YOUR_SECRET_KEY \
    -workDir /home/jenkins/agent
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

3.3 Agent配置最佳实践

/**
 * Agent配置最佳实践示例
 */

// ==================== 1. 资源限制配置 ====================
pipeline {
    agent {
        label 'linux'
        // 自定义工作空间
        customWorkspace "/opt/jenkins/workspaces/${JOB_NAME}/${BUILD_NUMBER}"
    }
    
    options {
        // 超时控制
        timeout(time: 60, unit: 'MINUTES')
        // 禁止并发构建(保护资源)
        disableConcurrentBuilds()
    }
    
    stages {
        stage('Build') {
            steps {
                sh 'mvn clean package'
            }
        }
    }
}

// ==================== 2. 按需保留策略 ====================
// Agent在空闲一段时间后自动断开
/*
<retentionStrategy class="hudson.slaves.RetentionStrategy$OnDemand">
    <idleMinutes>30</idleMinutes>
</retentionStrategy>
*/

// ==================== 3. 一次性格式策略 ====================
// 每次构建后清理工作空间
/*
<retentionStrategy class="hudson.slaves.RetentionStrategy$Once">
    <maxUses>10</maxUses>
</retentionStrategy>
*/

// ==================== 4. Docker Agent一次性运行 ====================
pipeline {
    agent {
        docker {
            image 'maven:3.8-openjdk-11'
            args '--rm -v /tmp/.m2:/root/.m2'
            reuseNode true
        }
    }
    stages {
        stage('Build') {
            steps {
                sh 'mvn clean package'
            }
        }
    }
}

4. Kubernetes动态Agent

4.1 Kubernetes Agent架构

Pipeline执行

Kubernetes集群

共享资源

jenkins namespace

动态Agent Pods

Jenkins Master

Pod

PVC
JENKINS_HOME

Agent Pod 1

Agent Pod 2

Agent Pod N

ConfigMap
Maven Settings

Secret
Credentials

PVC
Maven Cache

请求Agent

Kubernetes Plugin

创建Pod

Pod启动

JNLP连接

执行任务

删除Pod

4.2 Kubernetes Plugin配置

# 文件: Jenkins配置即代码 (JCasC)
# Kubernetes云配置

jenkins:
  clouds:
    - kubernetes:
        name: "kubernetes"
        serverUrl: "https://kubernetes.default"
        namespace: "jenkins"
        jenkinsUrl: "http://jenkins.jenkins.svc.cluster.local:8080"
        jenkinsTunnel: "jenkins.jenkins.svc.cluster.local:50000"
        
        # 连接超时
        connectTimeout: 5
        readTimeout: 15
        
        # 最大并发Pod数
        containerCap: 50
        
        # 保留时间
        retentionTimeout: 5
        
        # Pod模板
        templates:
          # 默认Pod模板
          - name: "default"
            namespace: "jenkins"
            label: "kubernetes default"
            
            # ServiceAccount
            serviceAccount: "jenkins-agent"
            
            # 资源限制
            nodeSelector:
              "kubernetes.io/os": "linux"
            
            # 容器配置
            containers:
              - name: "jnlp"
                image: "jenkins/inbound-agent:4.11.2"
                args: "^${computer.jnlpmac} ^${computer.name}"
                envVars:
                  - envVar:
                      key: "JENKINS_URL"
                      value: "http://jenkins.jenkins.svc.cluster.local:8080"
                resourceLimitCpu: "500m"
                resourceLimitMemory: "1Gi"
                resourceRequestCpu: "200m"
                resourceRequestMemory: "512Mi"
            
            # 工作空间卷
            workspaceVolume:
              emptyDirWorkspaceVolume:
                memory: false
            
            # 卷挂载
            volumes:
              - hostPathVolume:
                  mountPath: "/var/run/docker.sock"
                  hostPath: "/var/run/docker.sock"
              - persistentVolumeClaim:
                  mountPath: "/root/.m2/repository"
                  claimName: "maven-cache-pvc"
                  readOnly: false
          
          # Maven构建模板
          - name: "maven"
            namespace: "jenkins"
            label: "maven kubernetes"
            serviceAccount: "jenkins-agent"
            
            containers:
              - name: "jnlp"
                image: "jenkins/inbound-agent:4.11.2"
                resourceLimitCpu: "500m"
                resourceLimitMemory: "1Gi"
              
              - name: "maven"
                image: "maven:3.8.6-openjdk-11"
                command: "sleep"
                args: "99d"
                resourceLimitCpu: "2"
                resourceLimitMemory: "4Gi"
                resourceRequestCpu: "1"
                resourceRequestMemory: "2Gi"
                envVars:
                  - envVar:
                      key: "MAVEN_OPTS"
                      value: "-Xmx3g -XX:+UseG1GC"
                ttyEnabled: true
            
            volumes:
              - persistentVolumeClaim:
                  mountPath: "/root/.m2/repository"
                  claimName: "maven-cache-pvc"
          
          # Docker构建模板
          - name: "docker"
            namespace: "jenkins"
            label: "docker kubernetes"
            serviceAccount: "jenkins-agent"
            
            containers:
              - name: "jnlp"
                image: "jenkins/inbound-agent:4.11.2"
              
              - name: "docker"
                image: "docker:20.10.18"
                command: "sleep"
                args: "99d"
                ttyEnabled: true
                envVars:
                  - envVar:
                      key: "DOCKER_HOST"
                      value: "tcp://docker-dind:2376"
                  - envVar:
                      key: "DOCKER_TLS_VERIFY"
                      value: "1"
                  - envVar:
                      key: "DOCKER_CERT_PATH"
                      value: "/certs/client"
            
            volumes:
              - hostPathVolume:
                  mountPath: "/var/run/docker.sock"
                  hostPath: "/var/run/docker.sock"

4.3 Pipeline中使用Kubernetes Agent

/**
 * Kubernetes动态Agent完整示例
 */

// ==================== 方式1: 使用预定义模板 ====================
pipeline {
    agent {
        kubernetes {
            label 'maven-build-${BUILD_NUMBER}'
            cloud 'kubernetes'
            inheritFrom 'maven'  // 继承预定义模板
        }
    }
    
    stages {
        stage('Build') {
            steps {
                container('maven') {
                    sh 'mvn clean package'
                }
            }
        }
    }
}

// ==================== 方式2: 内联Pod定义 ====================
pipeline {
    agent {
        kubernetes {
            cloud 'kubernetes'
            label 'custom-build-${BUILD_NUMBER}'
            yaml '''
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: jenkins-agent
    build: ${BUILD_NUMBER}
spec:
  serviceAccountName: jenkins-agent
  securityContext:
    runAsUser: 1000
    fsGroup: 1000
  containers:
  - name: jnlp
    image: jenkins/inbound-agent:4.11.2
    args: ['$(JENKINS_SECRET)', '$(JENKINS_NAME)']
    resources:
      requests:
        cpu: "200m"
        memory: "512Mi"
      limits:
        cpu: "500m"
        memory: "1Gi"
  
  - name: maven
    image: maven:3.8.6-openjdk-11
    command: ['sleep', '99d']
    resources:
      requests:
        cpu: "1"
        memory: "2Gi"
      limits:
        cpu: "2"
        memory: "4Gi"
    volumeMounts:
    - name: maven-cache
      mountPath: /root/.m2/repository
  
  - name: docker
    image: docker:20.10.18
    command: ['sleep', '99d']
    resources:
      requests:
        cpu: "500m"
        memory: "1Gi"
    volumeMounts:
    - name: docker-sock
      mountPath: /var/run/docker.sock
  
  volumes:
  - name: maven-cache
    persistentVolumeClaim:
      claimName: maven-cache-pvc
  - name: docker-sock
    hostPath:
      path: /var/run/docker.sock
'''
        }
    }
    
    stages {
        stage('Build with Maven') {
            steps {
                container('maven') {
                    sh '''
                        mvn clean package -DskipTests
                        mvn test
                    '''
                }
            }
            post {
                always {
                    junit '**/target/surefire-reports/*.xml'
                }
            }
        }
        
        stage('Docker Build') {
            steps {
                container('docker') {
                    sh '''
                        docker build -t myapp:${BUILD_NUMBER} .
                        docker push registry.example.com/myapp:${BUILD_NUMBER}
                    '''
                }
            }
        }
    }
}

// ==================== 方式3: 动态生成Pod定义 ====================
pipeline {
    agent none
    
    parameters {
        choice(name: 'JAVA_VERSION', choices: ['11', '17'], description: 'Java版本')
        choice(name: 'BUILD_TOOL', choices: ['maven', 'gradle'], description: '构建工具')
    }
    
    stages {
        stage('Dynamic Agent Build') {
            agent {
                kubernetes {
                    cloud 'kubernetes'
                    label 'dynamic-${BUILD_NUMBER}'
                    yamlTemplate """
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: jnlp
    image: jenkins/inbound-agent:4.11.2
  - name: build
    image: ${params.BUILD_TOOL}:latest-openjdk-${params.JAVA_VERSION}
    command: ['sleep', '99d']
"""
                    defaultContainer 'build'
                }
            }
            steps {
                script {
                    if (params.BUILD_TOOL == 'maven') {
                        sh 'mvn clean package'
                    } else {
                        sh './gradlew build'
                    }
                }
            }
        }
    }
}

// ==================== 方式4: 多容器协作 ====================
pipeline {
    agent {
        kubernetes {
            cloud 'kubernetes'
            yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: jnlp
    image: jenkins/inbound-agent:4.11.2
  
  - name: maven
    image: maven:3.8.6-openjdk-11
    command: ['sleep', '99d']
    ttyEnabled: true
  
  - name: node
    image: node:18
    command: ['sleep', '99d']
    ttyEnabled: true
  
  - name: python
    image: python:3.11
    command: ['sleep', '99d']
    ttyEnabled: true
'''
        }
    }
    
    stages {
        stage('Build Backend') {
            steps {
                container('maven') {
                    dir('backend') {
                        sh 'mvn clean package'
                    }
                }
            }
        }
        
        stage('Build Frontend') {
            steps {
                container('node') {
                    dir('frontend') {
                        sh 'npm ci && npm run build'
                    }
                }
            }
        }
        
        stage('Run Python Tests') {
            steps {
                container('python') {
                    dir('scripts') {
                        sh 'pip install -r requirements.txt && pytest'
                    }
                }
            }
        }
    }
}

5. Docker动态Agent

5.1 Docker Agent架构

Jenkins Master

Docker主机

创建容器

数据卷

Maven缓存

npm缓存

工作空间

容器

Agent容器1

Agent容器2

Agent容器N

Docker Socket

Docker Plugin

任务队列

5.2 Docker Agent配置

/**
 * Docker动态Agent配置示例
 */

// ==================== 方式1: 简单Docker Agent ====================
pipeline {
    agent {
        docker {
            image 'maven:3.8-openjdk-11'
            args '-v /tmp/.m2:/root/.m2'
        }
    }
    
    stages {
        stage('Build') {
            steps {
                sh 'mvn clean package'
            }
        }
    }
}

// ==================== 方式2: 带凭证的Docker Agent ====================
pipeline {
    agent {
        docker {
            image 'maven:3.8-openjdk-11'
            args '-v /tmp/.m2:/root/.m2 -v /tmp/.gradle:/root/.gradle'
            registryUrl 'https://registry.example.com'
            registryCredentialsId 'docker-registry-credentials'
        }
    }
    
    stages {
        stage('Build') {
            steps {
                sh 'mvn clean package'
            }
        }
    }
}

// ==================== 方式3: 自定义Dockerfile ====================
pipeline {
    agent {
        dockerfile {
            filename 'Dockerfile.build'
            dir 'docker'
            additionalBuildArgs '--build-arg JAVA_VERSION=11'
            args '-v /tmp/.m2:/root/.m2'
        }
    }
    
    stages {
        stage('Build') {
            steps {
                sh 'mvn clean package'
            }
        }
    }
}

// ==================== 方式4: Docker模板标签 ====================
pipeline {
    agent none
    
    stages {
        stage('Build on Multiple Platforms') {
            parallel {
                stage('Linux') {
                    agent {
                        docker {
                            image 'maven:3.8-openjdk-11'
                            label 'docker-linux'
                        }
                    }
                    steps {
                        sh 'mvn clean package'
                    }
                }
                
                stage('Windows') {
                    agent {
                        docker {
                            image 'maven:3.8-openjdk-11-windowsservercore'
                            label 'docker-windows'
                        }
                    }
                    steps {
                        bat 'mvn clean package'
                    }
                }
            }
        }
    }
}

// ==================== 方式5: 动态Docker Agent ====================
pipeline {
    agent none
    
    parameters {
        string(name: 'DOCKER_IMAGE', defaultValue: 'maven:3.8-openjdk-11', 
               description: 'Docker镜像')
    }
    
    stages {
        stage('Dynamic Docker Build') {
            agent {
                docker {
                    image "${params.DOCKER_IMAGE}"
                    args '-v /tmp/.m2:/root/.m2'
                }
            }
            steps {
                sh 'mvn clean package'
            }
        }
    }
}

5.3 Docker Compose多容器

/**
 * 使用Docker Compose运行多容器Agent
 */

// ==================== docker-compose.yml ====================
version: '3.8'
services:
  maven:
    image: maven:3.8-openjdk-11
    command: sleep infinity
    volumes:
      - maven-cache:/root/.m2/repository
      - workspace:/workspace
    working_dir: /workspace
  
  node:
    image: node:18
    command: sleep infinity
    volumes:
      - npm-cache:/root/.npm
      - workspace:/workspace
    working_dir: /workspace
  
  selenium:
    image: selenium/standalone-chrome:latest
    ports:
      - "4444:4444"
    volumes:
      - workspace:/workspace

volumes:
  maven-cache:
  npm-cache:
  workspace:

// ==================== Pipeline使用Docker Compose ====================
pipeline {
    agent {
        label 'docker'
    }
    
    stages {
        stage('Start Services') {
            steps {
                sh 'docker-compose up -d'
            }
        }
        
        stage('Build Backend') {
            steps {
                sh '''
                    docker-compose exec -T maven mvn clean package
                '''
            }
        }
        
        stage('Build Frontend') {
            steps {
                sh '''
                    docker-compose exec -T node npm ci
                    docker-compose exec -T node npm run build
                '''
            }
        }
        
        stage('E2E Tests') {
            steps {
                sh '''
                    docker-compose exec -T node npm run e2e
                '''
            }
        }
    }
    
    post {
        always {
            sh 'docker-compose down -v'
        }
    }
}

6. 负载均衡与调度策略

6.1 调度策略架构

调度策略

调度决策

Agent池

Agent 1
负载: 2/4

Agent 2
负载: 1/4

Agent 3
负载: 3/4

任务队列

任务1

任务2

任务3

Label匹配

负载均衡

优先级排序

亲和性规则

6.2 调度策略配置

/**
 * 负载均衡与调度策略配置
 */

// ==================== 1. Label约束调度 ====================
pipeline {
    // 使用Label约束选择Agent
    agent { label 'linux && docker && maven' }
    
    stages {
        stage('Build') {
            steps {
                sh 'mvn clean package'
            }
        }
    }
}

// ==================== 2. 排他性Agent ====================
// Agent配置为EXCLUSIVE模式,仅执行指定Job
/*
<mode>EXCLUSIVE</mode>
*/

// ==================== 3. 自定义负载均衡 ====================
// 使用Groovy脚本实现自定义调度
import hudson.model.*
import jenkins.model.*

def selectLeastLoadedAgent(Label label) {
    def computers = Jenkins.instance.getComputers()
    
    // 过滤匹配Label的Agent
    def matchingComputers = computers.findAll { computer ->
        label == null || computer.node?.assignedLabel?.matches(label)
    }
    
    // 选择负载最低的Agent
    return matchingComputers.min { a, b ->
        a.countBusy() <=> b.countBusy()
    }
}

// ==================== 4. 优先级调度 ====================
// 安装Priority Sorter插件配置优先级

// 在Pipeline中使用优先级
pipeline {
    agent any
    
    options {
        // 设置构建优先级
        buildDiscarder(logRotator(numToKeepStr: '10'))
    }
    
    stages {
        stage('High Priority Build') {
            steps {
                echo 'This is a high priority build'
            }
        }
    }
}

// ==================== 5. 亲和性调度 ====================
// 让相关任务在同一Agent上执行
pipeline {
    agent {
        label 'linux'
    }
    
    stages {
        stage('Prepare') {
            steps {
                script {
                    // 记录当前Agent
                    env.PREFERRED_AGENT = env.NODE_NAME
                }
            }
        }
        
        stage('Build') {
            agent {
                label env.PREFERRED_AGENT
            }
            steps {
                sh 'mvn clean package'
            }
        }
        
        stage('Test') {
            agent {
                label env.PREFERRED_AGENT
            }
            steps {
                sh 'mvn test'
            }
        }
    }
}

6.3 队列管理策略

/**
 * 队列管理策略配置
 */

// ==================== 1. 并发限制 ====================
pipeline {
    agent any
    
    options {
        // 禁止并发构建
        disableConcurrentBuilds()
        
        // 或允许并发但限制数量
        // disableConcurrentBuilds(abortPrevious: false)
    }
    
    stages {
        stage('Build') {
            steps {
                sh 'sleep 60'
            }
        }
    }
}

// ==================== 2. 资源锁 ====================
pipeline {
    agent any
    
    stages {
        stage('Exclusive Resource') {
            steps {
                // 使用lock步骤确保资源独占
                lock(resource: 'shared-database', quantity: 1) {
                    sh 'run-tests.sh'
                }
            }
        }
        
        stage('Multiple Resources') {
            steps {
                lock(resources: ['server-a', 'server-b'], variable: 'LOCKED_SERVERS') {
                    echo "Locked servers: ${env.LOCKED_SERVERS}"
                }
            }
        }
    }
}

// ==================== 3. 节流分类 ====================
// 在Jenkins配置中设置Throttle Categories
/*
<throttle-concurrent-builds>
    <categories>
        <category>
            <name>heavy-builds</name>
            <maxConcurrentPerNode>1</maxConcurrentPerNode>
            <maxConcurrentTotal>3</maxConcurrentTotal>
        </category>
    </categories>
</throttle-concurrent-builds>
*/

// Pipeline中使用节流
pipeline {
    agent any
    
    options {
        throttleJobProperty(
            categories: ['heavy-builds'],
            throttleEnabled: true,
            throttleOption: 'category'
        )
    }
    
    stages {
        stage('Heavy Build') {
            steps {
                sh './heavy-build.sh'
            }
        }
    }
}

7. Agent监控与运维

7.1 监控指标

Agent监控

告警规则

离线告警

资源告警

超时告警

监控指标

CPU使用率

内存使用率

磁盘空间

网络IO

状态监控

在线状态

Executor数量

队列长度

构建时长

7.2 监控配置

/**
 * Agent监控配置示例
 */

// ==================== 1. 健康检查脚本 ====================
// 在Jenkins Script Console中运行

import hudson.model.*
import jenkins.model.*
import hudson.slaves.*

Jenkins jenkins = Jenkins.getInstance()

println "=== Agent Status Report ==="
println ""

jenkins.computers.each { computer ->
    println "Agent: ${computer.name}"
    println "  Status: ${computer.offline ? 'OFFLINE' : 'ONLINE'}"
    println "  Executors: ${computer.numExecutors}"
    println "  Busy: ${computer.countBusy()}"
    println "  Idle: ${computer.countIdle()}"
    
    if (computer.offline) {
        println "  Offline Cause: ${computer.offlineCause}"
    }
    
    // 获取系统信息(如果Agent在线)
    if (!computer.offline) {
        try {
            def mem = computer.node?.toComputer()?.getSystemInfo()?.getMemory()
            if (mem) {
                println "  Memory: ${mem}"
            }
        } catch (Exception e) {
            println "  Memory: Unable to retrieve"
        }
    }
    println ""
}

// ==================== 2. Prometheus监控集成 ====================
// 安装Prometheus插件后配置

// prometheus.yml
/*
scrape_configs:
  - job_name: 'jenkins'
    metrics_path: '/prometheus'
    static_configs:
      - targets: ['jenkins.example.com:8080']
*/

// 关键监控指标:
// - jenkins_nodes_online: 在线节点数
// - jenkins_nodes_offline: 离线节点数
// - jenkins_executors_available: 可用Executor数
// - jenkins_executors_busy: 繁忙Executor数
// - jenkins_queue_size: 队列大小
// - jenkins_queue_blocked: 阻塞任务数

// ==================== 3. 自动恢复脚本 ====================
// 定期检查并尝试恢复离线Agent

import hudson.model.*
import jenkins.model.*
import hudson.slaves.*

Jenkins jenkins = Jenkins.getInstance()

jenkins.computers.each { computer ->
    if (computer.offline && computer.offlineCause != null) {
        println "Attempting to reconnect: ${computer.name}"
        
        try {
            // 尝试重新连接
            computer.connect(false)
            
            // 等待连接
            Thread.sleep(30000)
            
            if (computer.offline) {
                println "  Still offline after reconnect attempt"
                
                // 发送告警通知
                // sendAlert(computer.name, computer.offlineCause)
            } else {
                println "  Successfully reconnected"
            }
        } catch (Exception e) {
            println "  Reconnect failed: ${e.message}"
        }
    }
}

// ==================== 4. 资源使用监控 ====================
pipeline {
    agent any
    
    stages {
        stage('Monitor Resources') {
            steps {
                script {
                    // 获取当前节点资源信息
                    def nodeInfo = sh(
                        script: '''
                            echo "CPU: $(top -bn1 | grep 'Cpu(s)' | awk '{print $2}')%"
                            echo "Memory: $(free -m | awk '/Mem/{printf "%.1f%%", $3/$2*100}')"
                            echo "Disk: $(df -h / | awk 'NR==2{print $5}')"
                        ''',
                        returnStdout: true
                    )
                    
                    echo "Node Resources:\n${nodeInfo}"
                    
                    // 记录到构建描述
                    currentBuild.description = nodeInfo
                }
            }
        }
    }
}

7.3 运维最佳实践

/**
 * Agent运维最佳实践
 */

// ==================== 1. 定期清理工作空间 ====================
pipeline {
    agent any
    
    options {
        // 构建后清理
        skipDefaultCheckout(true)
    }
    
    stages {
        stage('Checkout') {
            steps {
                // 清理并检出
                cleanWs()
                checkout scm
            }
        }
        
        stage('Build') {
            steps {
                sh 'mvn clean package'
            }
        }
    }
    
    post {
        cleanup {
            // 清理临时文件
            cleanWs(
                cleanWhenSuccess: true,
                cleanWhenFailure: false,
                deleteDirs: true,
                patterns: [
                    [pattern: '**/target/**', type: 'INCLUDE']
                ]
            )
        }
    }
}

// ==================== 2. Agent自动扩缩容 ====================
// 使用Kubernetes实现自动扩缩容

// Kubernetes Horizontal Pod Autoscaler配置
/*
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: jenkins-agent-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: jenkins-agent
  minReplicas: 2
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
*/

// ==================== 3. Agent配置版本控制 ====================
// 使用JCasC管理Agent配置

// jenkins.yaml
jenkins:
  nodes:
    - permanent:
        name: "agent-01"
        remoteFS: "/home/jenkins/agent"
        numExecutors: 2
        mode: NORMAL
        launcher:
          ssh:
            host: "192.168.1.100"
            port: 22
            credentialsId: "ssh-credentials"
        labelString: "linux docker"
        nodeProperties:
          - envVars:
              env:
                - key: "JAVA_HOME"
                  value: "/usr/lib/jvm/java-11"

// ==================== 4. 故障自动转移 ====================
pipeline {
    agent none
    
    stages {
        stage('Build with Failover') {
            steps {
                script {
                    def agents = ['agent-01', 'agent-02', 'agent-03']
                    def success = false
                    
                    for (agent in agents) {
                        try {
                            node(agent) {
                                sh 'mvn clean package'
                                success = true
                                break
                            }
                        } catch (Exception e) {
                            echo "Build failed on ${agent}: ${e.message}"
                        }
                    }
                    
                    if (!success) {
                        error("All agents failed")
                    }
                }
            }
        }
    }
}

总结

本文深入讲解了Jenkins分布式构建与Agent管理,涵盖以下关键知识点:

主题核心要点
分布式架构Master-Agent模式、通信协议、架构优势
Agent类型静态Agent、动态Agent、连接协议对比
静态AgentSSH配置、JNLP配置、最佳实践
Kubernetes Agent云配置、Pod模板、Pipeline集成
Docker Agent镜像配置、Dockerfile、多容器编排
负载均衡Label调度、优先级、资源锁、节流策略
监控运维监控指标、健康检查、自动恢复、最佳实践

更多推荐