什么是 Jenkins Pipline

Jenkins 流水线是一套插件,它集成持续交付流水线到 Jenkins。流水线提供了一组可扩展的工具,用于通过流水线语法将简单到复杂的交付流水线建模为“代码”.对流水线的定义通常写在一个文本文件中Jenkinsfile,该文件可以被提交到项目的源代码的控制仓库,这是"流水线即代码"的表现形式。

为什么要使用 Jenkins Pipeline

本质上,Jenkins是一个自动化引擎,流水线向 Jenkins 中添加了一组强大的工具,支持通过对一系列的相关任务进行建模,用户可以利用流水线的很多特性:

  • 流水线是在代码中实现的,通常会被一同提交到源代码控制,使团队有编辑,审查和迭代他们的交付流水线的能力。
  • 流水线可以从 Jenkins 的主分支的计划内和计划外的重启中存活下来。
  • 流水线可以有选择的停止或等待人工输入或批准,然后才能继续运行流水线。
  • 流水线支持复杂的现实世界的 CD 需求,包括 fork/join,循环,并行执行工作的能力。
  • 流水线插件支持扩展与其他插件集成

Jenkins Pipline 语法概述

Jenkinsfile能使用两种语法进行编写 - 声明式和脚本化。

声明式和脚本化的流水线从根本上是不同的:

  • 相比脚本化的流水线语法,声明式提供更丰富的语法特性,
  • 声明式是为了使编写和读取流水线代码更容易而设计的。

然而,现实情况中,写到Jenkinsfile中的许多单独的语法组件(或者 "步骤"),通常都是声明式和脚本化相结合

声明式流水线

在声明式流水线语法中,pipeline块定义了整个流水线中完成的所有的工作。

pipeline {
    agent any // 在任何可用的代理上,执行流水线或它的任何阶段
    stages {
        stage('Build') { // 定义 "Build" 阶段
            steps {
                // 执行与 "Build" 阶段相关的步骤
            }
        }
        stage('Test') { // 定义"Test" 阶段
            steps {
                // 执行与"Test" 阶段相关的步骤
            }
        }
        stage('Deploy') { // 定义 "Deploy" 阶段
            steps {
                // 执行与 "Deploy" 阶段相关的步骤
            }
        }
    }
}
  • pipline
  •   是声明式流水线的一种特定语法,他定义了包含执行整个流水线的所有内容和指令的一个块
  • agent
  •   声明式流水线的一种特定语法,它指示 Jenkins 为整个流水线分配一个执行器 (在节点上)和工作区
  • any:在任何可用的代理上执行流水线,配置语法
pipeline {
  agent any
}
  • none:表示该 Pipeline 脚本没有全局的 agent 配置。当顶层的 agent 配置为 none 时, 每个 stage 部分都需要包含它自己的 agent。配置语法
pipeline {
  agent none
  stages {
    stage('Stage For Build'){
      agent any
    }
  }
}
  • label:以节点标签形式选择某个具体的节点执行 Pipeline 命令,例如:agent { label 'my-defined-label' }。节点需要提前配置标签。
pipeline {
  agent none
    stages {
      stage('Stage For Build'){
        agent { label 'role-master' }
        steps {
          echo "role-master"
        }
      }
    }
}
  • stage
  •   声明式流水线中 stage 是必选的,是执行任务的概念性地不同的的子集
  • steps
  •   是声明式流水线的一种特定语法,它描述了在这个 stage 中要运行的步骤

脚本化流水线

在脚本化流水线语法中,一个或多个node块在整个流水线中执行核心工作。 虽然这不是脚本化流水线语法的强制性要求

