jenkins部署及使用

Jenkins 简介

Jenkins 是一款自动化的任务执行工具。通常用于持续集成/持续交付领域。

可以通过界面或 Jenkinsfile 告诉 Jenkins 执行什么任务, 何时执行。理论上, 我们可以让它执行任何任务, 但是通常只应用于持续集成和持续交付。

Jenkinsfile 是一个文本文件, 是部署 pipeline 概念在 Jenkins 中的表现形式。 和 Docker 的 Dockerfile 类似, 所有部署 pipeline 的逻辑都写在 Jenkinsfile 中。

安装部署

jdk

版本

jdk1.8.0_212

也可用新版本

jdk 下载地址

jenkins

Ubuntu 安装

Ubuntu 版本: Ubuntu 18.04.2 LTS

裸机安装

1
2
3
4
wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add -
sudo sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
sudo apt-get update
sudo apt-get install jenkins

更改/etc/init.d/jenkins中配置:

  1. $HTTP_PORT 后面端口为想要的端口, 如: 8800
  2. PATH 中加上本机 java 所在目录, 如: /usr/local/java/jdk1.8.0_212/bin

更改/etc/default/jenkins中设置:

  1. JAVA_ARGS=”-Djava.awt.headless=true -Xmx512m”, 作用是限制 jenkins 内存, 只是本机构建, 512m 就够用了
  2. HTTP_PORT=8800 修改 http 端口

其他默认即可

首次启动选择默认 jenkins 插件即可, 其他跟着一步一步操作即可

用到 maven 或者其他构建工具, 需要在全局工具配置中进行配置

使用

简单构建项目

一般来说选择构建一个自由风格的软件项目这一条就好, 其他后需要的请在官网查看

  1. General, 根据需要选择构建信息, 如果选择参数化构建过程, 参数的名称在下面能够用到
  2. 源码管理, 根据需要选择对应的代码管理, git 或者 svn
  3. 构建触发器, 自行选择
  4. 构建环境, 一般情况用不到, 可以根据项目需求选用
  5. 构建, 可以进行 maven 构建、shell 执行等等

注意事项

  1. 部署应用之后如果应用刚起来就被 jenkins 杀掉, 则需要在启动前加 BUILD_ID=project 这一行, project 替换为自己的项目名
    如: 构建好 java 应用, 然后在构建那一栏增加执行 shell, 把构建好的 Java 应用部署到指定目录, 然后用命令启动该程序, 在启动该程序前需要加入该语句
    代码示例:
1
2
3
4
5
6
7
echo "pwd: "`pwd`
cd ./target
echo "pwd: "`pwd`
tar -xzvf project-deploy.tar.gz

BUILD_ID=project
bash ./project/bin/deploy.sh ${deploy_path} ${run_mode}

上面的deploy.sh脚本自己根据需要自行编写, deploy_pathrun_modeGeneral步骤中的参数名称

除了 BUILD_ID 还有其他的可用的环境变量, 构建步骤中的执行 shell下面可以查看比较全的变量, 也可以在官网看可以使用的环境变量

pipeline 构建项目

pipeline 介绍

Jenkins 默认不支持 pipeline, 需要安装 pipeline 插件。

pipeline 主要是指代码的自动构建、测试、打包和部署等过程。

Jenkins 1.x 只能通过界面手动操作来“描述”部署 pipeline。Jenkins 2.x 支持 pipeline as code, 可以通过“代码”来描述部署 pipeline。

pipeline 优点

  1. Code(代码): Pipeline 的任务是通过代码来实现的, 可以通过 git 来进行版本化控制, 团队成员可以编辑迭代 Pipeline 代码
  2. Durable(持久化): 无论 Jenkins master 是在计划内或者非计划内重启, pipeline 任务都不会收到影响
  3. Pausable(可暂定性): pipeline 基于 groovy 可以实现 job 的暂停和等待用户的输入或批准然后继续执行。
  4. Versatile(多功能): 支持 fork/join、循环执行, 并行执行任务
  5. Extensible(可扩展性): 支持其 DSL 的自定义扩展 , 以及与其他插件集成的多个选项

pipeline 语法支持和比较

pipeline 支持以下两种语法:

  1. Groovy 语法(node 为根节点的是脚本式语法)
  2. 声明式语法(2.5 版本开始支持, pipeline 为根节点的是声明式语法, 推荐使用)

pipeline 语法比较

当 Jenkins pipeline 第一次构建时, Groovy 被选为基础。 Jenkins 长期使用嵌入式 Groovy 引擎来为管理员和用户提供 高级脚本功能。另外, Jenkins pipeline 的实现者发现 Groovy 是 构建现在成为 “脚本化 pipeline” DSL 的坚实基础。

由于它是一个功能齐全的编程环境, 脚本化 pipeline 为 Jenkins 用户提供了大量的灵活性性和可扩展性。 Groovy 学习曲线通常不适合给定团队的所有成员, 因此创造了声明式 pipeline 来为编写 Jenkins pipeline 提供一种更简单、更有主见的语法。

两者本质上是相同的 pipeline 子系统。 在底层, 它们都是 “pipeline 即代码” 的持久实现, 它们都能够使用构建到 pipeline 中或插件提供的步骤, 它们都能够使用 共享库

但是它们的区别在于语法和灵活性。 声明式限制了用户使用更严格和预定义的结构, 使其成为更简单的持续交付 pipeline 的理想选择。 脚本化提供了很少的限制, 以至于对脚本和语法的唯一限制往往是由 Groovy 子集本身定义的, 而不是任何特定于 pipeline 的系统, 这使他成为权利用户和那些有更复杂需求的人的理想选择。 顾名思义, 声明式 pipeline 鼓励 声明式编程模型。 而脚本化 pipeline 遵循一个更命令式的编程模型

步骤(steps)

pipeline 最基础的部分是”步骤”。从根本上说, 步骤告诉 Jenkins 要做什么, 并作为声明式和脚本化 pipeline 语法的基本构建块

对于可用步骤的概述, 请参考 pipeline steps 列表, 它包含了 pipeline 的步骤和插件提供的步骤的完整列表

Groovy 语法

这里 Groovy 语法不是重点, 但是还是需要了解必要的知识。如果想要详细了解, 可以参考 Groovy 教程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 一般用def定义变量
// 语句末尾不添加分号
def x = "abs"

// Groovy中的方法调用可以省略括号
println x
println "test"

// 支持命名参数
def m1(String givenName, String familyName) {
return givenName + " " + familyName
}
// 调用时可以这样
println m1("aaa", "bbb")
s1 = m1 familyName = "xxx", givenName = "yyy"
println s1

// 支持默认参数
def m2(String name = "hi") {
return name
}
// 括号不能省略
println m2()
println m2("aaa")

// 支持单引号、双引号。双引号支持插值, 单引号不支持
println '------支持单引号、双引号。双引号支持插值, 单引号不支持 ---------'
println ''
def name = "world";
println "hello ${name}"
println 'hello ${name}'


// 支持三引号。三引号分为三单引号和三双引号。它们都支持换行, 区别在于只有三双引号支持插值。
println ''
println '-----支持三引号。三引号分为三单引号和三双引号。它们都支持换行, 区别在于只有三双引号支持插值。-----'
println """line one
line two
line three
${name}
"""

println '''line one
line two
line three
${name}
'''

// 支持闭包
println '-------支持闭包---------'
def codeBlock = { println "hello closure" }
// 闭包可以被当成函数直接调用
codeBlock();
// 闭包可以被当成一个参数传递给另外一个方法
def pipeline(closure){
closure()
}
pipeline(codeBlock)

def stage(String name, closure){
println name
closure()
}
stage("jenkins", codeBlock)

脚本化 pipeline

脚本化 pipeline, 与声明式一样的是, 是建立在底层 pipeline 的子系统上的

与声明式不同的是, 脚本化 pipeline 实际上是由 Groovy 构建的通用 DSL

Groovy 语言提供的大部分功能都可以用于脚本化 pipeline 的用户。这意味着它是一个非常有表现力和灵活的工具, 可以通过它编写持续交付 pipeline

流控制

脚本化 pipeline 从 Jenkinsfile 的顶部开始向下串行执行, 就像 Groovy 或其他语言中的大多数传统脚本一样。 因此, 提供流控制取决于 Groovy 表达式, 比如 if/else 条件, 例如:

1
2
3
4
5
6
7
8
9
node {
stage('Example') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}

另一种方法是使用 Groovy 的异常处理支持来管理脚本化 pipeline 流控制。当 steps 失败 , 无论什么原因, 它们都会抛出一个异常。处理错误的行为必须使用 Groovy 中的 try/catch/finally 块 , 例如:

1
2
3
4
5
6
7
8
9
10
11
node {
stage('Example') {
try {
sh 'exit 1'
}
catch (exc) {
echo 'Something failed, I should sound the klaxons!'
throw
}
}
}

steps

脚本化 pipeline引入任何特定于其语法的步骤; pipeline steps 列表 包括 pipeline 和插件提供的步骤的完整列表

区别普通 Groovy

为了提供 durability, 这意味着运行 pipeline 可以在 Jenkins master 重启后继续运行, 脚本化的 pipeline 序列化数据到主服务器。

由于这个设计需求, 一些 Groovy 习惯用语, 比如 collection.each { item -> /* perform operation */ } 都不完全支持。

详情参见 JENKINS-27421JENKINS-26481

声明式 pipeline

声明式 pipeline 是 版本 2.5 之后添加到 Jenkins pipeline 的, 它在 pipeline 子系统之上提供了一种更简单, 更有主见的语法。

所有有效的声明式 pipeline 必须包含在一个 pipeline 块中:

1
2
3
pipeline {
/* insert Declarative Pipeline here */
}

在声明式 pipeline 中有效的基本语句和表达式遵循与 Groovy 的语法同样的规则, 有以下例外:

  1. pipeline 顶层必须是一个 block, 特别地: pipeline { }
  2. 没有分号作为语句分隔符, 每条语句都必须在自己的行上
  3. 块只能由 节段(Sections), 指令(Directives), 步骤(Steps), 或赋值语句组成
  4. 属性引用语句被视为无参方法调用。 例如, input 被视为 input()

局限性

当前存在一个未解决的问题, 它限制了 pipeline{} 块中代码的最大大小。此限制不适用于脚本化 pipeline。

pipeline 组成

pipeline 只能由 节段(Sections), 指令(Directives), 步骤(Steps), 或赋值语句组成

一个基本的 pipeline 结构:

1
2
3
4
5
6
7
8
9
10
11
pipeline {
agent any

stages {
stage('Hello') {
steps {
echo 'Hello World'
}
}
}
}
  1. pipeline: 代表整条流水线, 包含整条流水线的逻辑。
  2. agent 部分: 指定流水线的执行位置(Jenkins agent)。流水线中的每个阶段都必须在某个地方(物理机、虚拟机或 Docker 容器)执行, agent 部分即指定具体在哪里执行, 默认 any。
  3. stages 部分: 流水线中多个 stage 的容器。stages 部分至少包含一个 stage。
  4. stage 部分: 阶段, 代表流水线的阶段。每个阶段都必须有名称。本例中, Hello 就是此阶段的名称。
  5. steps 部分: 代表阶段中的一个或多个具体步骤(step)的容器。steps 部分至少包含一个步骤, 本例中, echo 就是一个步骤。在一个 stage 中有且只有一个 steps。

jenkins-pipeline结构

节段(Sections)

声明式 pipeline 中的节段通常包含一个或多个 指令(Directives) 或 步骤(Steps)。

agent

Required Yes
Allowed In the top-level pipeline block and each stage block.

agent 部分指定了整个 pipeline特定的部分, 将会在 Jenkins 环境中执行的位置, 这取决于 agent 区域的位置。该部分必须在 pipeline 块的顶层被定义, 但是 stage 级别的使用是可选的。

为了支持各种各样的用例 pipeline, agent 部分支持一些不同类型的参数。这些参数应用在 pipeline 块的顶层, 或 stage 指令内部。

any

在任何可用的代理上执行 pipeline 或阶段。例如: agent any

none

当在 pipeline 块的顶部没有全局代理, 该参数将会被分配到整个 pipeline 的运行中并且每个 stage 部分都需要包含他自己的 agent 部分。比如: agent none

label

在提供了标签的 Jenkins 环境中可用的代理上执行 pipeline 或阶段。 例如: agent { label 'my-defined-label' }

node

agent { node { label 'labelName' } }agent { label 'labelName' } 一样, 但是 node 允许额外的选项 (比如 customWorkspace )。

docker

使用给定的容器执行 pipeline 或 stage。该容器将在预置的 node 上, 或在匹配可选定义的 label 参数上, 动态的供应来接受基于 Docker 的 pipeline。docker 也可以选择的接受 args 参数, 该参数可能包含直接传递 到 docker run 调用的参数, 以及 alwaysPull 选项, 该选项强制 docker pull , 即使镜像名称已经存在。 比如: agent { docker 'maven:3-alpine' } 或:

1
2
3
4
5
6
7
agent {
docker {
image 'maven:3-alpine'
label 'my-defined-label'
args '-v /tmp:/tmp'
}
}
dockerfile

执行 pipeline 或 stage, 使用从源代码库包含的 Dockerfile 构建的容器。为了使用该选项, Jenkinsfile 必须从多个分支 pipeline 中加载, 或者加载 “Pipeline from SCM.” 通常, 这是源代码仓库的根目录下的 Dockerfile : agent { dockerfile true }. 如果在另一个目录下构建 Dockerfile , 使用 dir 选项: agent { dockerfile {dir 'someSubDir' } }。如果 Dockerfile 有另一个名称, 你可以使用 filename 选项指定该文件名。你可以传递额外的参数到 docker build ... 使用 additionalBuildArgs 选项提交, 比如 agent { dockerfile {additionalBuildArgs '--build-arg foo=bar' } }。 例如, 一个带有 build/Dockerfile.build 的仓库, 期望一个构建参数 version:

1
2
3
4
5
6
7
8
9
agent {
// Equivalent to "docker build -f Dockerfile.build --build-arg version=1.0.2 ./build/
dockerfile {
filename 'Dockerfile.build'
dir 'build'
label 'my-defined-label'
additionalBuildArgs '--build-arg version=1.0.2'
}
}
kubernetes

详见官网英文文档

post

Required No
Allowed In the top-level pipeline block and each stage block.

post 部分定义一个或多个 steps, 这些阶段根据 pipeline 或阶段的完成情况而 运行(取决于 pipeline 中 post 部分的位置). post 支持以下 post-condition 块中的其中之一: always, changed, failure, success, unstable, 和 aborted 。这些条件块允许在 post 部分的步骤的执行取决于 pipeline 或阶段的完成状态。

always

无论 pipeline 或阶段的完成状态如何, 都允许在 post 部分运行该步骤。

changed

只有当前 pipeline 或阶段的完成状态与它之前的运行不同时, 才允许在 post 部分运行该步骤。

fixed

上一次完成状态为失败或不稳定(unstable), 当前完成状态为成功时执行。

regression

上一次完成状态为成功, 当前完成状态为失败、不稳定或中止(aborted)时执行。

aborted

只有当前 pipeline 或阶段的完成状态为”aborted”, 才允许在 post 部分运行该步骤, 通常由于 pipeline 被手动的 aborted。通常 web UI 是灰色。

failure

只有当前 pipeline 或阶段的完成状态为”failure”, 才允许在 post 部分运行该步骤, 通常 web UI 是红色。

success

只有当前 pipeline 或阶段的完成状态为”success”, 才允许在 post 部分运行该步骤, 通常 web UI 是蓝色或绿色。

unstable

只有当前 pipeline 或阶段的完成状态为”unstable”, 才允许在 post 部分运行该步骤, 通常由于测试失败,代码违规等造成。通常 web UI 是黄色。

cleanup

清理条件块。不论当前完成状态是什么, 在其他所有条件块执行完成后都执行。post 部分可以同时包含多种条件块。

示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
post {
always {
echo 'stage post always'
}
}
}
}
// 按照惯例, post 部分应该放在 pipeline 的底部。
post {
// Post-condition 块包含与 steps 部分相同的steps
always {
echo 'I will always say Hello again!'
}
success {
echo 'pipeline post success'
}
}
}
stages

Required Yes
Allowed Only once, inside the pipeline block.

包含一系列一个或多个 stage 指令, stages 部分是 pipeline 描述的大部分”work” 的位置。 建议 stages 至少包含一个 stage 指令用于连续交付过程的每个离散部分, 比如构建, 测试, 和部署。

1
2
3
4
5
6
7
8
9
10
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
steps

Required Yes
Allowed Inside each stage block.

steps 部分在给定的 stage 指令中执行的定义了一系列的一个或多个步骤

pipeline steps 列表

1
2
3
4
5
6
7
8
9
10
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}

指令(Directives)

environment

Required No
Allowed Inside the pipeline block, or within stage directives.

environment 指令制定一个 键-值 对序列, 该序列将被定义为所有步骤的环境变量, 或者是特定于阶段的步骤, 这取决于 environment 指令在 pipeline 内的位置。

该指令支持一个特殊的助手方法 credentials() , 该方法可用于在 Jenkins 环境中通过标识符访问预定义的凭证。对于类型为 “Secret Text” 的凭证, credentials() 将确保指定的环境变量包含秘密文本内容。对于类型为 “SStandard username and password” 的凭证, 指定的环境变量指定为 username:password , 并且两个额外的环境变量将被自动定义: 分别为 MYVARNAME_USRMYVARNAME_PSW

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pipeline {
agent any
// 顶层pipeline块中使用的 environment 指令将适用于pipeline中的所有步骤
environment {
CC = 'clang'
}
stages {
stage('Example') {
// 在一个 stage 中定义的 environment 指令只会将给定的环境变量应用于 stage 中的步骤
environment {
// environment 块有一个 助手方法 credentials() 定义, 该方法可以在 Jenkins 环境中用于通过标识符访问预定义的凭证
AN_ACCESS_KEY = credentials('my-prefined-secret-text')
}
steps {
sh 'printenv'
}
}
}
}

Jenkins Pipeline 支持覆盖环境变量。

  1. 使用 withEnv([“env=value]) { }语句块可以覆盖任何环境变量。
  2. 使用 environment {}语句块设置的变量不能使用命令式 env.VAR = “value”赋值覆盖。
  3. 命令式 env.VAR = “value”分配只能覆盖使用命令式创建的环境变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
pipeline {
agent any

environment {
FOO = "bar"
NAME = "Joe"
}

stages {
stage("Env Variables") {
environment {
NAME = "Alan" // overrides pipeline level NAME env variable
BUILD_NUMBER = "2" // overrides the default BUILD_NUMBER
}

steps {
echo "FOO = ${env.FOO}" // prints "FOO = bar"
echo "NAME = ${env.NAME}" // prints "NAME = Alan"
echo "BUILD_NUMBER = ${env.BUILD_NUMBER}" // prints "BUILD_NUMBER = 2"

script {
env.SOMETHING = "1" // creates env.SOMETHING variable
}
}
}

stage("Override Variables") {
steps {
script {
env.FOO = "IT DOES NOT WORK!" // it can't override env.FOO declared at the pipeline (or stage) level
env.SOMETHING = "2" // it can override env variable created imperatively
}

echo "FOO = ${env.FOO}" // prints "FOO = bar"
echo "SOMETHING = ${env.SOMETHING}" // prints "SOMETHING = 2"

withEnv(["FOO=foobar"]) { // it can override any env variable
echo "FOO = ${env.FOO}" // prints "FOO = foobar"
}

withEnv(["BUILD_NUMBER=1"]) {
echo "BUILD_NUMBER = ${env.BUILD_NUMBER}" // prints "BUILD_NUMBER = 1"
}
}
}
}
}
options

Required No
Allowed Inside the pipeline block, or within stage directives.

options 指令允许从 pipeline 内部配置特定于 pipeline 的选项。 pipeline 提供了许多这样的选项, 比如 buildDiscarder, 但也可以由插件提供, 比如 timestamps.

buildDiscarder

为最近的 pipeline 运行的特定数量保存组件和控制台输出。例如: options { buildDiscarder(logRotator(numToKeepStr: '1')) }

disableConcurrentBuilds

不允许同时执行 pipeline。 可被用来防止同时访问共享资源等。 例如: options { disableConcurrentBuilds() }

overrideIndexTriggers

允许覆盖分支索引触发器的默认处理。 如果分支索引触发器在多分支或组织标签中禁用, options { overrideIndexTriggers(true) } 将仅启用它们来完成此作业。否则, options { overrideIndexTriggers(false) } 只会禁用改作业的分支索引触发器。

skipDefaultCheckout

agent 指令中, 跳过从源代码控制中检出代码的默认情况。例如: options { skipDefaultCheckout() }

skipStagesAfterUnstable

一旦构建状态变得 UNSTABLE, 跳过该阶段。例如: options { skipStagesAfterUnstable() }

checkoutToSubdirectory

在工作空间的子目录中自动地执行源代码控制检出。例如: options { checkoutToSubdirectory('foo') }

timeout

设置 pipeline 或阶段运行的超时时间, 在此之后, Jenkins 将中止 pipeline。例如: options { timeout(time: 1, unit: 'HOURS') }

