环境变量可以被看作是pipeline与Jenkins交互的媒介。⽐如,可 以在pipeline中通过BUILD_NUMBER变量知道构建任务的当前构建 次数。环境变量可以分为Jenkins内置变量和⾃定义变量。接下来我们 分别讨论。
在pipeline执⾏时,Jenkins通过⼀个名为env的全局变量,将 Jenkins内置环境变量暴露出来。其使⽤⽅法有多种,示例如下:
pipeline {
agent any
stages {
stage('Example') {
steps {
echo "Running ${env.BUILD_NUMBER} on ${env.JENKINS_URL}"
echo "Running $env.BUILD_NUMBER on $env.JENKINS_URL"
echo "Running ${BUILD_NUMBER} on ${JENKINS_URL}"
}
}
}
}
默认env的属性可以直接在pipeline中引⽤。所以,以上⽅法都是合法的。但是不推荐⽅法三,因为出现变量冲突时,⾮常难查问题。
通过访问
来获取完整列表。在列表中,当一个变量被声明为"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提供了environment指令,⽅便⾃定义变量。比如:
pipeline {
agent any
environment {
CC = "clang"
}
stages {
stage("Example") {
environment {
DEBUG_FLAGS = "-g"
}
steps {
sh "${CC} ${DEBUG_FLAGS}"
sh "printenv"
}
}
}
}
environment
指令可以用在pipeline中定义,作用域就是整个pipeline,当定义在stage阶段,只在当前stage有效。
但是这些变量都不是跨pipeline的,比如pipeline a访问不到pipeline b的变量。在pipeline之间共享变量可以通过参数化pipeline来实现。
环境变量的互相引用:
environment {
__server_name = 'mail-server'
__version = "${BUILD_NUMBER}"
__artifact_name = "${__server_name}-${__version}.jar"
}
小技巧 :
sh 'printenv'
,将env变量的属性值打印出来。这样可以帮助我们避免不少问题。定义 全局环境变量 可以跨pipeline使用。
进入Jenkins→Manage Jenkins→Confiure System找到Global properties→勾选"Environment variables"复选框,单击“Add”按钮,在输入框中输入变量名和变量值即可。
⾃定义全局环境变量会被加⼊ env 属性列表中,所以,使⽤⾃定 义全局环境变量与使⽤Jenkins内置变量的⽅法⽆异:${env.gname}
构建是指将源码转换成一个可使用的二进制程序的过程。这个过程可以包括但不限于这几个环节:下载依赖、编译、打包。构建过程的输出——比如一个zip包,我们称之为制品(有些书籍也称之为产出物)。而管理制品的仓库,称为制品库。
虽然Jenkins只负责执⾏构建⼯具提供的命令,本⾝没有实现任何构建功能,但是它提供了构建⼯具的⾃动安装功能。
对构建⼯具的选择,很⼤⼀部分因素取决于你所使⽤的语⾔。如 构 建 Scala 使 ⽤ SBT , JavaScript 的 Babel 、 Browserify 、 Webpack、Grunt以及Gulp等。当然,也有通⽤的构建⼯具,⽐如 Gradle,它不仅⽀持Java、Groovy、Kotlin等语⾔,通过插件的⽅式还可以实现对更多语⾔的⽀持。
对构建工具的选择,还取决于团队对工具本身的接受程度。建议是,团队中同一技术栈的所有项目都使用同一个构建工具。
tools指令能帮助我们自动下载并安装所指定的构建工具,并将其加入PATH变量中。这样,我们就可以在sh步骤里直接使用了。但在agent none的情况下不会生效。
tools指令默认支持3种工具:JDK、Maven、Gradle。通过安装插件,tools指令还可以支持更多的工具。接下来,我们介绍几种常用的构建环境的搭建。
进入Manage Jenkins→Global Tool Configuration→JDK页,单击“Add JDK”:
注意
- 这里需要oracle帐户验证。
- Jenkins不会马上下载JDK,而是当pipeline使用到时才会直接执行下载操作。
基于安全的考虑,公司的内网可能无法直接访问因特网或者因为无法访问官方插件地址,所以使用自动下载会失败。这时就需要在Jenkins agent上准备JDK,然后在Manage Jenkins→Global Tool Configuration→JDK页中指定名称和JAVA_HOME路径:
注意
- 使用
docker agent
或者kubernetes agent
时,可使用agent基础镜像内安装JDK定制成自定义镜像。- 可以脚本自动化,即在使用tools安装JDK前,脚本自动提前准备好这个JAVA_HOME的JDK。
Jenkins pipeline的tools指令默认就支持Maven。所以,使用Maven只需要两步。
Maven默认使用的是其官方仓库,国内下载速度很慢。所以,我们通常会使用国内的Maven镜像仓库。这时就需要修改 Maven 的配置文件 settings.xml
。settings.xml
文件的默认路径为${M2_HOME}/conf/settings.xml
。但是,我们是不可能登录上Jenkins的机器,然后手动修改这个文件的。
Config File Provider插件能很好地解决这个问题。只需要在Jenkins的界面上填入settings.xml的内容,然后在pipeline中指定settings.xml就可以了。也就是说,对于不同的pipeline,可以使用不同的settings.xml。
具体实现方法如下:
安装Config File Provider插件。
进入Manage Jenkins页面,就可以看到多出一个“Managed files”菜单。
单击“Managed files”进入,在左侧菜单栏中选择“Add a new Config”,就会看到该插件支持很多种配置文件的格式及方式,
选择“Global Maven settings.xml”选项。因为我们的设置是全局的。填写“ID”字段,Jenkins pipeline会引用此变量名。假如使用的ID为maven-global-settings。
在Jenkins pipeline中使用的方法如下:
configFileProvider([configFile(fileId: "maven-global-settings", variable: "MAVEN_GLOBAL_ENV")]) {
sh "mvn -s $MAVEN_GLOBAL_ENV clean install"
}
Jenkins支持Golang的构建,只需要以下几步。
pipeline {
agent none
environment {
GOPATH = "${env.WORKSPACE}/"
}
tools {
go 'go1.10'
}
stages {
stage('build') {
steps {
sh "go build"
}
}
}
}
此时,在环境变量中会增加一个GOROOT变量。
Python环境很容易产生Python版本冲突、第三方库冲突等问题。所以,Python开发通常会进行工程级别的环境隔离,也就是每个Python工程使用一个Python环境。
在Jenkins环境下,我们使用Pyenv Pipeline插件可以轻松地实现。
首先,准备Python基础环境。
withPythonEnv("/usr/bin/python") {
sh "python --version"
}
withPythonEnv方法会根据第一个参数——可执行python路径——在当前工作空间下创建一个virtualenv环境。
withPythonEnv方法的第二个参数是一个闭包。闭包内的代码就执行在新建的virtualenv环境下。
不是所有的构建工具都需要安装相应的Jenkins插件才可以使用。
平时,开发人员在搭建开发环境时做的就是:首先在机器上安装好构建工具,然后将这个构建工具所在目录加入PATH环境变量中。
如果想让Jenkins支持更多的构建工具,也是同样的做法:在Jenkins agent上安装构建工具,并记录下它的可执行命令的目录,然后在需要使用此命令的Jenkins pipeline的PATH环境变量中加入该可执行命令的目录。示例如下:
pipeline {
agent none
environment {
PATH = "/usr/local/customtool/bin:$PATH"
}
stages {
stage('build') {
steps {
sh "customtool build"
}
}
}
}
还可以有另一种写法:
pipeline {
agent none
environment {
CUSTOM_TOOL_HOME = "/usr/local/customtool/bin"
}
stages {
stage('build') {
steps {
sh "${CUSTOM_TOOL_HOME}/customtool build"
}
}
}
}
在实际工作中,有时需要对同一份源码使用多个版本的编译器进行编译。tools指令除了支持pipeline作用域,还支持stage作用域。所以,我们可以在同一个pipeline中实现多版本编译。代码如下:
pipeline {
agent none
stages {
stage('build with jdk-10.0.2') {
tools {
jdk "jdk-10.0.2"
}
steps {
sh "printenv"
}
}
stage('build with jdk-9.0.4') {
tools {
jdk "jdk-9.0.4"
}
steps {
sh "printenv"
}
}
}
}
在打印出来的日志中,会发现每个stage下的JAVA_HOME变量的值都不一样。