node { // 在任何可用的代理上,执行流水线或它的任何阶段
    stage('Build') { // 定义 "Build" 阶段。 stage 块 在脚本化流水线语法中是可选的。 然而,在脚本化流水线中实现 stage 块 ,可以清楚的显示Jenkins UI中的每个 stage 的任务子集
        // 执行与 "Build" 阶段相关的步骤
    }
    stage('Test') { // 定义 "Test" 阶段
        // 执行与 "Test" 阶段相关的步骤
    }
    stage('Deploy') { // 定义 "Deploy" 阶段
        // 执行与 "Deploy" 阶段相关的步骤
    }
}
  • node
  •   脚本化流水线的特定语法,它指示 Jenkins 在任何可用的代理/节点上执行流水线,等同于声明式中的 agent
  • stage
  •   脚本化流水线中 stage 是可选的,是执行任务的概念性地不同的的子集,但定义 stage 可以在 UI 中清晰的看到不同模块的分割和执行状态

流水线示例

下面是对同一个任务过程的两种语法的示例

pipeline { 
    agent any 
    stages {
        stage('Build') { 
            steps { 
                sh 'make' 
            }
        }
        stage('Test'){
            steps {
                sh 'make check'
                junit 'reports/**/*.xml' 
            }
        }
        stage('Deploy') {
            steps {
                sh 'make publish'
            }
        }
    }
}
node { 
    stage('Build') { 
        sh 'make' 
    }
    stage('Test') {
        sh 'make check'
        junit 'reports/**/*.xml' 
    }
    stage('Deploy') {
        sh 'make publish'
    }
}


语法比较

在 Jenkins 团队最开始设计 Jenkins 流水线的时候,他们选择 Groovy 作为其基础语法并设计了脚本化的流水线语法,使用嵌入式 Groovy 引擎来为管理员和用户提供高级脚本功能。

由于 Groovy 本身是一种具有功能齐全的编程语言环境,脚本化流水线为 Jenkins 用户提供了大量的灵活性性和可扩展性。 但是,Groovy 学习曲线通常不适合团队的所有成员,因此 Jenkins 团队重新设计了声明式的流水线来为编写 Jenkins 流水线提供一种更简单、更模板化的语法。

两者本质上是相同的流水线系统。都是 "流水线即代码" 的表现形式。它们都能够使用构建到流水线中或插件提供的步骤。但是它们的主要区别在于语法和灵活性

  1. 声明式限制了用户必须使用更严格和预定义的结构, 使其成为更简单的持续交付流水线的理想选择。
  2. 脚本化提供了很少的限制,以至于对脚本和语法的唯一限制往往是由 Groovy 语法本身定义的,而不是任何特定于流水线的规则,这使其成为那些有更复杂需求的人的理想选择。

顾名思义,声明式流水线鼓励声明式编程模型。 而脚本化流水线遵循一个更命令式的编程模型

创建 Jenkins Pipline

流水线可以通过以下任一方式来创建:

  • 通过经典 UI : 可以通过经典 UI 在 Jenkins 中直接输入基本的流水线。
  • 在源码管理系统中 : 你可以手动编写一个Jenkinsfile 文件,然后提交到项目的源代码管理仓库中。
  • 通过 Blue Ocean : Blue Ocean 是 Jenkins 专门为 pipeline 设计的友好性界面版本,在 Blue Ocean 中通过可视化的方式设置一个流水线项目后,Blue Ocean UI 会帮你编写流水线的 Jenkinsfile 文件。

通过经典 UI

新建流水线项目的过程,请参考操作手册 流水线项目,最后一步选择 Pipeline script

Jenkins Pipeline 流水线_Jenkins

选择下面任一种流水线代码复制到 脚本 文本区域

pipeline {
    agent any 
    stages {
        stage('Stage 1') {
            steps {
                echo 'Hello world!' 
            }
        }
    }
}
node { 
    stage('Stage 1') {
        echo 'Hello World' 
    }
}

点击保存后,在当前项目的页面点击立即构建开始构建任务

Jenkins Pipeline 流水线_环境变量_02

点击构建历史记录可以查看构建记录的详细内容

Jenkins Pipeline 流水线_Jenkins_03

点击控制台输出可以查看日志

Jenkins Pipeline 流水线_环境变量_04

在源码管理系统中

