Jenkins 不完全指南
Jenkins 是什么?
Jenkins 是一款由 Java 编写的开源的持续集成工具(ci/cd)
Jenkins 的安装
CentOS7 以下可以直接使用 yum 安装
Centos8 及以上可以使用 dnf 安装,将 yum 命令替换为 dnf 命令即可;没有dnf 可以自行安装
yum install dnf
Jenkins 依赖
java环境,请确保已安装java, 在终端输入java敲击回车验证
- yum 源导入
#添加Yum源
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
#导入密钥
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
- 安装/卸载
# 升级 yum 源中的所有包
sudo yum upgrade
#安装
sudo yum install jenkins
#卸载
yum remove jenkins
#想卸干净点,执行下面命令
rm -rf /etc/sysconfig/jenkins.rpmsave
rm -rf /var/cache/jenkins/
rm -rf /var/lib/jenkins/
rm -rf /var/log/jenkins
rm -rf /usr/lib/jenkins
Jenkins 的启动/重启/停止/状态
# 启动 Jenkins 服务
systemctl start jenkins
# 重启 Jenkins 服务
systemctl restart jenkins
# 停止 Jenkins 服务
systemctl stop jenkins
# 查看 Jenkins 服务状态
systemctl status jenkins
Jenkins 运行在机器的 8080 端口,使用云服务器的同学记得到防火墙放行端口。
初始化 Jenkins
在浏览器输入 http://<你的服务器 IP>:8080 就可以访问到 Jenkins 的解锁界面了。
首次进入初始化 Jenkins 需要输入一段命令来查看密码,在服务器终端执行:
cat /var/lib/jenkins/secrets/initialAdminPassword
把控制台输出的密码复制到 Jenkins 解锁界面中,就到插件安装界面了
安装插件
我们选择左边的默认安装推荐插件,然后静等插件安装完成。
假如插件安装失败,不要慌,我们分析下情况(欢迎大家补充)
- 被墙了
- 尝试开启科学上网(
推荐) - 换源,这里推荐清华源
- 尝试开启科学上网(
- 操作不对
- 点击重试,一般多试几次就可以
- 重新阅读本教程一遍
- 卸载 jenkins,重新把安装流程走一边
- 手动下载插件
- 重启服务器
创建用户
安装成功之后,根据提示创建管理员用户,到此,我们的Jenkins就安装成功了,也创建了我们自己的管理员账户
新建任务
本教程不赘述自由风格(Freestyle project)软件项目,因太过简单,教程烂大街
现在我们可以新建任务了,点击主界面左侧的新建任务,选择构建一个流水线(Pipeline)软件项目,给任务取个名字
Jenkins Pipeline 是什么?(大概看看,不懂可以跳过,因为我也不太懂)
Jenkins Pipeline(或简称为 "Pipeline")是一套插件,将持续交付的实现和实施集成到 Jenkins 中。持续交付 Pipeline 自动化的表达了这样一种流程:将基于版本控制管理的软件持续的交付到您的用户和消费者手中。 Jenkins Pipeline 提供了一套可扩展的工具,用于将“简单到复杂”的交付流程实现为“持续交付即代码”。Jenkins Pipeline 的定义通常被写入到一个文本文件(称为 Jenkinsfile )中,该文件可以被放入项目的源代码控制库中!!厉害吧👍
配置流水线
Pipeline 可以两种方式来配置
建议把
Jenkinsfile(Pipeline 脚本)跟项目源码一块加入到版本控制中,这样方便项目成员了解构建构建和流程。当然出于安全,有些环境变量和参数等可以管理在 Jenkins 管理平台上,具体后续会有介绍
- 配置 git 仓库的方式来获取到 pipeline 脚本(
推荐)- 定义(Definition)选择 Pipeline script from SCM
- SCM 选择 Git
- 配置 Jenkinsfile 所在仓库地址
- 选择 Credentials,添加凭证(
重要!没有的话配置一下git ssh连接信息) - 选择脚本路径(
Script Path)路径(通常默认 Jenkinsfile 即可)
- 在配置页面直接写 pipeline 脚本
pipeline 脚本
有些插件安装后可以直接在 pipeline 中使用,如发送邮件的
Extended E-mail Notification,安装后可以直接steps { emailext to: 'mafeifan@qq.com', subject: "test", body: "an email"}来发送邮件
pipeline 能使用 Declarative Pipeline(声明式)、Scripted Pipeline(脚本化)两种语法进行编写, 都是使用 groovy 来实现的
推荐使用
Declarative Pipeline(声明式),也是官方最新推荐的
例:声明式pipeline
pipeline {
agent any
// stages 包含一个或多个阶段(stage)的容器
stages {
// stage 阶段,pipleline流水线由一个或多个阶段(stage)组成,每个阶段必须有名称,这里build就是此阶段的名称
stage('build') {
// steps,阶段中的一个或多个具体步骤(step)的容器
steps {
// 这是是具体的步骤,真正”做事“的,不可再拆分的最小操作
echo "hello world"
}
}
}
}
- 所有的声明必须包含在 pipeline 语句块中。
- 块只能由 stage, directives (指令,后续会讲到) 或 steps 组成。
- agent:指定流水线的执行位置,流水线中的每个阶段都必须在某个地方(物理机,虚拟机或 Docker 容器)执行,agent 部分即指定具体在哪里执行。
- echo 是内置命令,用来输出一段文本,还有些命令是安装插件后才有的,参见官方文档。
- step: 步骤,可拆分最小单元,真正“做事”的语句。如 echo "hello world" 表示输出一句话。
例:脚本式 pipeline
node {
/* .. snip .. */
withEnv(["PATH+MAVEN=${tool 'M3'}/bin"]) {
sh 'mvn -B verify'
}
}
groovy 是什么
Groovy 是用于 Java虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。使用该种语言不必编写过多的代码,同时又具有闭包和动态语言中的其他特性
-
写 pipeline 就是写 Groovy 代码,Jenkins pipeline 其实就是基于 Groovy 语言实现的一种 DSL,了解一些 Groovy 语法知识是很有必要的
-
不想本地安装 Groovy 环境的话,可以打开 groovy-playground.appspot.com/ 运行线上 groovy 代码,直接查看结果,该网站可能需要会科学上网
必要的 Groovy 语法知识
- 定义变量和方法用def关键字,def name="jack"
- 语句最后的分号不是必需的
- 方法调用时可以省略括号
def say(String name = "world") {
return "hi " + name
}
// 调用
say name = "jack"
- 双引号支持插值,单引号不会解析变量,原样输出
def name = 'world'
// 结果: hello world
print "hello ${name}"
// 结果: hello ${name}
print 'hello ${name}
- 三双引号和三单引号都支持换行,只有三双引号支持插值
def foo = """ line one
line two
${name}
"""
- 支持闭包
// 定义闭包
def codeBlack = {print "hello closure"}
// 闭包当做函数调用
codeBlack
// 闭包可以赋值给变量,或者作为参数传递
def pipeline(closure) {
closure()
}
pipeline(codeBlack)
// 因为括号是非必需的,下面几种写法结果是一样的,是不是和 Jenkins pipeline 很像呢
pipeline( {print "hello closure"} )
pipeline {
print "hello closure"
}
pipeline codeBlack
- 闭包的另一个用法
def stage(String name, closure) {
println name
closure()
}
// 正在情况下,我们这样使用stage函数
stage("stage name", {
println "closure"
})
// 最终打印
/*
stage name
closure
*/
// 但是,在Groovy里,可以直接这么写
stage("stage name") {
print "closure"
}
Jenkins 环境变量
环境变量可以被看作是 pipeline 与 Jenkins 交互的媒介。比如,可以在 pipeline 中通过 BUILD_ NUMBER 变量知道构建任务的当前构建次数。环境变量可以分为 Jenkins 内置变量和自定义变量。
Jenkins 内置变量
在 pipeline 执行时,Jenkins 通过一个名为 env 的全局变量,将 Jenkins 内置环境变量暴露出来。其使用方法有多种,示例如下:
pipeline {
agent any
stages {
stage('Example') {
steps {
echo "Running ${env.BUILDNUMBER} on ${env.JENKINS_URL}" # 方法1
echo "Running $env.BUILDNUMBER on $env.JENKINS_URL" # 方法2
echo "Running ${BUILDNUMBER} on ${JENKINS_URL}" # 方法3 不推荐,难排查
}
}
}
}
默认 env 的属性可以直接在 pipeline 中引用。所以以上方法都是合法的。但是不推荐方法三,因为出现变量冲突时,非常难查问题。
通过访问 <Jenkins master的地址>/pipeline-syntax/globals#env 来获取完整列表。在列表中,当一个变量被声明为 "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提供的environment指令中定义
pipeline {
agent any
environment {
// 覆盖默认的PATH变量值
PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin"
name='jack'
}
stages {
stage("test env") {
steps {
sh "printenv" #调试,打印所有env变量
echo "${name}" # jack
echo "${env.name}" # jack
}
}
}
}
environment指令可以用在pipeline中定义,作用域就是整个pipeline,当定义在stage阶段,只在当前stage有效
- 环境变量的互相引用
在调试pipeline时,可以再开始阶段加一句 sh 'printenv' 将所有env变量打印出来
自定义变量时,为避免命名冲突,可根据项目或公司加上统一前缀,如__server_name,__就是前缀
environment {
__server_name = 'email-server'
__version = "${BUILD_NUMBER}"
__artifact_name = "${__server_name}-${__version}.jar"
}
- 自定义全局环境变量 定义全局环境变量可以跨pipeline使用 进入Jenkins -- Manage Jenkins -- 找到Global properties -- 勾选Environment variables
自定义全局环境变量会被加入env属性列表中,所以使用时可以直接用${env.g_name}引用
- 动态定义变量
pipeline {
agent any
environment {
_version = createVersion()
}
stages {
stage ('build') {
steps {
script {
echo "${_version}"
}
}
}
}
}
def createVersion() {
return new Date().format('yyyyMM') + "-${env.BUILD_NUMBER}"
}
Pipeline 中的指令
显然,基本结构满足不了现实多变的需求。所以,Jenkins pipeline通过各种指令(directive) 来丰富自己。指令可以被理解为对Jenkins pipeline基本结构的补充
- Jenkins pipeline支持的指令有:
- environment: 用于设置环境变量,可定义在stage或pipeline部分。
- tools: 可定义在pipeline或stage部分。它会自动下载并安装我们指定的工具,并将其加入PATH变量中。
- input: 定义在stage部分,会暂停 pipeline,提示你输入内容。
- options: 用于配置 Jenkins pipeline 本身的选项,比如 options {retry (3) }指当pipeline失败时再重试2次。options指令 可定义在stage或pipeline部分。
- parallel: 并行执行多个step。在pipeline插件 1.2版本后,parallel开始支 持对多个阶段进行并行执行。
- parameters: 与input不同,parameters是 执行pipeline前传入的一些参数。
- triggers: 用于定义执行pipeline的触发器。
- when: 当满足when定义的条件时,阶段才执行。
在使用指令时,需要注意的是每个指令都有自己的"作用域"。如果指令使用的位置不正确,Jenkins将会报错。
options 指令用于配置整个 Jenkins pipeline 本身的选项
pipeline {
agent any
options {
timeout(time: 1, unit: 'HOURS')
disableConcurrentBuilds()
}
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
- 整个pipeline执行超过一个小时将中止
- 禁止pipeline同时执行,避免抢占资源或调用冲突
stage 的 options 指令类似于流水线根目录上的 options
pipeline {
agent any
stages {
stage('Example') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
echo 'Hello World'
}
}
}
}
- 指定 Example 阶段的执行超时时间, 在此之后,Jenkins 将中止流水线运行
拓展
在实际使用中,我们很多项目都需要单元测试以及导出报告的 stage,这时这两个stage 我们应该能够服用量,否则的话每个 Job 的 pipeline 都需要写一遍。有几种方式可以实现复用
-
将公共的 pipeline 步骤导入到 Global Pipeline LIbraries,这个不是我们要讲的,感兴趣的话可以去官网看看: Jenkins 共享库
-
由于 pipeline 是用 groovy 脚本编写的,那么我们可以将公共的步骤抽出来,形成一个公共代码库,当需要引用公共库中的 stage 时,只需要将对应的 groovy 脚本 load 进来即可,这样做的好处是可以随时的修改,并且省去了上传到 Jenkins 共享库 的步骤