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 Agent JNLP Agent SSH Agent Master Kubernetes Agent JNLP Agent SSH Agent Master SSH协议连接流程 JNLP协议连接流程 Kubernetes动态Agent SSH连接请求 认证握手 发送slave.jar 启动Agent进程 建立双向通道 发送任务 返回结果 HTTP下载agent.jar 返回agent.jar TCP连接请求 返回密钥验证 建立双向通道 发送任务 返回结果 创建Pod请求 调度Pod Pod就绪通知 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 连接协议详解

协议 连接方向 适用场景 安全性 穿透性
SSH Master→Agent Agent在公网、有SSH服务 高(密钥认证) 需开放SSH端口(22)
JNLP Agent→Master Agent在内网、防火墙后 中(密钥认证) 仅需出站HTTP/HTTPS
WebSocket Agent→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、连接协议对比
静态Agent SSH配置、JNLP配置、最佳实践
Kubernetes Agent 云配置、Pod模板、Pipeline集成
Docker Agent 镜像配置、Dockerfile、多容器编排
负载均衡 Label调度、优先级、资源锁、节流策略
监控运维 监控指标、健康检查、自动恢复、最佳实践

更多推荐