新建流水线项目的过程,请参考本手册 流水线项目,最后一步选择 Pipeline script from SCM

Jenkins Pipeline 流水线_Jenkins_05

在源码仓库创建 Jenkinsfile 文件

Jenkins Pipeline 流水线_Jenkins_06

同样的,在 Jenkins UI 中点击立即构建,开始新的构建任务,并通过历史记录查看日志

Jenkins Pipeline 流水线_环境变量_07

内置 Pipeline 文档

流水线拥有内置文档的特性可以让创建各种复杂的流水线变得更容易。该内置文档基于 Jenkins 实例中安装的插件自动生成和更新。可以在任意流水线项目的详情页面找到该功能

Jenkins Pipeline 流水线_Jenkins_08

Jenkins Pipeline 流水线_Test_09

片段生成器

内置的“片段生成器”工具有助于为各个步骤创建代码段,为特定的步骤尝试不同的参数。

Jenkins Pipeline 流水线_环境变量_10

  1. 示例步骤 下拉菜单中选择需要的步骤。
  2. 使用 示例步骤 下拉菜单的动态填充区来配置已选的步骤。
  3. 点击 生成流水线脚本 生成一个能够被复制并粘贴到流水线中的流水线片段

Declarative Directive Generator

为声明式管道指令生成流水线代码,从下拉菜单中选择感兴趣的指令,然后从新表单中选择指令的内容,点击Generate Declarative directive,流水线代码就会出现在下面的框中

Declarative Online Documentation

声明式脚本的在线文档跳转连接

步骤参考

针对片段生成器中一些常用步骤的参考文档

全局变量参考

流水线还提供了一个内置的“全局变量参考”。和片段生成器一样,它也是由插件动态添加。但和片段生成器不一样的是,全局变量参考只包含由流水线或插件提供的可用于流水线的变量文档。

流水线默认提供的变量是:

env

可以从脚本式流水线中访问的环境变量,例如: env.PATHenv.BUILD_ID

params

将为流水线定义的所有参数作为 Map,例如:params.MY_PARAM_NAME

currentBuild

可用于发现当前正在执行的流水线的信息, 比如 currentBuild.resultcurrentBuild.displayName 等属性。

使用 Jenkinsfile

创建一个被源码管理系统维护的 Jenkinsfile 有以下好处:

  • 可以对流水线代码本身做评审/迭代
  • 流水线的单一可信,能够被项目的多个成员查看和编辑,且改动可追踪,。

创建 Jenkinsfile

正如前面介绍的,Jenkinsfile 是一个文本文件,它包含了 Jenkins 流水线的定义并被检入源代码控制仓库。下面的流水线实现了基本的三阶段持续交付流水线。

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                echo 'Building..'
            }
        }
        stage('Test') {
            steps {
                echo 'Testing..'
            }
        }
        stage('Deploy') {
            steps {
                echo 'Deploying....'
            }
        }
    }
}
node {
    stage('Build') {
        echo 'Building....'
    }
    stage('Test') {
        echo 'Testing....'
    }
    stage('Deploy') {
        echo 'Deploying....'
    }
}

不是所有的流水线都有相同的三个阶段,但为大多数项目都会需要这三个阶段。

构建

对于许多项目来说,流水线“工作”的开始就是“构建”阶段。通常流水线的这个阶段包括源代码的组装、编译或打包。Jenkinsfile 文件不能替代现有的构建工具,如 GNU/Make、Maven、Gradle 等,而应视其为一个将项目的开发生命周期的多个阶段(构建、测试、部署等)绑定在一起的模型。

Jenkins 有许多插件可以用于调用几乎所有常用的构建工具,下面这个例子只是从 shell 步骤(sh)调用 makesh 步骤假设系统是基于 Unix/Linux 的,对于基于 Windows 的系统可以使用 bat 替代。

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                sh 'make' 
                archiveArtifacts artifacts: '**/target/*.jar',fingerprint: true 
            }
        }
    }
}
node {
    stage('Build') {
        sh 'make' 
        archiveArtifacts artifacts: '**/target/*.jar',fingerprint: true 
    }
}
  • sh 步骤调用 make 命令,只有命令返回的状态码为零时才会继续。任何非零的返回码都将使流水线失败。
  • archiveArtifacts 捕获符合(`**/target/*.jar`)匹配的交付件并将其保存到 Jenkins master 节点

