为什么使用pipeline?
- 本质上,jenkins是一个自动化引擎,它支持许多自动模式。流水线向Jenkins添加了一组强大的工具,支持用例、简单的持续集成到全面的持续交付流水线。 通过对一系列的发布任务建立标准的模板,用户可以利用更多流水线的特性,比如:
- 代码化: 流水线是在代码中实现的,通常会存放到源代码控制,使团队具有编辑、审查和更新他们项目的交付流水线的能力。
- 耐用性:流水线可以从Jenkins的master节点重启后继续运行。
- 可暂停的:流水线可以由人功输入或批准继续执行流水线。
- 解决复杂发布: 支持复杂的交付流程。例如循环、并行执行。
- 可扩展性: 支持扩展DSL和其他插件集成。
- 构建一个可扩展是Jenkins的核心价值,流水线可以通过ShareLibrary的方式来扩展。
pipeline定义
Pipeline
- Jenkins的Pipeline通过Jenkinsfile进行描述(类似于Dockerfile)(镜像通过dockerfile描述,pipeline通过jenkinsfile描述)
- Jenkinsfile是Jenkins的特性(pipeline as code)
- Pipeline是Jenkins的核心功能,提供一组可扩展的工具。
- 通过Pipeline 的DSL语法可以完成从简单到复杂的交付流水线实现。
Jenkinsfile
- Jenkinsfile使用两种语法进行编写,分别是声明式和脚本式。
- 声明式和脚本式的流水线从根本上是不同的。
- 声明式是jenkins流水线更友好的特性。
- 脚本式的流水线语法,提供更丰富的语法特性。
- 声明式流水线使编写和读取流水线代码更容易设计。
Declarative pipeline
声明式流水线语法必须包含在一个 pipeline块内:
pipeline {
/* Declarative Pipeline */
}
pipeline块中主要由Sections, Directives, Steps, 或者赋值语句组成。
Sections
Sections包括agent、stages、steps和post。
pipeline {
agent any
stages {
stage('begin') {
steps {
echo 'Hello pipeline'
}
}
}
post {
always {
echo 'say goodbay'
}
}
}
agent
agent定义 pipeline执行节点,必须在pipeline 块的顶层定义。
主要参数:
- any:可以在任意可用的 agent上执行pipeline
- none:pipeline将不分配全局agent,每个 stage分配自己的agent
- label:指定运行节点agent的 Label
- node:自定义运行节点配置,指定 label,指定 customWorkspace
- docker:使用给定的容器执行流水线
- dockerfile:使用源码库中包含的Dockerfile构建的容器来执行Pipeline
- kubernetes:在kubernetes集群执行Pipeline
上述参数也可以用于stage中。
示例脚本:
pipline {
agent {
node {
label "myslave"
customWorkspace "myWorkspace"
}
}
}
stages
包含一个或多个 stage, Pipeline的大部分工作在此执行。stages也是必须指定的指令,没有参数。此外,每个 pipeline块中必须只有一个 stages。
stage也必须指定,需要定义stage的名字:
pipeline {
agent any
stages {
stage('init') {
steps {
echo 'Hello World'
}
}
}
}
steps
steps位于stage块中,也是必须设置的指令,无参数。
steps块中可以包含script块,可用于存放Scripted Pipeline 脚本:
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
script {
def browsers = ['chrome', 'firefox']
for (int i = 0; i < browsers.size(); ++i) {
echo "Testing the ${browsers[i]} browser"
}
}
}
}
}
}
post
post是在Pipeline或者 stage执行结束后的操作,不是必须出现的指令,可设置以下触发条件:
- always:无论 Pipeline或者stage运行完成的状态如何都会运行
- changed:只有当前 Pipeline或者stage运行的状态与先前运行状态不同时才能运行
- fixed:只有当前一次构建失败或者不稳定,而当前 Pipeline或者stage运行成功时运行
- regression:前一次运行成功,而当前Pipeline或者stage运行状态为failure, unstable 或者 aborted时运行
- aborted:只有当前 Pipeline或者stage处于“aborted”状态时才能运行。通常是手动终止。
- failure:当前 Pipeline或者stage处于“failed”状态时才运行
- success:当前 Pipeline或者stage具有“success”状态时才运行
- unstable:当前 Pipeline或者stage具有“unstable”状态才运行
- unsuccessful:当前 Pipeline或者stage不是“success”状态时运行
- cleanup:不管Pipeline或stage的状态如何,在每一个post条件被执行之后运行。
示例脚本:
pipeline {
agent any
stages {
stage('init') {
steps {
echo 'Hello World'
}
}
}
post {
success {
echo 'success!'
sleep 2
}
always {
echo 'goodbye'
}
}
}
Directives
Declarative pipeline也包含了各种指令,比如environment,options,parameters,triggers等,指令不是必须出现的指令。
environment
定义 Pipeline或stage运行时的环境变量,位于pipeline块顶部的 environment
定义的环境变量适用于流水线中的所有步骤,stage
中定义的 environment
只能应用于 stage
中的步骤。
pipeline {
agent any
environment {
CC = 'clang'
}
stages {
stage('Example') {
environment {
hlw = 'hello world'
}
steps {
echo hlw
}
}
}
}
options
options指令允许在Pipeline内部定义 pipeline专有属性。
pipeline可用选项:
- buildDiscarder: 保持构建的最大个数,超过最大构建数后会丢弃以前的构建。
- checkoutToSubdirectory: 在工作区的子目录中执行自动源代码控制checkout 。
- disableConcurrentBuilds: 禁止并行执行 pipeline任务,可用于防止同时访问共享资源。
- disableResume: 如果控制器重启,不允许管道恢复。
- newContainerPerStage:与docker或dockerfile顶级代理一起使用。指定后,每个阶段将运行在同一节点上的新容器实例中,而不是所有阶段都运行在同一个容器实例中。
- overrideIndexTriggers: 允许重写分支索引触发器的默认处理方法。如果分支索引触发器在多分支或组织标签处被禁用,options { overrideIndexTriggers(true) }将仅为该job启用。否则,options { overrideIndexTriggers(false) }将只禁用该job的分支索引触发器。
- preserveStashes: 保留已完成构建的stashes ,以便在stage 重启时使用。例如: options {preserveStashes()}用于保存最近完成构建的stashes ,或者options {preserveStashes(buildCount: 5)}用于保存最近完成构建的五个堆栈。
- quietPeriod: 为Pipeline设置静默期(以秒为单位),覆盖全局默认值。例如: options {quietPeriod(30)}
- skipDefaultCheckout: 在agent指令中,默认情况下跳过从源代码Checkout代码。例如: options {skipDefaultCheckout()}
- skipStagesAfterUnstable: 一旦构建状态变为 “Unstable“ 状态,就跳过stages。例如: options {skipstagesafterstable ()}
- retry: 失败后,重试整个 Pipeline的次数例如: options { retry(3) }
- timeout: 为Pipeline的运行设置一个超时时间,在此之后,Jenkins就中止Pipeline。例如: options {timeout(time: 1, unit: 'HOURS')}
- timestamps: 在所有由Pipeline运行生成的控制台输出前加上间。例如: options {timestamp ()}
- parallelsAlwaysFailFast: 将流水线中所有后续并行阶段的failfast设置为true,用于并行执行stage中。例如: options {parallelsAlwaysFailFast()}
stage的options指令类似于Pipeline的options指令。然而,stage选项只能包含retry, timeout, 或 timestamps 的步骤,或者与stage相关的声明性选项,比如skipDefaultCheckout。
在stage中,在进入agent或检查任何 when条件之前调用options指令中的步骤。
stage 可用选项:
- skipDefaultCheckout
- timeout:为当前stage的运行设置一个超时时间
- retry
- timestamps
示例脚本:
pipeline {
agent any
options {
timeout (time: 1, unit: 'HOURS')
buildDiscarder(logRotator(numToKeepStr: '2')
retry(5)
}
stages {
stage('init') {
options {
timeout(time: 30, unit: 'SECONDS')
}
steps {
echo 'Hello World'
}
}
}
}
parameters
parameters
指令定义 pipeline的专有参数列表,支持参数类型:
-
string
:字符串类型 -
text
:文本, 可包括多行 -
booleanParam
:布尔参数 -
choice
:choice 参数 -
password
:密码参数
示例脚本:
pipeline {
agent any
parameters {
string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: '')
text(name: 'DEPLOY_TEXT', defaultValue: 'One\nTwo\nThree\n', description: '')
booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '')
choice(name: 'CHOICES', choices: ['one', 'two', 'three'], description: '')
password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'A secret password')
}
stages {
stage('Example') {
steps {
echo "${params.DEPLOY_ENV}"
echo "${params.PASSWORD}"
}
}
}
}
triggers
triggers 指令定义了 Pipeline自动化触发的方式,主要包括3种触发器:
- cron: 接受一个cron样式的字符串来定义 Pipeline触发的间隔周期,例如: triggers { cron('H */4 * * 1-5') }
- pollSCM: 接受一个cron样式的字符串来定义 Jenkins检查SCM源码更新的常规间隔;如果存在新的更改,Pipeline将被重新触发。例如: triggers { pollSCM('H */4 * * 1-5') }
- upstream: 接受以逗号分隔的job字符串和阈值。当字符串中的任何作业以最小阈值完成时,将重新触发Pipeline。例如: triggers { upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS) }
- 更多cron表达式语法介绍可参考 Linux cron定时介绍。
示例脚本:
pipeline {
agent any
triggers {
cron('H */4 * * 1-5')
}
stages {
stage('init') {
steps {
echo 'Hello World'
}
}
}
}
stage
前面介绍过,stage指令位于stages块中,也是必须设置的指令,应至少包含一个。
tools
定义自动安装和PATH
上的工具。如果没有指定agent,则忽略此参数。
支持如下工具:
- maven
- jdk
- gradle
示例脚本:
pipeline {
agent any
tools {
maven 'apache-maven-3.0.1'
}
stages {
stage('Example') {
steps {
sh 'mvn --version'
}
}
}
}
其中工具名 apache-maven-3.0.1
必须在jenkins中预先配置:Manage Jenkins -> Global Tool Configuration 。
input
stage 的 input 指令允许使用 input step提示输入。 在应用了此 options 后,进入 stage 的 agent 或评估 when 条件前, stage 将暂停。 如果 input 被同意, stage 将会继续。
可配置选项如下:
- message:必须指定,是呈现给用户的信息。
- id:可选标识符, 默认为 stage 名称。
- ok: "ok"按钮的可选文本。
- submitter:以逗号分隔的用户列表或允许提交 input 的外部组名。默认允许任何用户。
- submitterParameter:环境变量的可选名称。如果存在,用 submitter 名称设置。
- parameters:提示提交者提供的一个可选的参数列表。 和前面介绍的parameters 指令定义方法一样。
示例脚本:
pipeline {
agent any
stages {
stage('Example') {
input {
message "Should we continue?"
ok "Yes, we should."
submitter "alice,bob"
parameters {
string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')
}
}
steps {
echo "Hello, ${PERSON}, nice to meet you."
}
}
}
}
when
when 指令位于stage指令中,允许流水线根据给定的条件决定是否应该执行阶段,必须包含至少一个条件。
支持以下嵌套条件:
- branch:当正在构建的分支与分支模式匹配时执行这个阶段, 例如: when { branch 'master' }。注意,只适用于多分支流水线。
- buildingTag:当构建正在构建标记时执行该阶段。例如: when {buildingTag()}
- environment:当指定的环境变量是给定的值时,执行这个步骤, 例如: when { environment name: 'DEPLOY_TO', value: 'production' }
- changelog:如果构建的SCM变更日志包含一个给定的正则表达式模式,则执行该阶段,例如: when { changelog '.*^\\[DEPENDENCY\\] .+$' }
- changeset:如果构建的SCM变更集包含一个或多个匹配给定模式的文件,则执行该阶段。例如: when { changeset "**/*.js" }
- changeRequest:如果当前构建是为了一个“change request”(比如GitHub的Pull request, GitLab上的Merge request, Gerrit中的change等)时执行这个阶段。如果没有传递参数,stage在每次变更请求上运行,例如: when { changeRequest() }
- environment:当指定的环境变量设置为给定的值时执行,例如: when { environment name: 'DEPLOY_TO', value: 'production' }
- equals:当期望值与实际值相等时执行,例如: when { equals expected: 2, actual: currentBuild.number }
- expression:当指定的Groovy表达式为true时执行, 例如: when { expression { return params.DEBUG_BUILD } }。注意,当表达式返回字符串时,它们必须转换为布尔值,或者返回null来计算为false。简单地返回“0”或“false”仍然会被计算为“true”。
- tag:如果TAG_NAME变量与给定的模式匹配则执行该阶段。例如: when { tag "release-*" }。如果提供了一个空模式,那么如果存在TAG_NAME变量,则该阶段将执行(与 buildingTag() 相同)。
- not:当嵌套条件是 false 时执行这个阶段,它必须包含一个条件,例如: when { not { branch 'master' } }
- allOf:当所有的嵌套条件都为 true 时执行,必须包含至少一个条件,例如: when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } }
- anyOf:当至少有一个嵌套条件为 true 时执行,必须包含至少一个条件,例如: when { anyOf { branch 'master'; branch 'staging' } }
- triggeredBy:当当前构建被给定的参数触发时执行。例如:
- when { triggeredBy 'SCMTrigger' }
- when { triggeredBy 'TimerTrigger' }
- when { triggeredBy 'BuildUpstreamCause' }
- when { triggeredBy cause: "UserIdCause", detail: "vlinde" }
- 在进入 stage 的 agent 前评估 when
- 默认情况下,如果定义了该stage 的 agent ,则stage的 when 条件将在进入该stage的agent之后计算。但是,这可以通过在 when 块中指定 beforeAgent 选项来更改。如果 beforeAgent 设置为 true ,则首先计算 when 条件,只有当条件计算为 true 时才进入 agent。
- 在 input 指令之前评估 when
- 默认情况下,如果定义了 stage 的 when 条件,则不会在 input 之前求值。但是,这可以通过在 when 块中指定 beforeInput 选项来更改。如果 beforeInput 设置为 true , when 条件将首先计算,只有当条件计算为true时才会进入input。
- beforeInput true优先级高于beforeAgent true。
- 在 options 指令之前评估 when
- 默认情况下,如果stage定义了任何 options ,stage 的 when 条件将在进入该stage的options之后计算。但是,这可以通过在 when 块中指定 beforeOptions 选项来更改。如果 beforeOptions 设置为true,则首先计算 when 条件,只有当条件计算为 true 时才会进入 options。
- beforeOptions true优先级高于beforeInput true和beforeAgent true。
示例脚本:
pipeline {
agent any
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Deploy1') {
when {
branch 'production1'
}
steps {
echo 'Deploying1'
}
}
stage('Deploy2') {
when {
allOf {
branch 'production2'
environment name: 'DEPLOY_TO', value: 'production2'
}
}
steps {
echo 'Deploying2'
}
}
stage('Deploy3') {
when {
beforeInput true
branch 'production3'
}
input {
message "Deploy to production3?"
id "simple-input"
}
steps {
echo 'Deploying3'
}
}
}
}