Jenkins制品管理
一.简介
制品是软件开发过程中产生的多种有形副产品之一。广义的制品还包括用例、UML图、设计文档等。而狭义的制品就可以简单地理解为二进制包。虽然有些代码是不需要编译就可以执行的,但是我们还是习惯于将这些可执行文件的集合称为二进制包。本章讨论的是狭义的制品。行业内有时也将制品称为产出物或工件。
最简单的制品管理仓库就是将制品统—放在一个系统目录结构下。但是很少有人这样做,更多的做法是使用现成的制品库。
制品管理涉及两件事情:一是如何将制品放到制品库中;二是如何从制品库中取出制品。由于每种制品的使用方式不一样,因此下面我们分别进行介绍。
二.Jenkins管理制品
从手工打包到自动化打包,再将打好的包放到制品库中。这看似简单,但是要在团队中从无到有地落地其实是一个很漫长的过程,特别是对于存在很多遗留项目的团队。每个团队都应该按照自己当前情况进行调整,有时统一的解决方案不一定适合你。
曾经,笔者所在团队已经将部分项目的编译和单元测试放到Jenkins上执行,然而并没有人力及能力搭建Nexus。但是又期望能将自动打包好的JAR包放到各个环境中使用,以马上从持续集成中获益,怎么办?
这时,archiveArtifacts步骤就派上用场了。它能对制品进行归档,然后你就可以从Jenkins页面上下载制品了。
完成的pipeline如下:
pipeline {
agent any
tools {
maven 'mvn-3.5.4'
}
stages {
stage('Build') {
steps {
sh "mvn clean spring-boot: repackage"
}
}
}
post {
always{
archiveArtifacts artifacts: 'target/**/*.jar', fingerprint: true
}
}
}
常用参数:
- artifacts(必填):字符串类型,需要归档的文件路径,使用Ant风格路径表达式
- fingerpring(可选):布尔类型,是否对归档的文件进行签名
- excludes(可选):字符串类型,需要排出的文件路径,使用Ant风格路径表达式
- caseSensitive(可选):布尔类型,对路径大小写是否敏感
- onlylfSuccessful(可选):布尔类型,只在构建成功时进行归档
- 这个步骤并不只用于归档jar包,事实上,它能归档所有类型的制品
三.Nexus
maven上传
nexus搭建好后,就可以使用deploy上传jar或者war包到nexus中。Deploy插件是Apache Maven团队提供的官方插件,能将JAR包及POM文件发布到Nexus中。目前该插件的最新版本是2.8.2,如果不需要自定义Deploy插件配置,则不需要在POM文件中定义。
<plugins>
<plugin>
<groupid>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
使用Deploy插件发布需要以下几个步骤
1.配置发布地址,在Maven项目的POM文件中加入∶
<distributionManagement>
<snapshotRepository>
<id>nexus-snapshot</id>
<name>my nexus snapshot</name>
<url>http://<你的Nexus地址>/repository/maven-snapshots</url>
</snapshotRepository>
<repository>
<id>nexus-release</id>
<name>my nexus release</name>
<url>http://<你的Nexus地址>/repository/maven-releases</url>
</repository>
</distributionManagement>
完成此步骤后,我们就可以通过执行mvn clean deploy进行发布了。Deploy插件会根据Maven项目中定义的version值决定是使用nexus-snapshot仓库还是nexus-release仓库。当version值是以-SNAPSHOT后缀结尾时,则发布到nexus-snapshot仓库
2.配置访问Nexus的用户名和密码才能发布制品,需要在Maven的settings.xml中加入:
<servers>
<server>
<id>nexus-snapshot</id>
<username>admin</username>
<password>admin123</password>
</server>
<server>
<id>nexus-release</id>
<username>admin</username>
<password>admin123</password>
</server>
</servers>
jenkins上传
除了可以通过Maven发布JAR包,还可以使用Nexus Platform来插件实现。最新版本的Nexus Platform ( 3.3.20180801-112343.4970c8a )已经同时支持Nexus 2.x和Nexus 3.x,只是它的文档更新不及时,大家都不知道它支持3.x版本了。
在安装好Nexus Platform插件后,根据以下步骤来使用。
1.进入Manage Jenkins→Configure System→Sonatype Nexus页,设置Nexus 3.x的服务器地址
需要注意的是:
- 在“Credentials”选项处,增加了一个具有发布制品到Nexus中的权限的用户名和密码凭证
- Server ID字段的值,在Jenkinsfile中会引用
设置完成后,单击“Test connection”按钮测试设置是否正确。
2.在Jenkinsfile中加入nexusPublisher步骤
stage('Build') {
steps {
sh "mvn clean test package"
nexusPublisher(
nexusInstanceId: 'nexus3',
nexusRepositoryId: 'maven-releases',
packages: [
[
$class: "MavenPackage',
mavenAssetList: [
[classifier: '',
extension: '',
filePath: './target/server-1.0-SNAPSHOT.jar'
]
],//end of mavenAssetList
mavenCoordinate: [
artifactId: 'server',
groupId: 'codes.showme',
packaging: 'jar', version: '1.0'
]
] //end of packages])
])
}
}
下面简单介绍一下nexusPublisher的参数。
- nexusInstanceld :在Jenkins中配置Nexus 3.x时的Server lD
- nexusRepositoryld :发布到Nexus服务器的哪个仓库
- mavenCoordinate : Maven包的坐标,packaging值与Maven中的packaging值一致,可以是jar、war、pom、hpi等。
- mavenAssetList:要发布的文件,如果是pom.xml,则extension必须填“xml”
在实际工作中,笔者并不常使用此插件。原因如下:
1.每个Maven项目都可能不同,必须为每个Maven项目写nexusPublisher方法
2.对于多模块的Maven项目,nexusPublisher的参数写起来十分啰唆
但是介绍这个插件还是有必要的,一是大家可以根据实际情况进行选择;二是可以了解Jenk-ins与Nexus的集成程度。
管理Docker镜像
在Jenkins机器安装Docker,在Nexus的仓库列表页Administration->repository->repositories
单机“docker(hosted)”,进入Docker私有仓库创建页
在创建过程中,需要指定Docker私有仓库提供HTTP服务的端口为8595,私有仓库地址为:http://<ip>:8595
创建Docker私有仓库凭证,将镜像推送到Docker私有仓库是需要用户名和密码的。我们不能将密码明文写在Jenkinsfile中,所以需要创建一个“Username withpassword”凭证。
当私有仓库创建好后,我们就可以构建Docker镜像并发布到仓库中了。
假设Dockerfile 与Jenkinsfile在同一个目录下,我们看一下Jenkinsfile的内容。
pipeline {
agent any
environment {
registry = "http://192.168.0.101:8595"
registryCredential = 'dockernexus'
}
stages {
stage('Build') {
steps {
withDockerRegistry([
credentialsId: "${registryCredential}",
url: "${registry}"]) {
sh "docker build . -t ${registry} /hello:v2"
sh "docker push ${registry}/hello:v2"
}
}
}
}
}
withDockerRegistry步骤做的事情实际上就是先执行命令∶
docker login-u admin-p*******http://192.168.0.101:8595
其间,所生成的config.json文件会存储在工作空间中。然后再执行闭包内的命令。将镜像推送到Nexus中后,在Nexus中可以看到信息
由于是私有的非安全(HTTP)的仓库,所以需要配置Docker的daemon.json
{
"insecure-registries":["<私有仓库的地址>"],
"registry-mirrors":["https://registry.docker-cn.com"]
}
同时,为加速基础镜像的下载,设置了国内Docker镜像
管理raw
进入Administration→Repository→Repositories页,单击“raw ( hosted )”,进入raw仓库创建页,输入仓库名称“raw-example”,单击“Create repository”按钮,确认后创建成功。
该仓库的地址是:<你的Nexus地址>/repository/raw-examplel
使用HTTP客户端就可以将制品上传到raw仓库中,使用curl命令
1.在Jenkins上添加“Username with password”凭证
2.在Jenkinsfile中加入上传制品的步骤
pipeline {
agent any
environment {
nexusRawUsernamePassword = credentials('nexusRaw')
}
stages {
stage('Build') {
steps {
sh "curl --user '${nexusRawUsernamePassword}' --upload-file ./readme.md http://10.33.193.82:8081/repository/raw-example/${BUILD_NUMBER}/readme.md"
}
}
}
}
为简单起见,我们直接使用构建号作为目录名称来区分每次上传的制品。curl命令的格式为:
curl --user '<username:password>' --upload-file <待上传制品的路径〉〈将制品保存到Nexus上的全路径>
将制品保存到Nexus上的全路径∶如果目录不存在,Nexus将会自动创建。
3.在Nexus中,我们看到readme.md文件已经上传成功
在Jenkins pipeline中获取原始制品时,我们同样使用curl命令。
sh "curl --user '${nexusRawUsernamePassword}' -o readme.md http://10.33.193.82:8081/repository/raw-example/2/readme.md"
四.拷贝制品
在某些场景下,我们需要从另一个pipeline中拷贝制品,Copy Artifact插件 可以帮助我们实现
steps {
copyArtifacts(
projectName: "core",
selector: lastSuccessful(true)
)
}
从core项目中拿到最后一次构建成功的制品
参数:
- projectname :字符串类型,Jenkins job或pipeline名称
- selector : BuildSelector类型,从另一个pipeline中拷贝制品的选择器,默认拷贝最后一个制品
- parameters :字符串类型,使用逗号分隔的键值对字符串( name1=value1 , name2=value2 ),用于过滤从哪些构建中拷贝制品
- filter:字符串类型,Ant风格路径表达式,用于过滤需要拷贝的文件
- excludes:字符串类型,Ant风格路径表达式,用于排除不需要拷贝的文件
- target:字符串类型,拷贝制品的目标路径,默认为当前pipeline的工作目录
- optional:布尔类型,如果为true,则拷贝失败,但不影响本次构建结果
- fingerprintArtifacts:布尔类型,是否对制品进行签名,默认值为true
- resultVariableSuffix :上例中,无法得知我们到底拿的是core项目的哪次构建的制品。Copy Artifact插件的设计是将其构建次数放到一个环境变量中。这个环境变量名就是在COPYARTIFACT BUILDNUMBER后拼上resultVariableSuffix,比如resultVariableSuf fix值为corejob,那么就在pipeline 中通过变量COPYARTIFACT BUILDNUMBER corejob拿到源pipeline的构建次数了。
除projectname参数是必填的外,其他参数都是可选的。
常用的获取选择器的方法
- lastSuccessful:最后―次构建成功的制品。方法签名为lastSuccessful ( boolean stable )。stable为true表示只取构建成功的制品,为false表示只要构建结果比UNSTABLE好就行。
- specific:指定某一次构建的制品。方法签名为specific(StringbuildNumber)。buildNum ber表示指定取第n次构建的制品
- lastCompleted:最后一次完成构建的制品,不论构建的最终状态如何。方法签名为lastCompleted()
- latestSavedBuild:最后一次被标记为keep forever的构建的制品。方法签名为latestSavedBuild()
五.版本号
谈到制品,就必须谈到版本号的管理。版本号的制定并没有所谓的行业标准。比如谷歌浏览器当前版本号为70.0.3538.110 ; Ubuntu操作系统当前版本号为18.10;由美国计算机教授高德纳(DonaldErvin Knuth )编写的功能强大的排版软件TEX系统的版本号不断趋近于T,类似于这样:3.1415926。
GitHub提出了一种具有指导意义、统一的版本号表示规则,称为Semantic Versioning (语义化版本表示)。这也被人们称为三段式版本号。有了这套规则,用户一看版本号,就大概能猜到一个软件两个版本之间的可能变化。
语义化版本格式为:主版本号.次版本号.修订号。版本号递增规则如下:
- 主版本号:当作了不兼容的API修改时。
- 次版本号:当作了向下兼容的功能性新增时。·修订号:当作了向下兼容的问题修正时。
- 修订号:当作了向下兼容的问题修正时
先行版本号及版本编译元数据可以加到“主版本号.次版本号.修订号”的后面,作为延伸。以下是常用的修饰词。
- alpha :内部版本
- beta :测试版本
- rc:即将作为正式版本发布
- lts :长期维护
语义化版本号的好处是除了方便人类识别,也方便软件识别。比如Ansible提供的版本比较器的使用:{{ansible distribution version isversion ( '12.04','>=')}。这也是很多开源软件使用语义化版本号的原因。
但是,语义化版本号真的适用于所有的场景吗?不一定。我们需要根据版本号的作用来确定软件版本号的格式。说白了,你希望别人一眼从版本号里看出什么,你就怎么确定版本号。
那么,谁看这个版本号?软件的真正使用者根本不关心软件版本号。不过,现实中各种App强制大版本,对于市场营销的确有好处。企业软件的销售人员是要看版本号的。他必须知道不同版本之间的功能区别,以更好地完成其工作。
移动端App的产品经理是要看版本号的。他必须知道当前最新版本与上一个版本的区别,以及市面上都运行了哪些版本。当用户提交Bug时,产品经理可以根据用户所装的版本进行决策。
程序员是要看版本号的。版本号意味着软件运行时的源码版本。有了这个对应关系,对于查Bug、了解线上业务逻辑的运行都是非常有用的。
对于版本号的不同诉求,决定了它的作用。笔者总结,可以从以
下两个角度来设计版本号。
1.方便表达。对于更接近使用者的软件,更倾向于这个角度,比如三段式版本号。所以,推荐前端应用使用三段式版本号。
2.方便找出制品与源码的关系。对于更接近软件源码的人,更倾向于这个角度,比如Go CD的版本号:18.10.0( 7703-42d1cbe661161b5400289ead86c0447c84af8cOa )。除了三段式版本号,还会有构建次数及相应的代码提交ID。推荐后端服务使用Go CD的这种版本号格式。
现实中,如何设计版本号才能做到既方便表达,又方便找出制品与源码的关系呢?采用内外部版本号策略就可以了。对外部,可以使用1.0.1这样的版本号;对内部,可以使用1.0.1.20180911.12.42d1cbe66116这样的版本号。最后要做的事情就是,想办法将内外部版本对应上就可以了。
Version Number
Version Number ( https"//plugins.jenkins.io/versionnumber )是一款用于生成版本号的插件,它提供了VersionNumber步骤。
具体使用方法如下:
script {
def version = VersionNumber versionPrefix: "${JOB_NANE}-", versionNumberString: 'v1.1.1.${BUILDS_ALL_TIME}'
echo "${version}"
}
注意:BUILDS ALL TIME只是占位符,并不是Jenkins或VersionNumber插件提供的环境变量。
VersionNumber步骤支持以下参数。
- versionNumberString :字符串类型,版本号格式,用于生成版本号。只能使用单引号,以防格式中的占位符被转义。版本号格式支持多种占位符。
- versionPrefix:字符串类型,版本号的前缀
- projectStartDate :字符串类型,项目开始时间,格式为yyyy-MM-dd,用于计算项目开始后的月数和年数
-worstResultForlncrement :字符串类型,如果本次构建状态比上一次构建状态更糟糕,则BUILDS_TODAY、BUILDS_THIS_WEEK、BUILDS_THIS_MONTH、BUILDS_THIS_YEAR占位符的值不会增加。worstResultForlncrement可以设置的值有sUCCESs.UNSTABLE、FAILURE、ABORTED、NOT_BUILT(默认)。此参数较少使用
versionNumberString参数使用占位符生成版本号。部分占位符本身支持参数化。接下来分别介绍它们
- BUILD DATEFORMATTED∶格式化的构建日期,支持参数化,如${BUILD DATE FORMATTED , "yyyy-MM-dd"}
- BUILD DAY:构建日期,支持×和XX参数。比如是12月2日,${BUILD DAY}将返回2,${BUILD DAY,X}将返回2,${BUILDDAY,XX}将返回03
- BUILD WEEK:今年构建的星期数,支持X和XX参数
- BUILD MONTH:今年构建的月数,支持X和XX参数
- BUILD YEAR:今年构建的年份
比如构建的时间为2018-12-02,那么BUILD_DAY的值为2,BUILD_WEEK的值为49,BUILD_MONTH的值为12,BUILD_YEAR的值为2018。
接下来是一组和构建数相关的占位符:BUILDS TODAY、BUILDS THIS WEEK、 BUILDS THIS MONTH、BUILDS THISYEAR,它们分别表示当天、本星期、本月、本年完成的构建数。BUILDS ALL TIME表示自从项目开始后完成的总构建数。
MONTHS SINCE PROJECT START和YEARS SINCE PROJECT START分别表示自项目开始日期起已过去的日历月数和年数。
Jenkins制品管理的更多相关文章
- Jenkins的制品管理
Jenkins的制品管理 制品是什么? 也叫产出物或工件.制品是软件开发过程中产生的多种有形副产品之一.广义的制品包括用例.UML图.设计文档等.而狭义的制品就可以简单地理解为二进制包.虽然有些代码是 ...
- [转]Jenkins使用 管理节点
现在我们已经搭建好了基本的Jenkins环境,在这一集里,我们说一说如何管理节点. 进入“系统管理”中的“管理节点”. 创建Windos系统的奴隶节点 先创建一台安装了Win7系统的虚拟机,作为Jen ...
- Jenkins用户组管理
Jenkins用户组管理 转载2015-06-10 21:44:24 标签:jenkinsrolestrategypluginusergroupcitools 一.安装插件 安装RoleStrateg ...
- 【Devops】【docker】【CI/CD】Jenkins源代码管理 添加gitlab项目地址,报错Failed to connect to repository : Error performing command: ls-remote -h git@192.168.92.130:8090/root/swapping.git HEAD
Jenkins源代码管理 添加gitlab项目地址 报错如下: Failed to connect to repository : Error performing command: ls-remot ...
- jenkins中管理用户
jenkins中管理用户: 管理用户权限
- Jenkins源代码管理(SVN)
Subversion 安装插件 1.首先将本地的自动化用例打包上传svn 2.配置jenkins源代码管理(每次执行jenkins时,会自动check-out配置地址中的代码到Jenkins的工作空间 ...
- jenkins插件管理提示“update information obtained:不可用ago”
jenkins插件管理遇到两个错误 (1)插件管理页面提示:There were errors checking the update sites:IOException:Unable to tunn ...
- Jenkins 源代码管理(SVN)
Subversion 安装插件 1.首先将本地的自动化用例打包上传 svn 2.配置 jenkins 源代码管理(每次执行 jenkins 时,会自动 check-ou t配置地址中的代码到 Jenk ...
- Jenkins凭证管理
目录 一.简介 二.管理凭证 三.常用凭证 保密文本 账号密码 保密文件 账号秘钥 四.优雅使用凭证 保密文本 账号密码 保密文件 五.凭证插件 集成HashiCorp Vault pipeline ...
随机推荐
- XenServer删除ISO存储!
1.用命令 df -hal 可以看到 ISO库是使用了10G的硬盘的 2.下面开始直接右键删除ISO,但看到资源还是占用着10G的 3.如果想把这10G的硬盘资源空出来的话,只要复制前面查找到挂载的路 ...
- python实现分水岭算法
目录: 问题:分水岭算法对图像分割很有作用,怎么把对象分割开来的?分水岭算法是比较完美的分割,跟前面的讲的轮廓不一样! (一)原理 (二)实现 (一)原理 opencv中的分水岭算法是基于距离变换的, ...
- Go语言核心36讲(Go语言实战与应用九)--学习笔记
31 | sync.WaitGroup和sync.Once 我们在前几次讲的互斥锁.条件变量和原子操作都是最基本重要的同步工具.在 Go 语言中,除了通道之外,它们也算是最为常用的并发安全工具了. 说 ...
- [loj2470]有向图
参考ExtremeSpanningTrees,考虑优化整体二分时求$g_{i}\in \{w_{mid},w_{mid+1}\}$的最优解 对于$m=n-1$的问题,不需要去网络流,可以直接树形dp ...
- try catch引发的性能优化深度思考
关键代码拆解成如下图所示(无关部分已省略): 起初我认为可能是这个 getRowDataItemNumberFormat 函数里面某些方法执行太慢,从 formatData.replace 到 une ...
- 7.4 k8s结合ceph rbd、cephfs实现数据的持久化和共享
1.在ceph集群中创建rbd存储池.镜像及普通用户 1.1.存储池接镜像配置 创建存储池 root@u20-deploy:~# ceph osd pool create rbd-test-pool1 ...
- 雪花算法对System.currentTimeMillis()优化真的有用么?
前面已经讲过了雪花算法,里面使用了System.currentTimeMillis()获取时间,有一种说法是认为System.currentTimeMillis()慢,是因为每次调用都会去跟系统打一次 ...
- P5509 派遣
题面传送门. 数论小杂烩( 由题意,对于每个士兵 \(i\),要么选,对答案产生 \(a_i(\frac{x}{i-x})\) 倍的贡献,要么不选,对答案产生 \(1\) 倍的贡献. 由此可知每个士兵 ...
- DirectX12 3D 游戏开发与实战第十章内容(上)
仅供个人学习使用,请勿转载.谢谢! 10.混合 本章将研究混合技术,混合技术可以让我们将当前需要光栅化的像素(也称为源像素)和之前已经光栅化到后台缓冲区的像素(也称为目标像素)进行融合.因此,该技术可 ...
- 如何利用efetch从NCBI中批量下载数据?
目录 找序列 下序列 假设我要从NCBI中下载全部水稻的mRNA序列,如何实施? 找序列 第一步,肯定是找到相关序列. 我从ncbi taxonomy进入,搜索oryza.因为要搜索mRNA核酸序列, ...