Pipeline as Code是Jenkins 2.0版本的精华所在,是帮助Jenkins实现从CI到CD华丽转身的关键工具。node
所谓Pipeline,简单来讲,就是一套运行于Jenkins上的工做流框架,将本来独立运行于单个或者多个节点的任务链接起来,实现单个任务难以完成的复杂发布流程android
Pipeline的实现方式是一套Groovy DSL(相似Gradle),任何发布流程均可以表述为一段Groovy脚本,而且Jenkins支持从代码库直接读取脚本,从而实现了Pipeline as Code的理念。git
注: 本文首发于 My 公众号 CodeSheep ,可 长按 或 扫描 下面的 当心心 来订阅 ↓ ↓ ↓github
这里主要结合我本身对传统Jenkins Job使用的一些痛点来讲:docker
传统的Jenkins Job难以灵活高效地并行(Job间、节点间、任务间、甚至任务内四个维度的并行)shell
传统的Jenkins Job日益失控的趋势让咱们措手不及,Job太多,CI脚本太离散,维护成本实在过高了,并且很危险,一单Jenkins Server挂了,一切都Game Over了编程
新拉分支的分支代码CI部署太麻烦了c#
传统的Jenkins Job显示真的是不太直观啊windows
我想这些理由应该足以让咱们把目光转向Jenkins2.0的Pipeline!bash
Pipeline的功能和优势:
Pipeline为用户设计了三个最最基本的概念:
一个典型的Stage View以下图所示:
从图中能够十分方便地看到哪些Stage经过,哪些Stage失败,以及构建的时间。
Jenkins2.0的Pipeline搭建使用的是Groovy脚本,经过Groovy脚本实现工做流管理的步骤以下:
实际上更经常使用的是MultiBranch Pipeline,上面的图中截图没有包含,但与普通Pipeline基本相似。
上图的实例脚本以下:
node {
stage('Checkout Code') { // for display purposes
// Get some code from a GitHub repository
git 'https://github.com/jglick/simple-maven-project-with-tests.git'
}
stage('Build') {
// Run the maven build
if (isUnix()) {
sh "'${MAVEN_HOME}/bin/mvn' -Dmaven.test.failure.ignore clean package"
} else {
bat(/"${MAVEN_HOME}\bin\mvn" -Dmaven.test.failure.ignore clean package/)
}
}
stage('Unit test') {
junit '**/target/surefire-reports/TEST-UT.xml'
archive 'target/*.jar'
}
}
复制代码
构建过程的stage View以下:
很明显能够看出,这里显示的和Groovy脚本中格式化的代码是一致的,会实时显示各个工做流的执行进度和结果,直观易懂。鼠标移上去,能看到日志信息的缩略图,单击能够调到对应stage的console中。
总而言之,一切都是那么地优雅!
在这里总结一下Pipeline中的关键DSL语法,利用Groovy对其进行组合能够完成任何一项复杂的CI/CD流程,熟悉它们大有裨益。
归档文件,举例:
archiveArtifacts 'target/*.jar'
复制代码
执行windows平台下的批处理文件,如
bat "call example.bat"
复制代码
触发构建一个jenkins job,如
build 'TEST_JOB'
复制代码
从SCM系统中checkout repo,如:
checkout([$class: 'SubversionSCM', additionalCredentials: [], excludedCommitMessages: '', excludedRegions: '', excludedRevprop: '', excludedUsers: '', filterChangelog: false, ignoreDirPropChanges: false, includedRegions: '', locations: [[credentialsId: '30e6c1e5-1035-4bdd-8a44-05ba8f885158', depthOption: 'infinity', ignoreExternalsOption: true, local: '.', remote: 'svn://xxxxxx']], workspaceUpdater: [$class: 'UpdateUpdater']])
复制代码
从workspace中删除当前目录
切换目录,如
dir('/home/jenkins') { // 切换到/home/jenkins目录中作一些事情
// some block
}
复制代码
打印信息,如 echo 'hello world'
利用Jenkins发送邮件,内容、主题全均可以自定义,如
emailext body: 'Subject_test', subject: 'Subject_test', to: 'hansonwang99@163.com.cn'
// 邮件的正文body,主题subject,收件人to等能够进行自定义
复制代码
抛出一个错误信号,能够自行在代码里抛出,如 error 'read_error'
检查工做空间某个路径里是否存在某个file,举例:
fileExists '/home/test.txt' // 检查是否存在test.txt
复制代码
等待外界用户的交互输入,举例:
input message: '', parameters: [string(defaultValue: '默认值', description: '版本号', name: 'version')] // 在某一步骤,等待用户输入version参数才能往下执行
复制代码
用于判断当前任务是否运行于Unix-like节点上,举例:
def flag = isUnix()
if( flag == false ) { // 能够据此进行判断
echo "not run on a unix node !"
}
复制代码
调用一个外部groovy脚本,举例:
load 'D:\\jenkins\\workspace\\test.groovy'
复制代码
分配节点给某个任务运行,举例:
node('节点标签') { // 在对应标签的节点上运行某项任务
Task()
}
复制代码
并行地执行任务,能够说是最实用高效的工具了,举例:
parallel( //并行地执行android unit tests和android e2e tests两个任务
'android unit tests': {
runCmdOnDockerImage(androidImageName, 'bash /app/ContainerShip/scripts/run-android-docker-unit-tests.sh', '--privileged --rm')
},
'android e2e tests': {
runCmdOnDockerImage(androidImageName, 'bash /app/ContainerShip/scripts/run-ci-e2e-tests.sh --android --js', '--rm')
}
)
复制代码
设置Job的属性,举例:
properties([parameters([string(defaultValue: '1.0.0', description: '版本号', name: 'VERSION')]), pipelineTriggers([])]) // 为job设置了一个VERSION参数
复制代码
pwd 显示当前目录
readFile
从工做空间中读取文件,举例:
def editionName = readFile '/home/Test/exam.txt'
复制代码
重复body内代码N次,举例:
retry(10) {
// some block
}
复制代码
执行shell脚本,如:sh "sh test.sh"
延时,如延时2小时:sleep time: 2, unit: 'HOURS'
建立任务的stage,举例:
stage('stage name') {
// some block
}
复制代码
存放文件为后续构建使用,举例:
dir('target') {
stash name: 'war', includes: 'x.war'
}
复制代码
将stash步骤中存放的文件在当前工做空间中重建,举例:
def deploy(id) {
unstash 'war'
sh "cp x.war /tmp/${id}.war"
}
复制代码
时间限制,举例
timeout(time: 4, unit: 'SECONDS') {
// some block
}
复制代码
用于在控制台加时间戳,举例:
timestamps {
// some block
}
复制代码
建立文件,举例:
touch file: 'TEST.txt', timestamp: 0
复制代码
解压文件,举例:
unzip dir: '/home/workspace', glob: '', zipFile: 'TEST.zip'
复制代码
检查给定的文件是否包含一个有效的Declarative Pipeline,返回T或者F
validateDeclarativePipeline '/home/wospace'
复制代码
等待,直到条件知足
waitUntil {
// some block
}
复制代码
使用凭据
withCredentials([usernameColonPassword(credentialsId: 'mylogin', variable: 'USERPASS')]) {
sh ''' set +x curl -u $USERPASS https://private.server/ > output '''
}
复制代码
设置环境变量,注意近本次运行有效!
withEnv(['MYTOOL_HOME=/usr/local/mytool']) {
sh '$MYTOOL_HOME/bin/start'
}
复制代码
写文件到某个路径
writeFile file: '/home/workspace', text: 'hello world'
复制代码
写JSON文件,用法基本同上
建立zip文件
zip dir: '/home/workspace', glob: '', zipFile: 'TEST.zip'
复制代码
自定义工做空间,在其中作一些工做,效果相似于Dir命令,举例:
ws('/home/jenkins_workspace') {
// some block
}
复制代码
做者更多的SpringBt实践文章在此:
若是有兴趣,也能够抽点时间看看做者一些关于容器化、微服务化方面的文章: