通常我们软件开发流程大概是下面所示:
本地开发->本地自测->提交代码->编译发布->测试人员测试->提交至生产
在发布阶段,
- 有的项目是采用版本控制工具在Linux服务器上拉取对应分支的最新代码
- 有的是在本地对比Git版本的差异,生成差异的文件,打包上传至服务器,进行覆盖原来的代码文件完成发布
上面2种方法是我工作中遇到的,下面我们来学习一种新的发布方式:Jenkins
Jenkins可以帮你在写完代码后,一键完成开发过程中的一系列工作
特别是在开发阶段,配合WebHook可以非常省心的完成代码发布工作,开发者只需要提交代码,就会触发Jenkins发布任务的执行,从而将最新代码部署到服务器上
什么是Jenkins?
Jenkins是一个Java开放的开源程序,所以,需要提前安装Java JDK环境,能支持安装到windows,mac,linux平台,主要是一个管理工具
为什么要使用Jenkins?
我们用它,主要是项目上的持续集成和持续交付。持续集成对应英文(Continuous Integration),有时候简称CI,持续交付对应英文(Continuous Delivery),简称CD,以后,听到了CI和CD,就明白了什么意思。下面这张图,是Jenkins在实际项目运用上的一个经典的流程图
##安装Jenkins
安装的方式很多,我这里学习Jenkins采用的是Docker创建容器的方式运行
下载Jenkins
docker pull jenkins
下载完成,查看下
1 | ☁ ~ docker image ls |
创建映射目录
这个目录根据个人需求,可以进行重新指定,我指定的是:/Users/zhimma/jenkins
mkdir /Users/zhimma/jenkins
创建容器
docker run -d -p 49001:8080 -v $PWD/jenkins:/var/jenkins_home -t jenkins/jenkins
我映射了容器的端口8080到主机上的端口49001, 第一个数字代表主机上的端口,而最后一个代表容器的端口
运行后,Docker会帮我们创建一个Jenkins的运行环境的容器,使用docker ps
查看容器启动情况
1 | ☁ ~ docker ps |
到这,我们的Jenkins环境搭建完成,下面我们做一些初始化工作
初始化Jenkins
解锁Jenkins
在浏览器中输入localhost:49001
,进入web页面,第一次需要先解锁Jenkins
进入/Users/zhimma/jenkins/secrets
目录,制initialAdminPassword
文件的内容就是首次解锁的密码
安装推荐插件
设置管理员
安装Jenkins插件
我们目前使用GitLab管理代码,所以我们先安装下面几个插件
- GitLab Plugin
- Gitlab Hook Plugin
- AnsiColor(可选)这个插件可以让Jenkins的控制台输出的log带有颜色(就和linux控制台那样)
配置SSH
本机生成SSH:ssh-keygen -t rsa -C "Your email"
,最终生成id_rsa和id_rsa.pub(公钥)
Gitlab上添加公钥:复制id_rsa.pub里面的公钥添加到Gitlab
Jenkins上配置密钥到SSH:复制id_rsa里面的公钥添加到Jenkins(private key选项)
开始Pipeline
在Jenkins中,把每一段管道比作是不同的Job,我们提到Jenkins的工作流程,build-deploy-test-release,每个流程之间我们都可以用Pipeline来连接,大致如下效果图。
SCM:软件配置管理工具
创建Pipeline风格的项目
实现Pipeline-Web UI方式
如下图所示:
实现Pipeline-Jenkinsfile方式
上面通过Web UI方式只适用于非常简单的任务,而大型复杂的任务最好采用Jenkinsfile
方式并纳入SCM管理。 这次我选择从SCM中的Jenkinsfile
来定义管道。
我们需要在自己的项目根目录创建Jenkinsfile
文件,在里面编写具体的发布流程代码。
使用Jenkinsfile
接下来详细介绍一下怎样编写Jenkinsfile
来完成各种复杂的任务。
Pipeline支持两种形式,一种是Declarative
管道,一个是Scripted
管道。
一个Jenkinsfile
就是一个文本文件,里面定义了Jenkins Pipeline
。 将这个文本文件放到项目的根目录下面,纳入版本系统。
####Declarative风格类型
1 | pipeline { |
上面是一个Declarative类型的Pipeline,目前实际开发基本采用这种方式;
- 第一行是小写的pipeline,然后一对大括{},大括号里面就是代码块,用来和别的代码块隔离出来,pipeline是一个语法标识符,也叫关键字,如果是Declarative类型,一定是pipeline {}这样起头的;如果是脚本文件,pipeline不要求一定是第一行代码。也就是说pipeline前面可以有其他代码,例如导入语句,和其他功能代码。pipeline是一个执行pipeline代码的入口,jenkins可以根据这个入门开始执行里面不同stage
- 第二行agent any,agent是一个语法关键字,any是一个option类型,agent是代理的意思,这个和选择用jenkins平台上那一台机器去执行任务构建有关
- 第三行stages{}, stages是多个stage的意思,也就是说一个stages可以包含多个stage,从上面代码结果你也可以看出来。上面写了三个stage,根据你任务需要,你可以写十多个都可以
- 第四行stage(‘Build’) {}, 这个就是具体定义一个stage,一般一个stage就是指完成一个业务场景。Build是认为给这个任务取一个名字。
- 第五行steps{},字面意思就是很多个步骤的意思。这里提一下,看到了steps,当然还有step这个指令。一般来说,一个steps{}里面就写几行代码,或者一个try catch语句。
post
post
section 定义了管道执行结束后要进行的操作。支持在里面定义很多Conditions
块: always
, changed
, failure
, success
和 unstable
。 这些条件块会根据不同的返回结果来执行不同的逻辑。
- always:不管返回什么状态都会执行
- changed:如果当前管道返回值和上一次已经完成的管道返回值不同时候执行
- failure:当前管道返回状态值为”failed”时候执行,在Web UI界面上面是红色的标志
- success:当前管道返回状态值为”success”时候执行,在Web UI界面上面是绿色的标志
- unstable:当前管道返回状态值为”unstable”时候执行,通常因为测试失败,代码不合法引起的。在Web UI界面上面是黄色的标志
1 | // Declarative // |
stages
由一个或多个stage
指令组成,stages块也是核心逻辑的部分。 我们建议对于每个独立的交付部分(比如Build
,Test
,Deploy
)都应该至少定义一个stage
指令。比如:
1 | // Declarative // |
steps
在stage
中定义一系列的step
来执行命令。
1 | // Declarative // |
agent
agent
指令指定整个管道或某个特定的stage
的执行环境。它的参数可用使用:
- any - 任意一个可用的agent
- none - 如果放在pipeline顶层,那么每一个
stage
都需要定义自己的agent
指令 - label - 在jenkins环境中指定标签的agent上面执行,比如
agent { label 'my-defined-label' }
- node -
agent { node { label 'labelName' } }
和 label一样,但是可用定义更多可选项 - docker - 指定在docker容器中运行
- dockerfile - 使用源码根目录下面的
Dockerfile
构建容器来运行
environment
environment
定义键值对的环境变量
1 | // Declarative // |
options
还能定义一些管道特定的选项,介绍几个常用的:
- skipDefaultCheckout - 在
agent
指令中忽略源码checkout
这一步骤。 - timeout - 超时设置
options { timeout(time: 1, unit: 'HOURS') }
- retry - 直到成功的重试次数
options { retry(3) }
- timestamps - 控制台输出前面加时间戳
options { timestamps() }
parameters
参数指令,触发这个管道需要用户指定的参数,然后在step
中通过params
对象访问这些参数。
1 | // Declarative // |
triggers
触发器指令定义了这个管道何时该执行,一般我们会将管道和GitHub、GitLab、BitBucket关联, 然后使用它们的webhooks来触发,就不需要这个指令了。如果不适用webhooks
,就可以定义两种cron
和pollSCM
- cron - linux的cron格式
triggers { cron('H 4/* 0 0 1-5') }
- pollSCM - jenkins的
poll scm
语法,比如triggers { pollSCM('H 4/* 0 0 1-5') }
1 | // Declarative // |
stage
stage
指令定义在stages
块中,里面必须至少包含一个steps
指令,一个可选的agent
指令,以及其他stage相关指令。
1 | // Declarative // |
tools
定义自动安装并自动放入PATH
里面的工具集合
1 | // Declarative // |
注:① 工具名称必须预先在Jenkins中配置好了 → Global Tool Configuration.
内置条件
- branch - 分支匹配才执行
when { branch 'master' }
- environment - 环境变量匹配才执行
when { environment name: 'DEPLOY_TO', value: 'production' }
- expression - groovy表达式为真才执行
expression { return params.DEBUG_BUILD } }
1 | // Declarative // |
Steps
这里就是实实在在的执行步骤了,每个步骤step都具体干些什么东西, 前面的Sections
、Directives
算控制逻辑和环境准备,这里的就是真实执行步骤。
这部分内容最多不可能全部讲完,官方Step指南 包含所有的东西。
Declared Pipeline
和Scripted Pipeline
都能使用这些step,除了下面这个特殊的script
。
一个特殊的step就是script
,它可以让你在声明管道中执行脚本,使用groovy语法,这个非常有用:
1 | // Declarative // |
Scripted风格类型
1 | node { |
这个代码,有两点和上面不同。
第一个是Scripted模式是node{}开头,并没有pipeline{}直观。
第二个要指出的是,scripted模式下没有stages这个关键字或者指令,只有stage。上面其实可以node(‘Node name’) {}来开头,Node name就是从节点或master节点的名称。
Scripted Pipeline
没那么多东西,就是定义一个node
, 里面多个stage
,里面就是使用Groovy语法执行各个step
了,非常简单和清晰,也非常灵活。
环境变量
Jenkins定了很多内置的环境变量,可在文档localhost:49001/pipeline-syntax/globals#env
找到, 通过env
直接使用它们:
1 | pipeline { |
在项目根目录修改Jenkinsfile后,提交到服务器,点击立即构建,查看Console Output
输出系统的环境变量
参考引用
https://blog.csdn.net/u011541946/article/details/83152494
https://blog.csdn.net/u011541946/article/category/8223796/2?
https://www.xncoding.com/2017/03/22/fullstack/jenkins02.html