retry

在失败时, 重新尝试整个 pipeline 或阶段的指定次数。 For example: options { retry(3) }

timestamps

为控制台输出增加时间戳。 例如: options { timestamps() }

示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pipeline {
agent any
options {
// 指定 2 小时的全局执行超时, 在此之后, Jenkins 将中止 pipeline 运行
timeout(time: 2, unit: 'HOURS')
}
stages {
stage('Example') {
// 指定 Example 阶段的执行超时时间, 在此之后, Jenkins 将中止 pipeline 运行
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
echo 'Hello World'
}
}
}
}
注意 stage 选项

stage 的 options 指令类似于 pipeline 根目录上的 options 指令。然而, stage 级别 options 可选的只能是跟 stage 相关的选项(skipDefaultCheckout, retry, timeout, timestamps 等)

在 stage, options 指令中的步骤在进入 agent 之前被调用或在 when 条件出现时进行检查

parameters

Required No
Allowed Only once, inside the pipeline block.

string

A parameter of a string type, for example: parameters { string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: '') }

text

A text parameter, which can contain multiple lines, for example: parameters { text(name: 'DEPLOY_TEXT', defaultValue: 'One\nTwo\nThree\n', description: '') }

booleanParam

A boolean parameter, for example: parameters { booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '') }

choice

A choice parameter, for example: parameters { choice(name: 'CHOICES', choices: ['one', 'two', 'three'], description: '') }

password

A password parameter, for example: parameters { password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'A secret password') }

示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
pipeline {
agent any
parameters {
string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')

text(name: 'BIOGRAPHY', defaultValue: '', description: 'Enter some information about the person')

booleanParam(name: 'TOGGLE', defaultValue: true, description: 'Toggle this value')

choice(name: 'CHOICE', choices: ['One', 'Two', 'Three'], description: 'Pick something')

password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'Enter a password')
}
stages {
stage('Example') {
steps {
echo "Hello ${params.PERSON}"

echo "Biography: ${params.BIOGRAPHY}"

echo "Toggle: ${params.TOGGLE}"

echo "Choice: ${params.CHOICE}"

echo "Password: ${params.PASSWORD}"
}
}
}
}
triggers

Required No
Allowed Only once, inside the pipeline block.

triggers 指令定义了 pipeline 被重新触发的自动化方法。对于集成了源( 比如 GitHub 或 BitBucket)的 pipeline, 可能不需要 triggers, 因为有些集成的网络钩子已经包含了触发器。 当前可用的触发器是 cron, pollSCMupstream

cron

接收 cron 样式的字符串来定义要重新触发 pipeline 的常规间隔 ,比如: triggers { cron('H */4 * * 1-5') }

pollSCM

接收 cron 样式的字符串来定义一个固定的间隔, 在这个间隔中, Jenkins 会检查新的源代码更新。如果存在更改, pipeline 就会被重新触发。例如: triggers { pollSCM('H */4 * * 1-5') }

只在 Jenkins 2.22 及以上版本中可用

upstream

接受逗号分隔的工作字符串和阈值。 当字符串中的任何作业以最小阈值结束时, pipeline 被重新触发。例如: triggers { upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS) }

