Jenkins
前言
在了解Jenkins之前我们可能需要了解CI/CD的概念。CI/CD 是一种通过在应用开发阶段引入自动化来频繁向客户交付应用的方法。CI/CD 的核心概念是持续集成、持续部署。
CI 是什么?CI 和 CD 有什么区别?
缩略词 CI / CD 具有几个不同的含义。CI/CD 中的“CI”始终指持续集成
,它属于开发人员的自动化流程。成功的 CI 意味着应用代码的新更改会定期构建、测试并合并到共享存储库中。该解决方案可以解决在一次开发中有太多应用分支,从而导致相互冲突的问题。
CI/CD 中的“CD”指的是持续交付或持续部署
,这些相关概念有时会交叉使用。两者都事关管道后续阶段的自动化,但它们有时也会单独使用,用于说明自动化程度。
什么是持续集成?
持续集成(Continuous integration,简称CI)指的是,频繁的将代码集成到主干。
持续集成的目的,就是上产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,不惜通过自动化测试。只要有一个测试用例,就不能集成。
通过持续集成,团队可以快速的从一个功能到另一个功能,简而言之,敏捷软件开发很大一部分都要归功于持续集成。
什么是持续部署?
对于一个成熟的 CI/CD 管道来说,最后的阶段是持续部署。作为持续交付——自动将生产就绪型构建版本发布到代码存储库——的延伸,持续部署可以自动将应用发布到生产环境。由于在生产之前的管道阶段没有手动门控,因此持续部署在很大程度上都得依赖精心设计的测试自动化。
实际上,持续部署意味着开发人员对应用的更改在编写后的几分钟内就能生效(假设它通过了自动化测试)。这更加便于持续接收和整合用户反馈。总而言之,所有这些 CI/CD 的关联步骤都有助于降低应用的部署风险,因此更便于以小件的方式(而非一次性)发布对应用的更改。不过,由于还需要编写自动化测试以适应 CI/CD 管道中的各种测试和发布阶段,因此前期投资还是会很大。
持续集成/部署的好处
1、降低风险,由于持续集成不断去构建,编译和测试,可以很早期发现问题,所以修复的代价就少;
2、对系统健康持续检查,减少发布风险带来的问题;
3、减少重复性工作;
4、持续部署,提供可部署单元包;
5、持续交付可提供使用的版本;
6、增强团队信心;
持续集成部署流程说明
1)首先,开发人员每天进行代码提交,提交到Git仓库
2)然后,Jenkins作为持续集成工具,使用Git工具到Git仓库拉取代码到集成服务器,再配合JDK, Maven等软件完成代码编译,代码测试与审查,测试,打包等工作,在这个过程中每一步出错,都重新再执行一次整个流程。
3)Jenkins把生成的jar或war包分发到测试服务器或者生产服务器,测试人员或用户就可以访问 应用。
Jenkins概念
Jenkins是一个独立的开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。前身是Hudson是一个可扩展的持续集成引擎。可用于自动化各种任务,如构建,测试和部署软件。
Jenkins官网: jenkins-ci.org/
主要用于:
- 持续、自动地构建/测试软件项目,如CruiseControl与DamageControl。
- 监控一些定时执行的任务。
环境搭建
Jenkins支持各个平台上的搭建过程,开发我们主要在Linux和win7上玩转Jenkins,这边主要通过win7下介绍Jenkins玩法,Linux上大同小异。
Jenkins特点:
- 开源免费;
- 跨平台,支持所有的平台;
- master/slave支持分布式的build;
- web形式的可视化的管理页面;
- 安装配置超级简单;
- tips及时快速的帮助;
- 已有的200多个插件
Jenkins 安装环境
1.打开Jenkins 官网
2.点击图中的Download 按钮,我们将看到如下内容
3.右键管理员身份运行该安装包,避免权限不足等原因导致安装失败。
4.点击Next 进入这个界面
5.如果不需要修改安装路径,直接点击Next即可。这里建议修改成D:\Applications\Jenkins\
6.接下来我们来到这个界面
7.然后配置一个端口,端口范围在1-65535之间任意一个数字,可以通过Test Port 测试端口是否被其他程序占用。
8.然后配置一个端口,端口范围在1-65535之间任意一个数字,可以通过Test Port 测试端口是否被其他程序占用。
9.如果测试通过,如上图所示,然后我们点击Next.
10.这里我们需要选择JDK 路径,可以选择jdk 1.8 或JDK 11. PS: 这里建议安装JDK 1.8 ,这是因为目前lombok 貌似不支持JDK 11,如果贸然使用JDK 11 ,你的程序使用了Lombok 则可能无法构建成功。
11.然后我们来到这个界面,这时候我们点击Install 即可进行安装。
12.点击Finished 后会自动打开浏览器的 http://localhost:8080/login?from=%2F
双击图中路径,从这个路径中找到密码
C:\Windows\System32\config\systemprofile\AppData\Local\Jenkins.jenkins\secrets\
13.将密码输入上面的输入框中点击继续,即可打开界面
这里我们可以选择安装的Jenkins 插件,如果不太熟,新手建议选择安装推荐的插件
以后如果熟悉了可以选择自定义的插件。
14.然后这里就会开始安装
- 耐心等待片刻,即可安装完成。
16.点击保存并完成。
17.再次点击保存并完成
18.到这一步之后点击开始使用Jenkins 即可打开这样的界面
Jenkins API 接口
Jenkins 作为项目构建,持续部署必不可少的工具,如何使用程序或者脚本来控制构建流程成为本文研究的内容.
默认情况下,安装好Jenkins后,/api
路径下面有一些基本 api 的介绍,可供参考,但是不是很直观,没有罗列出 api 接口.
本文使用的 jenkins-java 客户端是:
<dependency>
<groupId>com.offbytwo.jenkins</groupId>
<artifactId>jenkins-client</artifactId>
<version>0.3.7</version>
</dependency>
假设 jenkins 部署地址为: http://localhost:8080
本文用到的 api:
名称 | API |
---|---|
创建 Job | POST http://localhost:8080/createItem/api/json?name=xxx |
更新 Job | POST http://localhost:8080/job/{job_name}/config.xml/api/json |
获取 Job | GET http://localhost:8080/job/{job_name}/api/json |
获取 JobXml | GET http://localhost:8080/job/{job_name}/config.xml/api/json |
创建 Build | POST http://localhost:8080/job/{job_name}/build/api/json |
获取 QueueItem | GET http://localhost:8080/queue/item/17/api/json |
获取 Build信息 | GET http://localhost:8080/job/test/6/api/json |
获取TXT日志 | GET http://localhost:8080/job/test/{build_number}/logText/progressiveText/api/json |
获取 Html 日志 | GET http://localhost:8080/job/test/{build_number}/logText/progressiveHtml/api/json |
创建 Job API
jenkins 的配置都是靠 xml 的格式落地的,所以配置其实都是 xml 的形式.
POST http://localhost:8080/createItem/api/json?name=xxx
将创建需要的 config.xml也用请求传入到服务端,既可以创建成功.
如何知道 config.xml应该如何编写呢?
- 可以在 jenkins 收工创建一个需要的项目,然后编辑完成后,到 jenkins 工作目录下 找到 jobs/{job_name}/config.xml 用他作为模板来书写你需要的模板.
- 通过获取 xml 的 api 来获取
GET http://localhost:8080/job/{job_name}/config.xml/api/json
Java Client
jenkinsServer.createJob("auto_test_job", replacedText, true);
String xml = jenkinsServer.getJobXml("auto_test_job");
修改 Job API
修改 job 也是修改xml.
POST http://localhost:8080/job/{job_name}/config.xml/api/json
config.xml的内容传入到 body 中,contentType 设置为text/xml
Java Client
jenkinsServer.updateJob("auto_test_job", replacedText, true);
构建 Build API
根据 job 名称获取 Job
GET http://localhost:8080/job/{job_name}/api/json
新的构建
POST http://localhost:8080/job/{job_name}/build/api/json
提交到服务器成功后返回一个类似于队列ID的东西,因为是异步构建,那么要获取构建的状态,就需要,用这个队列 id去进一步的获取. 例如:
$ curl -v -XPOST http://localhost:8080/job/test/build/api/json
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /job/test/build/api/json HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 201 Created
< Date: Sat, 05 Jan 2019 08:33:45 GMT
< X-Content-Type-Options: nosniff
< Location: http://localhost:8080/queue/item/17/
< Content-Length: 0
< Server: Jetty(9.4.z-SNAPSHOT)
<
* Connection #0 to host localhost left intact
上面的Location: http://localhost:8080/queue/item/17/
就是返回的队列信息,下面的 queueItem 获取就是依赖这个.
根据 QueueId 获取 QueueItem
GET http://localhost:8080/queue/item/17/api/json
举例
$ curl http://localhost:8080/queue/item/17/api/json\?pretty\=true
{
"_class" : "hudson.model.Queue$LeftItem",
"actions" : [
{
"_class" : "hudson.model.CauseAction",
"causes" : [
{
"_class" : "hudson.model.Cause$UserIdCause",
"shortDescription" : "由用户 anonymous 启动",
"userId" : null,
"userName" : "anonymous"
}
]
}
],
"blocked" : false,
"buildable" : false,
"id" : 17,
"inQueueSince" : 1546677225670,
"params" : "",
"stuck" : false,
"task" : {
"_class" : "hudson.maven.MavenModuleSet",
"name" : "test",
"url" : "http://localhost:8080/job/test/",
"color" : "blue"
},
"url" : "queue/item/17/",
"why" : null,
"cancelled" : false,
"executable" : {
"_class" : "hudson.maven.MavenModuleSetBuild",
"number" : 6,
"url" : "http://localhost:8080/job/test/6/"
}
}
获取到的 QueueItem 上面就知道这个 item 有没有被 build 执行,比较关键的参数就是executable
,如果executable
不为空,就说明 jenkins 已经在对这个任务进行 build 的了,build 的编号就是number
,也就是我们在 jenkins 页面上看到的编号.你可以通过url
字段的值在浏览器打开.
获取 Build 详情
既然开始了 build,我们就可以获取 build 的详细信息.
curl http://localhost:8080/job/test/6/api/json\?pretty\=true
{
...
"building" : false,
"description" : null,
"displayName" : "#6",
"duration" : 13631,
"estimatedDuration" : 17999,
"executor" : null,
"fullDisplayName" : "test #6",
"id" : "6",
"keepLog" : false,
"number" : 6,
"queueId" : 17,
"result" : "SUCCESS",
"timestamp" : 1546677234794,
"url" : "http://localhost:8080/job/test/6/",
"builtOn" : "",
...
}
从返回结果可以看到 是否还在 build:"building" : false,
,如果 build 结束状态就在:"result" : "SUCCESS",
获取Build日志
文本:
GET http://localhost:8080/job/test/{build_number}/logText/progressiveText/api/json
html
GET http://localhost:8080/job/test/{build_number}/logText/progressiveHtml/api/json
Java Client
JobWithDetails job = jenkinsServer.getJob(jenkinsJob);
...
QueueReference reference = job.build( true);
...
QueueItem queueItem = jenkinsServer.getQueueItem(new QueueReference(queuePart));
...
Build build = jenkinsServer.getBuild(queueItem);
...
BuildWithDetails details = build.details();
BuildResult result = details.getResult();
...
String logs = details.getConsoleOutputText();
Jenkins 调用API 相关问题
org.apache.http.client.HttpResponseException: Forbidden
at com.offbytwo.jenkins.client.validator.HttpResponseValidator.validateResponse(HttpResponseValidator.java:11)
at com.offbytwo.jenkins.client.JenkinsHttpClient.post(JenkinsHttpClient.java:261)
at com.offbytwo.jenkins.client.JenkinsHttpClient.post(JenkinsHttpClient.java:221)
按ctrl键进去看源码,此post方法在这里传了一个crumbFlag参数,
传一个true进来,这里就会去获取crumb值,
获取到的信息长这个样子: {"_class":“hudson.security.csrf.DefaultCrumbIssuer”,“crumb”:“2e214ad29c6319a985dde08d70818c1287a7f1ae077d4e65156d6e636d5a67bd”,“crumbRequestField”:“Jenkins-Crumb”}
然后将其中的crumb值放入到请求头中。
API调用的如果遇到类似的问题,可以在方法中传入crumbFlag参数 true即可。