18.3.3 流水线阶段设计与并行/矩阵构建

在流水线设计中,合理拆分阶段(stage)并利用并行与矩阵构建可以显著提升交付效率与可维护性。阶段划分应贴合价值流,从源码到发布形成清晰链路,并在关键节点设置质量门禁。

文章图片

阶段设计原则#

  • 按价值流拆分:Checkout → Build → Unit Test → Integration Test → Package → Security Scan → Deploy → Verify。
  • 阶段内聚、职责单一:单个阶段只做一类工作,便于失败定位与重试。
  • 可观测性:每阶段输出关键日志、产物与指标,便于追踪。
  • 可重用与可扩展:与共享库结合,将通用步骤封装。
  • 环境隔离:区分构建、测试、预发与生产环境,避免污染。

并行构建(Parallel)#

并行适用于独立任务,例如多模块构建、分组测试、扫描任务等。

应用场景
- 多模块项目并行构建
- 单元测试与代码扫描并行
- 多环境部署前的并行验证

设计要点
- 资源限制:控制并发避免Agent耗尽
- 失败策略:设置failFast按需快速失败
- 结果汇总:并行分支产物统一归档与报告聚合

示例结构(Declarative)

// Jenkinsfile
pipeline {
  agent any
  options { timestamps() }
  stages {
    stage('Test') {
      failFast true
      parallel {
        stage('UnitTest') {
          steps {
            sh 'mvn -B -DskipITs=false test'
          }
        }
        stage('IntegrationTest') {
          steps {
            sh 'mvn -B -DskipUTs=true verify'
          }
        }
        stage('SecurityScan') {
          steps {
            sh 'trivy fs --exit-code 0 --format table .'
          }
        }
      }
    }
  }
  post {
    always {
      junit 'target/surefire-reports/*.xml'
      archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
    }
  }
}

矩阵构建(Matrix)#

矩阵构建用于多维度组合测试或打包,例如不同JDK、OS、架构或环境组合。

应用场景
- JDK 8/11/17 多版本测试
- Linux/Windows 多平台构建
- 多架构(amd64/arm64)制品构建

设计要点
- 维度控制:避免组合爆炸,合理裁剪矩阵
- 排除规则:通过exclude去除无效组合
- 统一产物命名:包含维度信息,便于追踪
- 资源调度:为不同组合指定合适的Agent标签

示例结构(Declarative)

// Jenkinsfile
pipeline {
  agent none
  stages {
    stage('Matrix Build') {
      matrix {
        axes {
          axis { name 'JDK'; values '8', '11', '17' }
          axis { name 'OS'; values 'linux', 'windows' }
        }
        excludes {
          exclude { axis { name 'OS'; values 'windows' }
                   axis { name 'JDK'; values '8' } }
        }
        agent { label "${OS}" }
        stages {
          stage('Build') {
            steps {
              sh 'echo "Build with JDK=${JDK} on ${OS}"'
              sh 'mvn -B -DskipTests package'
            }
          }
          stage('Test') {
            steps {
              sh 'mvn -B test'
            }
          }
        }
        post {
          always {
            archiveArtifacts artifacts: "target/*-${JDK}-${OS}.jar", allowEmptyArchive: true
          }
        }
      }
    }
  }
}

并行与矩阵结合策略#

  • 先矩阵后并行:适合多维组合后并行执行测试
  • 先并行后矩阵:适合按模块并行,再在模块内矩阵测试
  • 拆分流水线:复杂场景使用多流水线协作(上游触发)

并行+矩阵示例

// Jenkinsfile
pipeline {
  agent none
  stages {
    stage('Modules') {
      parallel {
        stage('Module-A') {
          stages {
            stage('Matrix-A') {
              matrix {
                axes { axis { name 'JDK'; values '11', '17' } }
                agent { label 'linux' }
                stages {
                  stage('Build') { steps { sh 'mvn -pl module-a -am package' } }
                }
              }
            }
          }
        }
        stage('Module-B') {
          steps { sh 'mvn -pl module-b -am test' }
        }
      }
    }
  }
}

失败与重试策略#

  • 关键阶段阻断:构建与测试失败直接阻断
  • 非关键阶段降级:扫描或通知失败可标记为UNSTABLE
  • 重试控制:对不稳定测试设置retry次数
  • 超时控制:对长耗时阶段设置timeout

示例

stage('E2E Test') {
  options { timeout(time: 20, unit: 'MINUTES') }
  steps {
    retry(2) {
      sh './tests/e2e.sh'
    }
  }
  post {
    unsuccessful { currentBuild.result = 'UNSTABLE' }
  }
}

产物与报告管理#

  • 使用archiveArtifacts归档产物
  • 使用JUnit、Allure等统一测试报告
  • 并行/矩阵结果汇总生成统一可视化报告

报告汇总示例

post {
  always {
    junit 'target/surefire-reports/*.xml'
    archiveArtifacts artifacts: 'target/*.jar, reports/**', fingerprint: true
  }
}

安装与环境准备示例#

并行与矩阵通常依赖多Agent与标签,以下为基础安装与标签设置示例。

Linux节点安装Java与Maven

# Ubuntu
sudo apt update
sudo apt install -y openjdk-11-jdk maven

# 校验
java -version
mvn -v

Jenkins节点标签设置
- 在 Jenkins 节点配置中添加标签:linuxwindows
- 在 Pipeline 中用 agent { label 'linux' } 绑定

Docker化构建可选

# 安装Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker jenkins

# 验证
docker version

常见排错与定位#

  1. 并行阶段不执行
    - 可能原因:语法嵌套错误或agent none未设置分支agent
    - 排查:检查流水线日志,确保每个并行分支有agent或继承agent any
  2. 矩阵组合过多导致排队
    - 可能原因:轴值过多、Agent不足
    - 排查:减少轴值、增加排除规则,或增加节点与标签
  3. 归档产物为空
    - 可能原因:产物路径与矩阵维度命名不一致
    - 排查:在构建后ls -l target验证产物生成
  4. JDK切换失败
    - 可能原因:节点未安装对应JDK
    - 排查:在节点执行java -version确认,或使用工具链插件

诊断命令示例

# 查看构建节点信息
uname -a
java -version
mvn -v

# 查看产物目录
ls -lh target/

练习题#

  1. 将现有单模块流水线改造为并行的UnitTestSecurityScan两个阶段,要求失败即中断。
  2. 设计一个JDK=11/17、OS=linux/windows的矩阵构建,并排除windows+11组合。
  3. 在矩阵构建中为不同组合生成命名包含维度信息的产物,例如app-11-linux.jar
  4. 为E2E测试阶段添加timeoutretry,并在失败后标记为UNSTABLE。
  5. 将并行分支产物统一归档并生成JUnit报告。