0. 背景
什么是pipeline?
pipeline称为部署流水线。
Jenkins 1.x只能通过界面来手动描述部署流水线。
Jenkins 2.x开始支持pipeline as code, 可以通过代码来描述部署流水线。
pipeline as code的意义在于:
更好的版本化
将pipeline提交到版本库中进行版本控制。更好的协作
pipeline的每个修改对团队成员可见, 另外还可以对pipeline进行代码审核。更好的重用性
pipeline代码可以重用。
2. Jenkinsfile和pipeline语法
Jenkinsfile是什么?
Jenkinsfile是一个文本文件。
它是部署流水线在Jenkins中的表现形式, 所有部署流水线的逻辑都卸载Jenkinsfile中。
它存在的意义就像dockerfile对于Docker的意义。
Jenkins默认是不支持Jenkinsfile的,我们需要安装pipeline插件。
pipeline语法的选择
Groovy脚本语言被作为pipeline的默认语言。
脚本中每个步骤我们称之为stage
一个基本的基于groovy语法的pipeline骨架如下:
pipeline {
agent any
stages {
stage("Build") {
// 构建
steps {
echo("Building Start...")
}
}
stage("Test") {
// 测试
steps {
echo("Testing Start...")
}
}
stage("Deploy") {
// 部署
steps {
echo("Deploy Start...")
}
}
}
}
3. 创建第一个pipeline
1. 在首页创建项目时选择pipeline
2. 从版本控制库拉取pipeline
2-1) 安装git插件
2-2) 将git私钥放到Jenkins上
Jenkins->Creentials->System->Global credentials
选择Kind为"SSH Username with private key"
2-3) 将Jenkinsfile推送到gitlab
2-4) Pipeline节点下的Destination选择"Pipeline script from SCM", SCM中选择Git,
Credentials中选择刚刚创建好的凭证
3. 用Maven来构建Java Application
3-1) 安装JDK和Maven
Manage Jenkins->Global Tool Configuration->JDK
(可以选择外部的jdk目录, 如果是docker方式安装的jenkins一定要记得挂载外部jdk目录)
Manage Jenkins->Global Tool Configuration->Maven
(可以选择外部的maven目录, 如果是docker方式安装的jenkins一定要记得挂载外部maven目录)
maven构建应用示例代码, 如下:
pipeline {
agent any
tools {
maven 'maven '3.6.3''
}
stages {
stage("Build") {
// Maven构建
steps {
script {
dir("$SOME_DIR") {
sh("mvn clean package -DskipTests=true")
echo("Package xxx done")
}
}
}
}
}
}
4. 基本Groovy语法
- Groovy支持静态和动态类型
定义变量时, 我们还是习惯使用def
eg:
def a = 0
-
Groovy语句不需要用分号结尾
Groovy中方法调用可以省略括号
print "Hello World"
- 支持命名参数
def testMethod(String arg1, String arg2) {
return arg1 + "_" + arg2
}
// call the method
testMethod arg2 = "B", arg1 = "A"
// return result
A_B
- 支持默认参数
def printName(String name = "default name") {
print "name is: ${name}"
}
// call method
printName()
// return result
name is: default name
- 同时支持双引号和单引号
要注意的是: 双引号支持占位符插值,单引号不支持。
如下代码:
def name = 'world'
print "hello ${name}" // hello world
print 'hello ${name}' // hello ${name}
- 支持三引号
三单引号和三双引号都支持换行
但是只有三双引号支持换行
代码如下:
def name = "Tom"
def tempStr = """
Today is a good day.
${name} plans to go to the park.
He wants to have a good rest.
"""
- 支持闭包
闭包可以作为参数传递给另一个方法
代码如下:
// 定义闭包
def codeBlock = { print "Hello Closure" }
def stage(String name, closure) {
println name
closure()
}
// 调用
stage("stage name", codeBlock)
// return result
stage name
Hello Closure
// Groovy的另一种简洁写法
stage("stage name") {
print "Hello Closure"
}
5. pipeline的组成和指令
pipeline的组成
关键字 | 含义 |
---|---|
pipeline | 整条流水线的逻辑 |
stage | 流水线的阶段 |
steps | 每个阶段的具体步骤 |
agent | 指定流水线的执行位置(eg: 物理机/虚拟机/Docker容器) |
post | pipeline执行失败后通过failure部分发送邮件到指定邮箱 |
6. 如何在pipeline中编写脚本
直接在steps块中编写Groovy代码是不可以的(eg: if-else),会出错。
Jenkins pipeline专门提供了一个script步骤, 可以再script步骤中像写代码一样编写pipeline逻辑。
例子代码如下:
pipeline {
agent any
stages {
stage("Demo") {
steps {
script {
def browers = ['chrome', 'firefox']
for (int i = 0; i < browers.size(); i++) {
echo "Using the ${browsers[i]} browser"
}
}
}
}
}
}
pipeline内置基础步骤
-
deleteDir
删除当前目录, 通常与dir一起使用。
dir
切换到目录
(默认pipeline在工作空间目录下,dir可以切换到其它目录。)
dir("/myapp") {
...
}
-
fileExists
判断文件是否存在,返回布尔类型。
-
pwd
返回当前目录(同Linux的pwd命令)。
writeFile
将内容写入指定文件。
参数列表:
file: 文件路径
text: 写入的内容
encoding(optional): 目标文件的编码(eg: Base64)
- readFile
读取文件的内容。
参数列表:
file: 文件路径
encoding(option): 读取文件的编码(eg: Base64)
- stash
将一些文件保存起来,以便同一次构建的其它步骤或阶段使用。
stash(name: "test", includes: "test.txt")
- unstash
取出之前stash的文件。
unstash("test")
命令相关步骤
- sh
执行shell命令。
参数名 | 含义 |
---|---|
script | 执行的shell脚本 |
encoding | 输出日志的编码 |
returnStatus | 脚本返回的状态码 |
returnStdout | true返回任务的标准输出 |
其它步骤
- error
主动报错,终止当前pipeline。
error("error occurs")
- tool
使用预定义的工具。
参数名 | 含义
---- | ----
name | 工具名称
type(optional) | 工具安装类的全路径类名
def t = tool name: 'docker', type: 'org.jenkinssci.plugins.docker.commons.tools.DockerTool'
- timeout
代码块超时时间。
参数名 | 含义
---- | ----
time | 超时时间
unit(optional) | 时间单位 默认minutes 其它有milliseconds, seconds, hours, days
activity(optional) | true 当日志没有活动后,才算真正超时
timeout(10)
-
waitUntil
不断重复代码,直到条件满足。
retry
重复执行块。
// 重复10次
retry(10) {
...
}
- sleep
让pipeline休眠一段时间。
默认是秒。
// 休眠120秒
sleep(120)
// 休眠2分钟
sleep(time: '2', unit: 'MINUTES')