一、介绍
官方文档
Jenkins Pipeline(或简称为“Pipeline”,大写字母为“P”)是一套插件,支持在Jenkins中实现和集成连续交付管道。
持续交付(CD)管道是将软件从版本控制直接传递给用户和客户的过程的自动表达。对软件的每次更改(在源代码管理中提交)都会在发布的过程中经历一个复杂的过程。此过程涉及以可靠且可重复的方式构建软件,以及通过多个测试和部署阶段推进构建的软件(称为“构建”)。
Pipeline提供了一组可扩展的工具,用于通过管道域特定语言(Pipeline domain-specific language)语法“作为代码”对简单到复杂的传输管道进行建模。
Jenkins管道的定义被写入一个文本文件(称为Jenkinsfile),该文件又可以提交给项目的源代码控制库。这是“作为代码的管道”的基础;将CD管道视为应用程序的一部分,以便像任何其他代码一样进行版本控制和审查。
学习pipeline语法可以查看官方文档也可以在经典UI中选择帮助
两种Pipeline语法的选择
选择
Jenkinsfile可以使用两种语法编写 - Declarative和Scripted。声明式和脚本化管道的构造从根本上不同。
早期Jenkins是使用Java实现的,所以在很早的时候就引入了groovy作为DSL,管理员可以使用groovy来实现一些自动化和高级的管理功能。因为groovy引擎已经集成到Jenkins,所以在pipeline一开始很自然就使用groovy来编写Jenkinsfile。也就是脚本式pipeline。但是groovy毕竟是一种语言,且学习成本很高。这个时候声明式的pipeline就出现了,主要是为了降低入门的难度,提高分工协作的能力。
作为官方推荐的语法,Declarative Pipeline也获得了很多官方的支持,比如blue ocean。即使声明式语法还没有支持的功能,也可以在声明式里直接调用脚本。
所以Declarative Pipeline是个不错的选择。
区别
在Declarative Pipeline语法中,pipeline块定义了整个管道中完成的所有工作。表达式与Groovy语法基本相同,区别在于:
Pipeline的顶级必须是一个块,特别是:pipeline {}
没有分号作为语句分隔符。 每个声明都必须独立
块只能由章节,指令,步骤或赋值语句组成。(Sections, Directives, Steps, or assignment statements.)
属性引用语句被视为无参数方法调用。 例如,输入被视为输入()
可以使用声明性指令生成器(Declarative Directive Generator)来帮助您开始配置声明性管道中的指令和部分。
声明式pipeline
pipeline {
agent any
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
branch 'production'
environment name: 'DEPLOY_TO', value: 'production'
}
steps {
echo 'Deploying'
}
}
}
}
脚本式pipeline
node {
stage('Example') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}
一个基本的Jenkinsfile
大多数项目并不止三个步骤,不过这创建、测试、交付是最基本的工作流。
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building..'
}
}
stage('Test') {
steps {
echo 'Testing..'
}
}
stage('Deploy') {
steps {
echo 'Deploying....'
}
}
}
}
章节Sections
通常包含一个或多个Directives or Steps。
关键字 | 意义 | 常见选项 |
---|---|---|
agent | 指定整个管道或特定阶段在Jenkins环境中的执行位置,具体取决于代理程序部分的放置位置。 该部分必须在管道块内的顶层定义,但阶段级使用是可选的。 | any, none, label, node, docker, dockerfile |
post | post部分定义了一个或多个附加步骤,这些步骤在完成Pipeline或stage的运行时运行(取决于Pipeline中post部分的位置)。 | always, changed, fixed, regression, aborted, failure, success, unstable, cleanup |
stages | 包含一个或多个阶段指令的序列 | |
steps | 定义了在给定阶段指令中要执行的一系列一个或多个步骤。 |
指令Directives
关键字 | 意义 | 常见选项 |
---|---|---|
environment | 指定一系列键 - 值对,它们将被定义为所有 具体取决于环境指令在管道中的位置。 | credentials() |
options | 允许在Pipeline中配置特定于Pipeline的选项。 | buildDiscarder, checkoutToSubdirectory, disableConcurrentBuilds, newContainerPerStage, overrideIndexTriggers, preserveStashes, quietPeriod, retry, skipDefaultCheckout,skipStagesAfterUnstable, timeout,timestamps |
parameters | 提供了用户在触发Pipeline时应提供的参数列表 | string, test, booleanParam, choice, file, password |
triggers | 定义了重新触发管道的自动方式。 对于与GitHub或BitBucket等源集成的管道,可能不需要触发器,因为基于webhooks的集成可能已经存在。 目前可用的触发器是cron,pollSCM和upstream。 | cron, pollSCM, upstream |
stage | 位于阶段部分。Pipeline所做的所有实际工作都将包含在一个或多个阶段指令中。 | |
tools | 定义用于自动安装和放置PATH的工具的部分。 如果未指定agent none,则忽略此项。引用的工具名必须在Manage Jenkins → Global Tool Configuration中预定义 |
maven,jdk,gradle |
input | 允许您使用输入步骤提示输入。 在应用any选项之后,在进入stage的agent或评估其状态之前,stage将暂停。 如果输入被批准,则stage将继续。 作为输入提交的一部分提供的任何参数将在该阶段的其余部分的环境中可用 | message, id, ok, submitter, submitterParameter, parameters |
when | 允许Pipeline根据给定的条件确定是否应该执行该阶段。 when指令必须至少包含一个条件。 | beforeAgent, branch, buildingTag, changelog, changeset, changeRequest, environment, equal, expression, tag, not, allof, anyof |
串行stages - Sequential Stages
声明性管道中的阶段可以按顺序声明要在其中运行的嵌套阶段的列表。
请注意,一个stage有且仅有一个steps, parallel, or stages,最后一个是连续阶段。
stages中各stage的阶段不能包含parallel或stage(s)本身,但它们允许使用阶段的所有其他功能,包括agent, tool, when。
并行stages - Parallel
使用parallel可以在不同的代理商同时执行某项任务,和lable的区别在于,lable是线性的,比如完成一项测试需要30MIN分别在windows上执行和linux上执行需要60M。使用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 {
agent any
environment {
PROJECT_HOME='/var/lib/jenkins/workspace/xxx/projdir'
}
stages{
stage("test_env"){
environment {
DEBUG_FLAGS = '-g'
}
steps {
echo "工作目录是:$PROJECT_HOME"
echo "内置的环境变量可以直接使用 $BUILD_ID"
echo "内置的环境变量可以直接使用 $WORKSPACE"
echo "stage设置的环境变量只能在本块中引用 $DEBUG_FLAGS"
}
}
}
}
自定义变量
1、environment顶层pipeline块中使用的指令将应用于管道中的所有步骤,在stage中设置的只应用于stage内。
2、和shell的变量引用一样,使用双引号应用变量,单引号为字符串。
3、在脚本式pipeleine中使用withEnv
内置环境变量
系统内置的环境变量可以直接引用。系统的内置环境变量记录在$ {YOUR_JENKINS_URL}--项目-- pipeline-syntax
流水线语法-- globals全局变量参考--env部分。
BUILD_ID | 当前的版本ID,与在Jenkins版本1.597+中创建的版本相同,为BUILD_NUMBER |
---|---|
BUILD_NUMBER | 当前的内部版本号,例如“ 153” |
BUILD_TAG | jenkins字符串-$ {JOB_NAME}-$ {BUILD_NUMBER}。方便放入资源文件,JAR文件等中,以便于识别 |
BUILD_URL | 可以找到此构建结果的URL(例如http:// buildserver / jenkins / job / MyJobName / 17 /) |
EXECUTOR_NUMBER | 标识执行此构建的当前执行程序(在同一计算机的执行程序中)的唯一编号。这是您在“构建执行器状态”中看到的数字,除了该数字从0而不是1开始 |
JAVA_HOME | 如果您的作业配置为使用特定的JDK,则此变量设置为指定JDK的JAVA_HOME。设置此变量后,PATH也将更新为包括JAVA_HOME的bin子目录 |
JENKINS_URL | Jenkins的完整URL,例如https://example.com:port/jenkins/(注意:仅在“系统配置”中设置了Jenkins URL时可用) |
JOB_NAME | 此生成的项目的名称,例如“ foo”或“ foo / bar”。 |
NODE_NAME | 当前构建正在其上运行的节点的名称。将主节点设置为“ master”。 |
WORKSPACE | 工作区的绝对路径 |
动态设置环境变量
环境变量可以在运行时设置,可以由Shell脚本(sh
),Windows批处理脚本(bat
)和PowerShell脚本(powershell
)的状态returnStatus
或结果returnStdout
作为变量值。
使用returnStdout
尾随空格时,会将空白附加到返回的字符串中。使用.trim()
删除它。
Jenkinsfile(声明性管道)
pipeline {
agent any
environment {
// Using returnStdout
CC = """${sh(
returnStdout: true,
script: 'echo "clang"'
)}"""
// Using returnStatus
EXIT_STATUS = """${sh(
returnStatus: true,
script: 'exit 1'
)}"""
}
stages {
stage('Example') {
environment {
DEBUG_FLAGS = '-g'
}
steps {
sh 'printenv'
}
}
}
}
三、参数
参数和环境变量不一样的地方是,参数可以在pipeline运行时指定,就是类似交互的意思。例如有字符串参数,布尔选择参数,下拉多选参数等。可以通过UI设置,也可以卸载pipeline代码中,在代码片段生成器中找到properties
步骤参考。
pipeline{
agent any
parameters {
string(name: 'userName', defaultValue: 'Anthony', description: 'please give a name')
choice(name: 'version', choices: ['1.1', '1.2', '1.3'], description: 'select the version to test')
booleanParam(name: 'is_boy', defaultValue: true, description: 'you is boy or not')
}
stages {
stage('test') {
steps{
script {
sh "java -version"
}
}
}
}
}
字符串参数
定义一个字符串参数,用户可以在Jenkins UI上输入字符串,常见使用这个参数的场景有,用户名,收件人邮箱,文件网络路径,主机名称的或者url等。
pipeline {
agent any
parameters {
string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: '')
}
}
布尔值参数
定义一个布尔类型参数,用户可以在Jenkins UI上选择是还是否,选择是表示代码会执行这部分,如果选择否,会跳过这部分。一般需要使用布尔值的场景有,执行一些特定集成的脚本或则工作,或者事后清除环境,例如清楚Jenkins的workspace这样的动作。
pipeline {
agent any
parameters {
booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '')
}
}
文本参数
文本(text)的参数就是支持写很多行的字符串,这个变量我好像没有使用过,例如想给发送一段欢迎的消息,你可以采用text的参数
pipeline {
agent any
parameters {
text(name: 'Welcome_text', defaultValue: 'One
Two
Three
', description: '')
}
}
选择参数
选择(choice)的参数就是支持用户从多个选择项中,选择一个值用来表示这个变量的值。工作中常用的场景,有选择服务器类型,选择版本号等。
pipeline {
agent any
parameters {
choice(name: 'ENV_TYPE', choices: ['test', 'dev', 'product'], description: 'test means test env,….')
}
}
文件参数
文件(file)参数就是在Jenkins 参数化构建UI上提供一个文件路径的输入框,Jenkins会自动去你提供的网络路径去查找并下载。一般伴随着还有你需要在Pipleline代码中写解析文件。也有这样场景,这个构建job就是把一个war包部署到服务器上特定位置,你可以使用这个文件参数。
pipeline {
agent any
parameters {
name: 'FILE', description: 'Some file to upload')
}
}
密码参数
密码(password)参数就是在Jenkins 参数化构建UI提供一个暗文密码输入框,例如,我需要在一些linux机器上做自动化操作,需要提供机器的用户名和密码,由于密码涉及安全问题,一般都采用暗文显示,这个时候你就不能用string类型参数,就需要使用password参数类型。
pipeline {
agent any
parameters {
password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'A secret password')
}
}
使用
stages {
stage('test_params') {
steps {
echo "pv_name: ${params.pv_name}"
echo "pv_volume: ${params.pv_volume}"
echo "dp_name: ${params.dp_name}"
echo "dp_port: ${params.dp_port}"
}
}
}
四、凭证
凭证类型
SSH用户私钥 | 处理 SSH公/私钥对凭据,您可以从中指定: |
---|---|
密钥文件变量 | 将绑定到这些凭据的环境变量的名称。Jenkins实际上将此临时变量分配给SSH公钥/私钥对身份验证过程中所需的私钥文件的安全位置。 |
密码短语变量 | 将绑定到 与SSH公钥/私钥对关联的密码短语的环境变量的名称 。 |
用户名变量 | 将绑定到与SSH公钥/私钥对关联的用户名的环境变量的名称。 |
凭证 | 选择存储在Jenkins中的SSH公/私钥凭证。该字段的值是凭证ID,jenkins将其写入已生成的代码段。 |
证书 | 处理PKCS#12证书,您可以从中指定: |
密钥库变量 | 将绑定到这些凭据的环境变量的名称。Jenkins实际上将此临时变量分配给证书认证过程中所需的证书密钥库的安全位置。 |
密码变量 | 将绑定到与证书关联的密码的环境变量的名称。 |
别名变量 | 将绑定到与证书关联的唯一别名的环境变量的名称。 |
凭证 | 选择存储在Jenkins中的凭证凭证。该字段的值是凭证ID,jenkins将其写入已生成的代码段。 |
Docker客户端证书 | 处理Docker主机证书身份验证。 |
使用凭证
- credentials helper方法只支持Secret text、Username with password、Secretfile三种凭证。
- credentialsId()支持ssh凭据、docker凭据等。
- 使用Jenkins的代码段生成器功能,可以通过Jenkins的经典UI进行访问。
已访问gitlab仓库为例,如果凭证配置的username password 模式,就需要在environment中使用credentials()如果是SSH认证方式就可以在stage里使用credentialsId()
credentials helper方法
秘密文本
environment {
AWS_ACCESS_KEY_ID = credentials('jenkins-aws-secret-key-id')
AWS_SECRET_ACCESS_KEY = credentials('jenkins-aws-secret-access-key')
}
用户密码
environment {
BITBUCKET_COMMON_CREDS = credentials('jenkins-bitbucket-common-creds')
}
秘密文件
environment {
// The MY_KUBECONFIG environment variable will be assigned
// the value of a temporary file. For example:
// /home/user/.jenkins/workspace/cred_test@tmp/secretFiles/546a5cf3-9b56-4165-a0fd-19e2afe6b31f/kubeconfig.txt
MY_KUBECONFIG = credentials('my-kubeconfig')
}
credentialsId()
stages{
stage("Git clone"){
steps {
//拉取front代码
echo '正在拉取代码...'
dir("projdir/front"){
git credentialsId: '10e76a46-7872-4266-9e32-e0dbcb7df1c2', url: 'http://10.60.1.90/front.git',branch:'dev',changelog:true
}
//拉取middle代码
dir("projdir/middle"){
git credentialsId: '10e76a46-7872-4266-9e32-e0dbcb7df1c2', url: 'http://10.60.1.90/middle.git',branch:'dev',changelog:true
}
}
}
合并凭证
使用代码段生成器,可以使用withCredentials( … ) { … }
通过执行以下操作在一个步骤中提供多个凭据:
- 在Jenkins主页(即Jenkins经典UI的仪表板)中,单击您的Pipeline项目/项目的名称。
- 在左侧,单击“ 管道语法”,并确保“ 代码段生成器” 链接在左上角为粗体。(如果没有,请单击其链接。)
- 在“ 样本步骤”字段中,选择withCredentials:将凭证绑定到变量。
- 单击绑定下的添加。
withCredentials( … ) { … }
从下拉列表中选择要添加到步骤的凭据类型。- 指定凭证绑定详细信息。
- 对每个(一组)凭据重复单击``单击添加 ...''(上方)以添加到
withCredentials( … ) { … }
步骤。 - 单击生成管道脚本以生成最后
withCredentials( … ) { … }
代码段。
示例
五、post 钩子
post 步骤在Jenkins pipeline语法中是可选的,包含的是整个pipeline或阶段完成后一些附加的步骤。
比如我们希望整个pipeline执行完成之后或pipeline的某个stage执行成功后发生一封邮件,就可以使用post,可
理解为”钩子“
pipeline {
agent any
stages {
stage('Test') {
steps {
sh 'make check'
}
}
}
post {
always {
script{
if (currentBuild.currentResult == "ABORTED" || currentBuild.currentResult == "FAILURE" || currentBuild.currentResult == "UNSTABLE" ){
slackSend channel: "#机器人", message: "Build failure: ${env.JOB_NAME} -- No: ${env.BUILD_NUMBER}, please check detail in email!"
} else {
slackSend channel: "#机器人", message: "Build Success: ${env.JOB_NAME} -- Build No: ${env.BUILD_NUMBER}, please check on http://www.yourwebsite.com"
}
}
}
failure {
mail to: team@example.com, subject: 'The Pipeline failed :('
}
}
}
根据 pipeline 或阶段的完成状态,post 部分分成多种条件块,包括:
-
always: 无论pipeline或者stage的执行结果如何,此块中的预置操作都会执行。
-
changed:只有当pipeline或者stage的执行后,当前状态与之前发生了改变时,此块中的预置操作才会执行。
-
fixed:前一次运行为不稳定状态或者失败状态,而且本次运行成功结束,这两个条件同时满足时,此块中的预置操作才会执行。
-
regression: 本次运行状态为不稳定状态,失败状态或者是中止状态,而且前一次运行成功结束,这两个条件同时满足时,此块中的预置操作才会执行。
-
aborted:当前pipeline或者stage的状态为aborted时,此块中的预置操作才会执行。通常是由于流水线被手工中会导致此状态产生,而产生此状态后,通常在Jenkins的UI界面会显示为灰色。
-
failure:当前pipeline或者stage的状态为failed时,此块中的预置操作才会执行。而产生此状态后,通常在Jenkins的UI界面会显示为红色。
-
success:当前pipeline或者stage的状态为success时,此块中的预置操作才会执行。而产生此状态后,通常在Jenkins的UI界面会显示为绿色。
-
unstable: 当前pipeline或者stage的状态为unstable时,此块中的预置操作才会执行。通常情况下测试失败或者代码规约的违反都会导致此状态产生,而产生此状态后,通常在Jenkins的UI界面会显示为黄色。
-
unsuccessful:当前pipeline或者stage的状态不是success时,此块中的预置操作才会执行。
-
cleanup:无论pipeline或者stage的状态为何种状态,在post中的其他的条件预置操作执行之后,此块中的预置操作就会执行。
六、使用多个代理
agent lable可以使用不同的jenkins代理来执行构建,多用在跨平台的测试。如下:
构建结果将在“测试”阶段期间在两个后续代理(分别标记为“ linux”和“ windows”)上重用。
Jenkinsfile(声明性管道)
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'
}
}
}
}
}
七、简写
管道遵循Groovy语言约定,允许在方法参数周围省略括号。语法[key1: value1, key2: value2]
git([url: 'git://example.com/amazing-project.git', branch: 'master'])
简写 git url: 'git://example.com/amazing-project.git', branch: 'master'
为方便起见,当调用仅采用一个参数(或仅采用一个强制性参数)的步骤时,可以省略参数名称,例如
sh 'echo hello' /* short form */
sh([script: 'echo hello']) /* long form */