测试

运行自动化测试是任何成功的持续交付过程的重要组成部分。因此,Jenkins 有许多测试记录,报告和可视化工具,这些都是由各种插件提供的。最基本的,当测试失败时,让 Jenkins 记录这些失败以供汇报以及在 web UI 中可视化是很有用的。下面的例子使用由 JUnit 插件 提供的 junit 步骤。

pipeline {
    agent any

    stages {
        stage('Test') {
            steps {
                /* `make check` 在测试失败后返回非零的退出码;
                使用 `true` 允许流水线继续进行 */
                sh 'make check || true' 
                junit '**/target/*.xml' 
            }
        }
    }
}
node {
    /* .. snip .. */
    stage('Test') {
        /* `make check` 在测试失败后返回非零的返回码;
        使用 `true` 允许流水线继续进行 */
        sh 'make check || true' 
        junit '**/target/*.xml' 
    }
    /* .. snip .. */
}
  • 使用内联的 shell 条件(sh 'make || true')确保 sh 步骤总是看到退出码是零,使 junit 步骤有机会捕获和处理测试报告
  • junit 捕获并关联与包含模式(\**/target/*.xml)匹配的 JUnit XML 文件

部署

部署可以隐含许多步骤,这取决于项目或组织的要求。 在示例流水线的这个阶段,“Build(构建)” 和 “Test(测试)” 阶段都已成功执行。从本质上讲,“Deploy(部署)” 阶段只有在之前的阶段都成功完成后才会进行,否则流水线会提前退出。

pipeline {
    agent any

    stages {
        stage('Deploy') {
            when {
              expression {
                currentBuild.result == null || currentBuild.result == 'SUCCESS' 
              }
            }
            steps {
                sh 'make publish'
            }
        }
    }
}
node {
    /* .. snip .. */
    stage('Deploy') {
        if (currentBuild.result == null || currentBuild.result == 'SUCCESS') { 
            sh 'make publish'
        }
    }
    / .. snip .. */
}

常用 Jenkinsfile 语法

字符串插值

Jenkins 使用与 Groovy 相同的规则进行字符串插值。 Groovy 的字符串插值支持可能会使很多新手感到困惑。尽管 Groovy 支持使用单引号或双引号声明一个字符串,例如:

def singlyQuoted = 'Hello'
def doublyQuoted = "World"

但是只有后面使用双引号这样的字符串才支持基于美元符($)的字符串插值,例如:

def username = 'Jenkins'
echo 'Hello Mr. ${username}'             // 不支持插值
echo "I said,Hello Mr. ${username}"     // 支持插值

其结果为:

Hello Mr. ${username}
I said,Hello Mr. Jenkins

使用环境变量

Jenkins 流水线通过全局变量 env 提供环境变量,它在 Jenkinsfile 文件的任何地方都可以使用。查看完整的环境变量列表可以访问 ${YOUR_JENKINS_URL}/pipeline-syntax/globals#env,下面介绍部分常用变量

变量名

说明

BUILD_ID

当前构建的 ID

BUILD_NUMBER

当前构建号,比如 “153”。

BUILD_URL

可以定位此次构建结果的 URL(比如 http://buildserver/jenkins/job/MyJobName/17/ )

EXECUTOR_NUMBER

用于识别执行当前构建的执行者的唯一编号(在同一台机器的所有执行者中),编号从 0 开始

JAVA_HOME

如果你的任务配置了使用特定的一个 JDK,那么这个变量就被设置为此 JDK 的 JAVA_HOME

JOB_NAME

本次构建的项目名称,如 “foo” 或 “foo/bar”

NODE_NAME

运行本次构建的节点名称。对于 master 节点则为 “master”

WORKSPACE

workspace 的绝对路径。

引用或使用这些环境变量就像访问 Groovy Map 的 key 一样, 例如:

pipeline {
    agent any
    stages {
        stage('Example') {
            steps {
                echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}"
            }
        }
    }
}
node {
    echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}"
}
设置环境变量

