备注:由于我不是专职的devops工程师,所以学习jenkins本着够用的原则即可。但作为一个高级软件工程师,学会写pipeline是必须的。
pipeline翻译成流水线,在Unix/Linux系统中经常用到,Pipeline将一个命令/程序/进程的输出发送到另一个命令/程序/进程,以进行进一步处理。比如:cat test.txt | grep test1。Jenkins 中的Pipeline借用了Unix/Linux中的 Pipeline思路,实现像流水线一样来调度Jenkins任务,通过Jenkinsfile来描述整个持续集成流程。
Jenkinsfile就是描述pipeline的脚本文件。
pipeline支持两种语法:声明式Declarative和脚本式,声明式比较简单,也基本满足我们的需求,所以非专业人事建议学习声明式语法即可。
Scripted pipeline - 脚本式流水线语法,基于 Groovy语言构建的通用 DSL(Domain-specific language,领域特定语言)
Declarative pipeline - 声明式流水线语法,在v2.5之后引入,支持结构化方式,提供了更丰富的语法特性。
声明式语法包括以下核心流程:
1.pipeline : 声明其内容为一个声明式的 pipeline 脚本
2.agent: 执行节点(job 运行的 slave 或者 master 节点)
3.stages: 阶段集合,包裹所有的阶段(例如:编译,打包,部署等各个阶段)
4.stage: 阶段,被 stages 包裹,一个 stages 可以有多个 stage,但至少要有一个
5.steps: 步骤,为每个阶段的最小执行单元,被 stage 包裹
6.post: 执行构建后的操作,根据构建结果来执行对应的操作
一个最基本的声明式 pipeline框架如下:
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building..'
}
}
stage('Test') {
steps {
echo 'Testing..'
}
}
stage('Deploy') {
steps {
echo 'Deploying....'
}
}
}
}
声明式流水线语法必须包含在一个 pipeline块内:
pipeline {
/* Declarative Pipeline */
}
pipeline块中主要由Sections, Directives, Steps, 或者赋值语句组成。
Sections
Sections包括agent、stages、steps和post。
agent
agent定义 pipeline执行节点。agent定义在顶层pipeline下叫全局agent。也可以为stage指定agent。
主要参数:
- any:可以在任意可用的 agent上执行pipeline
- none:pipeline将不分配全局agent,每个 stage必须分配自己的agent
- label:指定运行节点agent的 Label
agent { label 'my-defined-label' }
label支持条件语法:agent { label 'my-label1 && my-label2' } or agent { label 'my-label1 || my-label2' }
这个label要来自jenkins的配置,例如公司里有很多台服务器,我们可以给服务器贴标签,用指定的服务器干指定的事。
点击左下角执行器状态可以对执行器进行配置:
有比较多的有用配置,可以配置服务器有多少个执行器,服务器的label,添加环境变量等。
- node:自定义运行节点配置,
- 指定 label
- 指定 customWorkspace
- docker:使用给定的容器执行流水线。
agent {
docker {
image 'maven:3.8.1-adoptopenjdk-11'
label 'my-defined-label'
args '-v /tmp:/tmp'
}
}
agent {
docker {
image 'myregistry.com/node'
label 'my-defined-label'
registryUrl 'https://myregistry.com/'
registryCredentialsId 'myPredefinedCredentialsInJenkins'
}
}
- dockerfile:使用源码库中包含的Dockerfile构建的容器来执行Pipeline。
比较少用,因为每次都要构建docker有点浪费时间。 - kubernetes:在kubernetes集群执行Pipeline
上述参数也可以用于stage中。
示例脚本:
pipline {
agent {
node {
label "myslave"
customWorkspace "myWorkspace"
}
}
}
为stage指定agent示例:
pipeline {
agent none
stages {
stage('Example Build') {
agent { docker 'maven:3.8.1-adoptopenjdk-11' }
steps {
echo 'Hello, Maven'
sh 'mvn --version'
}
}
stage('Example Test') {
agent { docker 'openjdk:8-jre' }
steps {
echo 'Hello, JDK'
sh 'java -version'
}
}
}
}
stages
包含一个或多个 stage, Pipeline的大部分工作在此执行。stages也是必须指定的指令,没有参数。此外,每个 pipeline块中必须只有一个 stages。
stages里至少要有一个stage,
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"
}
}
}
}
}
}
jenkins的插件提供了许多有用的steps,查阅https://www.jenkins.io/doc/pipeline/steps/,我们就常写的steps就是执行shell命令,
可以使用sh 'shell语句'
的方式。
例如我们要执行编译:sh 'make'
post
post是在Pipeline或者 stage执行结束后的操作,不是必须出现的指令。
也就是说,post可以放在pipeline里,那么会在整个pipeline结束后运行;放在特定的stage里,就会在该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'
}
}
}
典型pipeline框架参考
一个基本的CI流程:
下面这个pipeline能满足绝大数场景需求了:
pipeline {
agent any
stages {
stage('Build') {
steps {
//
}
}
stage('Test') {
steps {
//
}
}
stage('Deploy') {
steps {
//
}
}
}
post {
success {
}
failure{
}
}
}
参考:https://www.jenkins.io/doc/book/pipeline/syntax/