原文地址:Jenkins 2.x-实践指南
环境变量
环境变量可以看做是 pipeline 与 Jenkins 交互的媒介。比如,可以在 pipeline 中通过 BUILD_NUMBER 变量知道构建任务的当前构建次数。环境变量可以分为 Jenkins 内置变量和自定义变量。
Jenkins 内置变量
在 pipeline 执行时,Jenkins 通过一个名为 env 的全局变量,将 Jenkins 内置环境变量暴露出来。其使用方法有多种,示例如下:
1 | pipeline { |
默认 env 的属性可以直接在 pipeline 中引用。所以,以上方法都是合法的。但是不推荐方法三,因为出现变量冲突时,非常难查问题。
那么,env 变量都有哪些可用属性呢?通过访问 <Jenkins master的地址>/pipeline-syntax/globalsenv
来获取完整列表。在列表中,当一个变量被声明为 “For a multibranch project” 时,代表只有多分支项目才会有此变量。
下面我们介绍几个在实际工作中经常用到的变量。
- BUILD_NUMBER:构建号,累加的数字。在打包时,它可作为制品名称的一部分,比如 server-2.jar;
- BRANCH_NAME:多分支 pipeline 项目支持。当需要根据不同的分支做不同的事情时就会用到,比如通过代码将 release 分支发布到生产环境中,master 分支发布到测试环境中;
- BUILD_URL:当前构建的页面URL,如果构建失败,则需要将失败的构建链接放在邮件通知中,这个链接就可以是 BUILD_URL;
- GIT_BRANCH:通过 git 拉取的源码构建的项目才会有此变量。
在使用 env 变量时,需要注意不同类型的项目,env 变量所包含的属性及其值是不一样的。比如普通 pipeline 任务中的 GIT_BRANCH 变量的值为 origin/master,而在多分支 pipeline 任务中 GIT_BRANCH 变量的值为 master。
所以,在 pipeline 中根据分支进行不同行为的逻辑处理时,需要留意。
小技巧:在调试 pipeline 时,可以在 pipeline 的开始阶段加一句: sh ‘printenv’,将 env 变量的属性值打印出来。这样可以帮助我们避免不少问题。
自定义 pipeline 环境变量
当 pipeline 变得复杂时,我们就会有定义自己环境变量的需求。声明式 pipeline 提供了 environment 指令,方便自定义变量。比如:
1 | pipeline { |
另外,environment 指令可以在 pipeline 中定义,代表变量作用域为整个 pipeline;也可以在 stage 中定义,代表变量只在该阶段有效。
但是这些变量都不是跨 pipeline 的,比如 pipeline a 访问不到 pipeline b 的变量。在 pipeline 之间共享变量可以通过参数化 pipeline 来实现。我们将在后续讨论。
在实际工作中,还会遇到一个环境变量引用另一个环境变量的情况。在 environment 中可以这样定义:
1 | environment { |
值得注意的是,如果在 environment 中定义的变量与 env 中的变量重名,那么被重名的变量的值会被覆盖掉。比如在 environment 中定义 PATH 变量(PATH 也是 env 中的一个变量)
1 | environment { |
在执行 sh 指令时,我们将看到无法在系统上执行。
1 | [Pipeline] sh |
小技巧:为了避免变量名冲突,我们可以根据公司的实际情况,在变量名前加上前缀,比如
__server_name
,__
是就是前缀。
自定义全局环境变量
env 中的变量都是 Jenkins 内置的,或者是具体 pipeline 相关的。有时候我们想要定义一些全局的跨 pipeline 的自定义变量。
进入 Manage Jenkins
–> Configure System
–> Global properties
页,勾选 “Environment variables
“ 复选框,单击 “Add
“ 按钮,在输入框中输入变量名和变量值即可。
通过单击 “Add” 按钮,还可以添加多个全局环境变量。
自定义全局环境变量会被加入 env 属性列表中,所以,使用自定义全局环境变量与使用 Jenkins 内置变量的方法无异:${env.g_name}
构建工具
构建是指将源码转换成一个可使用的二进制程序的过程。这个过程可以包括但不限于这几个环节:下载依赖,编译,打包。构建过程的输出–比如一个 zip 包,我们称之为制品。而管理制品的仓库,称为制品库。关于制品的管理,我们在后面进行详细介绍。
在没有 Jenkins 的情况下,构建过程通常发生在某个程序员的电脑上,甚至只能发生在某台特定的电脑上。这会给软件的质量带来很大的不确定性。
解决这一问题的办法就是让构建每一步都是可重复的,尽量与机器无关。所以,构建工具的安装,设置也应该是自动化的,可重复的。
虽然 Jenkins 只负责执行构建工具提供的命令,本身没有实现任何构建功能,但是它提供了构建工具的自动安装功能。
构建工具的选择
对于构建工具的选择,很大一部分因素取决于你所使用的语言。比如构建 Scala 使用 SBT,JavaScript 的 Babel,Browserify,Webpack,Grunt 以及 Gulp 等。当然也有通用的构建工具,比如 Gradle,它不仅支持 Java,Groovy,Kotlin 等语言,通过插件的方式还可以实现对更多语言的支持。
对构建工具的选择,还取决于团队对工具本身的接受程度。笔者的建议是,团队中同一技术栈的所有项目都使用同一个构建工具。
tools 指令介绍
tools 指令能帮助我们自动下载并安装所指定的构建工具,并将其加入 PATH 变量中。这样,我们就可以在 sh 步骤里直接使用了。但在 agent none 的情况下不会生效。
tools 指令默认支持3种工具:JDK,Maven,Gradle。通过插件安装,tools 指令还可以支持更多的工具。接下来我们介绍几种常用的构建环境的搭建。
JDK 环境搭建
自动安装 JDK
设置自动安装 Oracle JDK 时有一些特殊,因为下载 Oracle JDK 时需要输入用户名和密码。
进入 Manage Jenkins –> Global Tool Configuration –> JDK 页,单击 “Add JDK” 按钮,就可以设置自动安装 JDK,如下图所示:
这时,Jenkins 并不会马上下载 JDK,而是当 pipeline 使用到时才会直接执行下载操作。
指定 JDK 路径
基于安全的考虑,公司的网络可能无法直接访问外网,所以无法使用自动下载。这时就需要在 Jenkins agent 上自行安装 JDK,然后在 Manage Jenkins –> Global Tool Configuration –> JDK页中指定名称和 JAVA_HOME 路径,如下图所示:
注意:”自行安装“ 的意思并不是指手动安装,我们应该写自动化脚本,自动化安装 JDK。
Maven
使用 Maven 进行构建
Jenkins pipeline 的 tools 指令默认就支持 Maven。所以,使用 Maven 只需要两步。
进入 Manage Jenkins –> Global Tool Configuration –> Maven 页,设置如下图所示。
请注意 Name 的值为 mvn-3.6.3。接下来会用到这个值。”Install from Apache” 下的 Version 可以选择 Maven 版本。在 jenkinsfile 中指定 Maven 版本,并使用 mvn 命令。
1 | pipeline { |
这样,当执行到 tools 指令时,Jenkins 会自动下载并安装 Maven。将 mvn 命令加入环境变量中,可以使我们在 pipeline 中直接执行 mvn 命令。
使用 Managed files 设置 Maven
Maven 默认使用的是其官方仓库,国内下载速度很慢。所以,我们通常会使用国内的 Maven 镜像仓库。这时候就需要修改 Maven 的配置文件 settings.xml。settings.xml 文件的默认路径为 ${M2_HOME}/conf/settings.xml。但是我们是不可能登录上 Jenkins 的机器,然后手动修改这个文件的。
Config File Provider 插件(https://plugins.jenkins.io/config-file-provider
) 能很好的解决这个问题。只需要在 Jenkins 的界面填入 settings.xml 的内容,然后在 pipeline 中指定 settings.xml 就可以了。也就是说,对于不同的 pipeline,可以使用不同的 settings.xml。
具体的实现方法:
安装 Config File Provider 插件;
进入 Manage jenkins 页面,就可以看到多出一个
Manage files
菜单;单击 Manage files 进入,在左侧菜单栏中选择
Add a new Config
,就会看到该插件支持很多种配置文件的格式以及方式;选择 Global Maven settings.xml 选项。因为我们的设置是全局的。填写 “ID” 字段,Jenkins pipeline 会引用此变量名。假如使用的 ID 为 maven-global-settings。
单击 Submit 按钮提交后,就看到编辑页了。将自定义的 Maven settings.xml 的内容粘贴到 ”Content“ 字段中,单击 “Submit” 按钮即添加完成。
在 Jenkins pipeline 中使用的方法如下:
1
2
3configFileProvider([configFile(fileId: 'maven-global-settings', variable: 'MAVEN_GLOBAL_ENV')]) {
sh "mvn -s $MAVEN_GLOBAL_ENV clean install"
}
Go 语言环境搭建
Jenkins 支持 Golang 的构建,只需要以下几步。
安装 Go 插件(
https://plugins.jenkins.io/golang
)进入 Manage Jenkins –> Global Tool Configuration –> Go 页,设置如下图
在 pipeline 中加入 tools 部分
1
2
3tools {
go 'go1.14.2'
}此时,在环境变量中会增加一个 GOROOT 变量。
设置 GOPATH,了解 Go 语言开发的读者都会知道,编译时需要设置 GOPATH 环境变量。直接在 environment 指令中添加就可以了。完整代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16pipeline {
agent any
environment {
GOPATH = "${env.WORKSPACE}/"
}
tools {
go 'go1.10'
}
stages {
stage('build') {
steps {
sh "go build"
}
}
}
}
Python 环境搭建
Python 环境很容易产生 Python 版本冲突,第三方库冲突等问题。所以 Python 开发通常会进行工程级别的环境隔离,也就是每个 Python 工程使用一个 Python 环境。
在 Jenkins 环境下,我们使用 Pyenv Pipeline 插件(https://plugins.jenkins.io/pyenv-pipeline
) 可以轻松地实现。
首先,准备 Python 基础环境
在 Jenkins 机器上安装 Python ,pip,virtualenv
- pip: Python 包管理工具
- virtualenv :Python 中的虚拟环境管理工具。
安装 Pyenv Pipeline 插件,然后在 pipeline 中使用 Pyenv Pipeline 插件提提供的 withPythonRnv 方法。
1
2
3withPythonEnv('/usr/bin/python') {
sh 'python --version'
}
withPythonEnv 方法会根据第一个参数 —可执行Python 路径 —在当前工作空间下创建一个 virtualenv 环境。
withPythonEnv 方法的第二个参数是一个闭包。闭包内的代码就执行在新建的 virtualenv 环境下。
利用环境变量支持更多的构建工具
是不是所有的构建工具都需要安装相应的 Jenkins 插件才可以使用呢?当然不是。
平时,开发人员在搭建开发环境时做的就是:首先在机器上安装好构建工具,然后将这个构建工具所在的目录加入 PATH 环境变量中。
如果想让 Jenkins 支持更多的构建工具,也是同样的做法:在 Jenkins agent 上安装构建工具,并记录下它的可执行命令的目录,然后在需要使用此命令的 Jenkins pipeline 的 PATH 环境变量中加入该可执行命令的目录。示例如下:
1 | pipeline { |
还有另一种写法
1 | pipeline { |
利用 tools 作用域实现多版本编译
在实际工作中,有时候需要对同一份源码使用多个版本的编译器进行编译。tools 指令除了支持 pipeline 作用域,还支持 stage 作用域,所以我们可以在同一个 pipeline 中实现多版本编译。代码如下:
1 | pipeline { |
在打印出来的日志中,会发现每个 stage 下的 JAVA_HOME 变量的值都不一样。