在 Jenkins 流水线中,取决于使用的是声明式还是脚本式流水线,设置环境变量的方法不同。

声明式流水线支持 environment 指令,而脚本式流水线的使用者必须使用 withEnv 步骤。

pipeline {
    agent any
    environment { 
        // 全局变量
        CC = 'clang'
    }
    stages {
        stage('Example') {
            environment { 
                // 局部变量
                DEBUG_FLAGS = '-g'
            }
            steps {
                sh 'printenv'
            }
        }
    }
}
node {
  withEnv(['MYTOOL_HOME=/usr/local/mytool']) {
    sh '$MYTOOL_HOME/bin/start'
  }
}

使用凭据

Jenkins 中配置的凭据可以在流水线中处理以便于立即使用。Jenkins 的声明式流水线语法有一个 credentials() 辅助方法(在environment指令中使用),它支持 secret 文本,带密码的用户名,以及 secret 文件凭据。参考 Manage Credentials 凭据管理

Jenkins Pipeline 流水线_Jenkins_11

Secret text 文本

下面的流水线代码演示了如何使用环境变量为 secret 文本凭据创建流水线的示例。

在该示例中,将两个 secret 文本凭据赋予各自的环境变量来访问 Amazon Web 服务(AWS)。这些凭据已在 Jenkins 中配置了各自的凭据 ID jenkins-aws-secret-key-idjenkins-aws-secret-access-key

pipeline {
    agent any
    environment {
        AWS_ACCESS_KEY_ID = credentials('jenkins-aws-secret-key-id')
        AWS_SECRET_ACCESS_KEY = credentials('jenkins-aws-secret-access-key')
    }
    stages {
        stage('Example stage 1') {
            steps {
                // 运行会报错,因为 Secret text 属于保密文本,不应该被打印
                echo "${env.AWS_ACCESS_KEY_ID}" 
            }
        }
        stage('Example stage 2') {
            steps {
                // 运行会报错,因为 Secret text 属于保密文本,不应该被打印
                echo "${env.AWS_SECRET_ACCESS_KEY}"
            }
        }
    }
}
带密码的用户名

下面的流水线代码片段展示了如何创建一个使用带密码的用户名凭据的环境变量的流水线。

在该示例中,带密码的用户名凭据被分配了环境变量,用来使你的组织或团队以一个公用账户访问 harbor 仓库;这些凭据已在 Jenkins 中配置了凭据 ID jenkins-harbor-common-creds

当在 environment 指令中设置凭据环境变量时:

pipeline {
    agent any
    stages {
        stage('Example stage 1') {
            environment {
                HARBOR_COMMON_CREDS = credentials('jenkins-harbor-common-creds')
                // HARBOR_COMMON_CREDS - 包含一个以冒号分隔的用户名和密码,格式为 username:password。
                // HARBOR_COMMON_CREDS_USR- 附加的一个仅包含用户名部分的变量。
                // HARBOR_COMMON_CREDS_PSW- 附加的一个仅包含密码部分的变量。
            }
            steps {
                // 可以输出用户名
                echo "${env.HARBOR_COMMON_CREDS_USR}"
                // 报错,因为密码不应该被打印
                echo "${env.HARBOR_COMMON_CREDS_PSW}"
            }
        }
    }
}
Secret 文件

就流水线而言,secret 文件的处理方式与 Secret text 文本 完全相同。

实际上,secret 文本和 secret 文件凭据之间的唯一不同是,对于 secret 文本,凭据本身直接输入到 Jenkins 中,而 secret 文件的凭据则原样保存到一个文件中,之后将传到 Jenkins。与 secret 文本不同的是,secret 文件适合:

  • 太长而不能方便直接输入 Jenkins 的内容
  • 二进制格式内容,比如 GPG 文件
其他凭据类型

如果你需要在流水线中设置除了 secret 文本、带密码的用户名、secret 文件以外的其他凭据——即 SSH 秘钥或证书,那么请使用 Jenkins 的片段生成器特性。参考本手册 片段生成器

  1. 示例步骤字段中,选择 withCredentials: Bind credentials to variables
  2. 绑定下面,点击新增并从下拉框中选择:
  1. SSH User Private Key - 要处理 SSH 公私钥对凭据,可以提供:
  • Key 文件变量 - 将要绑定到这些凭据的环境变量的名称。Jenkins 实际上将此临时变量分配给 SSH 公私钥对身份验证过程中所需的私钥文件的安全位置。
  • 密码变量可选)- 将要被绑定到与 SSH 公私钥对相关的 密码 的环境变量的名称。
  • 用户名变量可选)- 将要绑定到与 SSH 公私钥对相关的用户名的环境变量的名称。
  • 凭据 - 选择存储在 Jenkins 中的 SSH 公私钥对证书。该字段的值是凭据 ID,Jenkins 将其写入生成的代码片段中。
  • Jenkins Pipeline 流水线_Test_12

  1. Certificate - 要处理 PKCS#12 证书,可以提供:
  • 密钥库变量 - 将要绑定到这些凭据的环境变量的名称。
  • 密码变量可选) - 将会被绑定到与证书相关的密码的环境变量的名称。
  • 别名变量可选) - 将会被绑定到与证书相关的唯一别名的环境变量的名称。
  • 凭据 - 选择存储在 Jenkins 中的证书。该字段的值是凭据 ID,Jenkins 将其写入生成的代码片段中。
  • Jenkins Pipeline 流水线_Jenkins_13

  1. 点击 生成流水线脚本,Jenkins 会为你指定的凭据生成一个 withCredentials( ... ) { ... } 的流水线步骤片段,你可以将其复制并粘贴到你的声明式或脚本化流水线代码中。

处理参数

声明式流水线支持参数开箱即用,允许流水线在运行时通过parameters 指令接受用户指定的参数。配置脚本式流水线的参数是通过 properties 步骤实现的,可以在 片段生成器 中找到。

pipeline {
    agent any
    parameters {
        string(name: 'Greeting',defaultValue: 'Hello',description: 'How should I greet the world?')
    }
    stages {
        stage('Example') {
            steps {
                echo "${params.Greeting} World!"
            }
        }
    }
}
properties([parameters([string(defaultValue: 'Hello',description: 'How should I greet the world?',name: 'Greeting')])])

node {
    echo "${params.Greeting} World!"
}

处理故障

声明式流水线默认通过 post 节段支持强大的故障处理,它允许声明许多不同的 “post 条件”,比如: alwaysunstablesuccessfailurechanged。然而脚本化的流水线依赖于 Groovy 的内置的 try/catch/finally 语义来处理流水线运行期间的故障。

pipeline {
    agent any
    stages {
        stage('Test') {
            steps {
                sh 'make check'
            }
        }
    }
    post {
        always {
            junit '**/target/*.xml'
        }
        failure {
            mail to: team@example.com,subject: 'The Pipeline failed :('
        }
    }
}
node {
    /* .. snip .. */
    stage('Test') {
        try {
            sh 'make check'
        }
        finally {
            junit '**/target/*.xml'
        }
    }
    /* .. snip .. */
}

使用多个代理 agent

在之前所有的示例中都只使用了一个代理。这意味着 Jenkins 会分配一个可用的执行者而无论该执行者是如何打标签 Label 或配置的

在下面的示例中,“Build” 阶段将会在一个代理中执行,并且构建结果将会在后续的 “Test” 阶段被两个分别标记为 “linux” 和 “windows” 的代理重用。agent/node 中的参数允许使用任何可用的 Jenkins 标签表达式。