示例
1
2
3
4
5
6
7
8
9
10
11
12
13
pipeline {
agent any
triggers {
cron('H */4 * * 1-5')
}
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
stage

Required At least one
Allowed Inside the stages section.

stage 指令在 stages 部分进行, 应该至少包含一个

pipeline 所做的所有实际工作都将封装进一个或多个 stage 指令中

1
2
3
4
5
6
7
8
9
10
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
tools

Required No
Allowed Inside the pipeline block or a stage directive.

自动安装工具并设置 PATH

如果 agent 设置为 none, 即 agent none 则忽略本操作

支持的工具: maven, jdk, gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pipeline {
agent any
tools {
// The tool name must be pre-configured in Jenkins under Manage Jenkins → Global Tool Configuration
maven 'apache-maven-3.8.6'
}
stages {
stage('Example') {
steps {
sh 'mvn --version'
}
}
}
}
input

Required No
Allowed Inside a stage directive.

执行 input 步骤会暂停 pipeline, 直到用户输入参数

input 输入的参数能用在本 stage 的剩余部分

input 输入的参数如果要用在其他 stage, 需要在 pipeline 外或 environment 中定义一个变量用来接受 input 返回值

input 步骤的返回值类型取决于要返回的值的个数, 如果只有一个值, 返回值类型就是这个值的类型; 如果有多个值, 返回值类型为 Map 类型

input 参数只有 message 是必选参数

message

input 步骤的提示信息

id

input 的可选标识符, 默认为 stage 名称。

ok

自定义确定按钮的文本

submitter

字符串类型, 可以进行操作的用户 ID 或用户组名, 使用逗号分隔, 在逗号左右不允许有空格

在做 input 步骤的权限控制方面很实用

submitterParameter

字符串类型, 保存 input 步骤的实际操作者的用户名的变量名

parameters

手动输入的参数列表, 详见 parameters

示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//变量名, 用于存储input步骤的返回值
def inputParam
pipeline {
agent any
stages {
stage('pre deploy') {
steps {
script {
inputParam = input(
message: '准备发布到哪个环境?',
ok:'确定',
submitter:'admin,admin2,releaseGroup',
submutterParameter:'PERSON',
parameters: [
choice(name:'ENV', choices:'dev\ntest\nonline', description:'发布到什么环境?'),
string(name:'MY_PARAM', defaultValue:'hello', description:'')
]
)
}
}
}
stage('deploy') {
steps {
echo "操作者是 ${inputParam['PERSON']}"
echo "发布到什么环境? ${inputParam['ENV']}"
echo "自定义参数: ${inputParam['MY_PARAM']}"
}
}
}
}
when

Required No
Allowed Inside a stage directive.

when 指令允许 pipeline 根据给定的条件决定是否应该执行阶段

when 指令必须包含至少一个条件, 如果 when 指令包含多个条件, 所有的子条件必须返回 True, 阶段才能执行, 这与子条件在 allOf 条件下嵌套的情况相同 (参见下面的示例)

使用诸如 not, allOf, 或 anyOf 的嵌套条件可以构建更复杂的条件结构 can be built 嵌套条件可以嵌套到任意深度

在进入 stage 的 agent 前评估 when

默认情况下, 如果定义了某个阶段的代理, 在进入该 stage 的 agent 后该 stage 的 when 条件将会被评估。但是, 可以通过在 when 块中指定 beforeAgent 选项来更改此选项。 如果 beforeAgent 被设置为 true, 那么就会首先对 when 条件进行评估, 并且只有在 when 条件验证为真时才会进入 agent。

branch

当正在构建的分支与模式给定的分支匹配时, 执行这个阶段, 例如: when { branch 'master' }。注意, 这只适用于多分支 pipeline。

environment

当指定的环境变量是给定的值时, 执行这个步骤, 例如: when { environment name: 'DEPLOY_TO', value: 'production' }

expression

当指定的 Groovy 表达式评估为 true 时, 执行这个阶段, 例如: when { expression { return params.DEBUG_BUILD } }

not

当嵌套条件是错误时, 执行这个阶段,必须包含一个条件, 例如: when { not { branch 'master' } }

allOf

当所有的嵌套条件都正确时, 执行这个阶段,必须包含至少一个条件, 例如: when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } }

anyOf

当至少有一个嵌套条件为真时, 执行这个阶段,必须包含至少一个条件, 例如: when { anyOf { branch 'master'; branch 'staging' } }

示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
pipeline {
agent any
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
agent {
label "some-label"
}
when {
beforeAgent true
branch 'production'
environment name: 'DEPLOY_TO', value: 'production'
expression { BRANCH_NAME ==~ /(production|staging)/ }
not branch 'master'
allOf {
branch 'production'
environment name: 'DEPLOY_TO', value: 'production'
}
anyOf {
environment name: 'DEPLOY_TO', value: 'production'
environment name: 'DEPLOY_TO', value: 'staging'
}
}
steps {
echo 'Deploying'
}
}
}
}

并行(Parallel)

声明式 pipeline 的 stage 可以在他们内部声明多个嵌套 stage, 它们将并行执行。 注意, 一个 stage 必须只有一个 steps 或 parallel。 嵌套阶段本身不能包含进一步的 parallel, 但是其他的 stage 的行为与任何其他 stage 相同。任何包含 parallel 的 stage 不能包含 agent 或 tools, 因为他们没有相关 steps。