pipeline {
    agent none
    stages {
        stage('Build') {
            agent any
            steps {
                checkout scm
                sh 'make'
                stash includes: '/target/*.jar',name: 'app' 
            }
        }
        stage('Test on Linux') {
            agent { 
                label 'linux'
            }
            steps {
                unstash 'app' 
                sh 'make check'
            }
            post {
                always {
                    junit '/target/*.xml'
                }
            }
        }
        stage('Test on Windows') {
            agent {
                label 'windows'
            }
            steps {
                unstash 'app'
                bat 'make check' 
            }
            post {
                always {
                    junit '**/target/*.xml'
                }
            }
        }
    }
}
stage('Build') {
    node {
        checkout scm
        sh 'make'
        stash includes: '/target/*.jar',name: 'app' 
    }
}

stage('Test') {
    node('linux') { 
        checkout scm
        try {
            unstash 'app' 
            sh 'make check'
        }
        finally {
            junit '/target/*.xml'
        }
    }
    node('windows') {
        checkout scm
        try {
            unstash 'app'
            bat 'make check' 
        }
        finally {
            junit '**/target/*.xml'
        }
    }
}


高级脚本式流水线

脚本式流水线是一种基于 Groovy 的领域特定语言 ,大多数 Groovy 语法都可以无需修改,直接在脚本式流水线中使用。

并行执行

上一节示例跨两个不同的平台是以串联地运行测试。在实践中,如果执行 make check 需要30分钟来完成,那么两个 “Test” 阶段加起来就需要 60 分钟来完成。因此,流水线有一个内置的并行执行部分脚本式流水线的功能,通过贴切的名为 parallel 的步骤实现。

stage('Build') {
    /* .. snip .. */
}

stage('Test') {
    parallel 
    linux: {
        node('linux') {
            checkout scm
            try {
                unstash 'app'
                sh 'make check'
            }
            finally {
                junit '**/target/*.xml'
            }
        }
    },
    windows: {
        node('windows') {
            /* .. snip .. */
        }
    }
}

在 Pipeline 中使用 Docker

许多公司都会使用 Docker 在不同机器之间统一构建和测试环境,并为部署应用程序提供一致性保障。从 Pipeline 版本 2.5 或以上开始,Pipeline 支持在Jenkinsfile中进行配置从而与 Docker 进行交互。

安装 Docker 插件

在 Pipeline 中使用 Docker 的前置条件是需要安装好 Docker 插件,插件的安装参考 插件管理

Jenkins Pipeline 流水线_环境变量_14

指定 Docker 镜像为构建环境

可以将一个 Docker 镜像指定为 agent/node,从而作为单个 Stage 或整个流水线的执行环境。

pipeline {
    agent {
        docker { image 'node:7-alpine' }
    }
    stages {
        stage('Test') {
            steps {
                sh 'node --version'
            }
        }
    }
}
node {
    /* Requires the Docker Pipeline plugin to be installed */
    docker.image('node:7-alpine').inside {
        stage('Test') {
            sh 'node --version'
        }
    }
}

使用 Dockerfile 并运行一个容器环境

默认情况下,将使用源码仓库的根目录下的名为 Dockerfile 的文件

pipeline {
    agent { dockerfile true }
    stages {
        stage('Test') {
            steps {
                sh 'node --version'
                sh 'svn --version'
            }
        }
    }
}

如果在另一个目录下构建 Dockerfile,使用 dir 选项来指定目录

如果 Dockerfile 有另一个名称,可以使用 filename 选项指定该文件名。

可以传递额外的参数到 docker build ... 使用 additionalBuildArgs 选项提交

agent {
    // 等价于 "docker build -f NewName.Dockerfile --build-arg version=1.0.2 ./build/
    dockerfile {
        filename 'NewName.Dockerfile'
        dir 'build'
        additionalBuildArgs  '--build-arg version=1.0.2'
    }
}