另外, 通过添加 failFast true 到包含 parallel 的 stage 中, 当其中一个进程失败时, 可以强制所有的 parallel 阶段都被终止。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
pipeline {
agent any
stages {
stage('Non-Parallel Stage') {
steps {
echo 'This stage will be executed first.'
}
}
stage('Parallel Stage') {
when {
branch 'master'
}
failFast true
parallel {
stage('Branch A') {
agent {
label "for-branch-a"
}
steps {
echo "On Branch A"
}
}
stage('Branch B') {
agent {
label "for-branch-b"
}
steps {
echo "On Branch B"
}
}
}
}
}
}

步骤(Steps)

声明式 pipeline 可以使用 pipeline steps 列表 中记录的所有可用步骤, 其中包含全面的步骤列表, 并添加了下面列出的步骤, 仅在声明式 pipeline 中支持。

script

script 可以在声明式 pipeline 中声明一个块并执行。一般情况下, 不需要在声明式 pipeline 中使用 script, 但是它可以提供了一个有用的”方法”(原文”escape hatch”)。

较大或较复杂的 script 块应该被移到共享库中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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"
}
}
}
}
}
}

插件

generic webhook trigger

简称 GWT, 安装后会暴露出来一个公共 API, GWT 插件接收到 JSON 或 XML 的 HTTP POST 请求后, 根据我们配置的规则决定触发哪个 Jenkins 项目。

multibranch scan webhook trigger plugin

如果希望通过 Webhook 触发 multibranch pipeline 项目需要安装 multibranch-scan-webhook-trigger-plugin 插件 安装完之后, 配置界面多出一个 Scan by webhook 选项:

config file provider

创建配置模板, 然后实现复用和灵活修改

role-based authorization strategy

实现不同的账号有不同的权限, 不同的项目

credentials binding plugin

添加凭证后, 需要安装”Credentials Binding Plugin”插件, 就可以在 pipeline 中使用 withCredentials 步骤使用凭证了

如果觉得 withCredentials 比较麻烦, 声明式 pipeline 还提供了 helper 方法, 在 environment 中使用 credentials(‘credentials-id’)就可以方便取出

注意: credentials 指令只能使用在 environment 段中, 而且目前只支持 Secret text, Username with password 和 Secret file 三种

vault

如果你要管理很多服务器密钥, 数据库密码, 用户密码或 token 等敏感信息, 可以使用 Vault 他是 hashicorp 公司出品的专业管理机密和保护敏感数据的工具。

vault 有以下功能:

  • 提供图形化界面, CLI 命令和 HTTP API
  • 方便的密码维护和变更管理功能, 比如密码需要定期更换, 使用 Vault 只需要在 vault 端更新密码, 通知应用重新拉取就可以了
  • 动态定期生成唯一密码, 省去人工维护麻烦
  • 支持 ACL, 角色, 策略, 认证等

安装非常简单, 就一个二进制包, 直接运行即可。具体使用请参考官方文档写的非常清晰, 再结合 Jenkins 的 vault 插件。就可以方便的管理凭证了。

更换插件镜像源

我们装好 Jenkins 后, 需要安装各种插件, 但是有时候安装插件经常失败, 或者特别慢。 这时候我们更新为国内源

具体方法: 系统管理 >> 管理插件 >> 高级 将 “升级站点” 更换为 https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/current/update-center.json (清华大学开源软件镜像站)

类似的还有 https://jenkins-zh.gitee.io/update-center-mirror/tsinghua/update-center.json

jenkins 镜像地址列表 http://mirrors.jenkins-ci.org/status.html

指定插件版本

最新全新安装的 Jenkins 并安装相关插件后发现执行流水线后报错, 经过排查, 是钉钉通知插件版本导致, 最新的 2.0 在 pipeline 中不支持 dingtalk, 需要降级使用 1.9 版本, 具体方法:

打开 http://updates.jenkins-ci.org/download/plugins 这里列出了所有可安装的插件, 然后搜索 ding, 进到 http://updates.jenkins-ci.org/download/plugins/dingding-notifications/

点 1.9 下载, 得到文件 dingding-notifications.hpi 然后回到 Jenkins 插件管理页面上传即可

参考资料

  1. 官方文档 - 安装 Jenkins
  2. 官方文档 - 使用 Jenkins
  3. 官方文档 - pipeline 步骤引用
  4. JENKINS-27421
  5. JENKINS-26481
  6. mafeifan 的技术博客
  7. pipeline input 步骤