一.简介

制品是软件开发过程中产生的多种有形副产品之一。广义的制品还包括用例、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制品管理的更多相关文章

  1. Jenkins的制品管理

    Jenkins的制品管理 制品是什么? 也叫产出物或工件.制品是软件开发过程中产生的多种有形副产品之一.广义的制品包括用例.UML图.设计文档等.而狭义的制品就可以简单地理解为二进制包.虽然有些代码是 ...

  2. [转]Jenkins使用 管理节点

    现在我们已经搭建好了基本的Jenkins环境,在这一集里,我们说一说如何管理节点. 进入“系统管理”中的“管理节点”. 创建Windos系统的奴隶节点 先创建一台安装了Win7系统的虚拟机,作为Jen ...

  3. Jenkins用户组管理

    Jenkins用户组管理 转载2015-06-10 21:44:24 标签:jenkinsrolestrategypluginusergroupcitools 一.安装插件 安装RoleStrateg ...

  4. 【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 ...

  5. jenkins中管理用户

    jenkins中管理用户: 管理用户权限

  6. Jenkins源代码管理(SVN)

    Subversion 安装插件 1.首先将本地的自动化用例打包上传svn 2.配置jenkins源代码管理(每次执行jenkins时,会自动check-out配置地址中的代码到Jenkins的工作空间 ...

  7. jenkins插件管理提示“update information obtained:不可用ago”

    jenkins插件管理遇到两个错误 (1)插件管理页面提示:There were errors checking the update sites:IOException:Unable to tunn ...

  8. Jenkins 源代码管理(SVN)

    Subversion 安装插件 1.首先将本地的自动化用例打包上传 svn 2.配置 jenkins 源代码管理(每次执行 jenkins 时,会自动 check-ou t配置地址中的代码到 Jenk ...

  9. Jenkins凭证管理

    目录 一.简介 二.管理凭证 三.常用凭证 保密文本 账号密码 保密文件 账号秘钥 四.优雅使用凭证 保密文本 账号密码 保密文件 五.凭证插件 集成HashiCorp Vault pipeline ...

随机推荐

  1. XenServer删除ISO存储!

    1.用命令 df -hal 可以看到 ISO库是使用了10G的硬盘的 2.下面开始直接右键删除ISO,但看到资源还是占用着10G的 3.如果想把这10G的硬盘资源空出来的话,只要复制前面查找到挂载的路 ...

  2. python实现分水岭算法

    目录: 问题:分水岭算法对图像分割很有作用,怎么把对象分割开来的?分水岭算法是比较完美的分割,跟前面的讲的轮廓不一样! (一)原理 (二)实现 (一)原理 opencv中的分水岭算法是基于距离变换的, ...

  3. Go语言核心36讲(Go语言实战与应用九)--学习笔记

    31 | sync.WaitGroup和sync.Once 我们在前几次讲的互斥锁.条件变量和原子操作都是最基本重要的同步工具.在 Go 语言中,除了通道之外,它们也算是最为常用的并发安全工具了. 说 ...

  4. [loj2470]有向图

    参考ExtremeSpanningTrees,考虑优化整体二分时求$g_{i}\in \{w_{mid},w_{mid+1}\}$的最优解 对于$m=n-1$的问题,不需要去网络流,可以直接树形dp ...

  5. try catch引发的性能优化深度思考

    关键代码拆解成如下图所示(无关部分已省略): 起初我认为可能是这个 getRowDataItemNumberFormat 函数里面某些方法执行太慢,从 formatData.replace 到 une ...

  6. 7.4 k8s结合ceph rbd、cephfs实现数据的持久化和共享

    1.在ceph集群中创建rbd存储池.镜像及普通用户 1.1.存储池接镜像配置 创建存储池 root@u20-deploy:~# ceph osd pool create rbd-test-pool1 ...

  7. 雪花算法对System.currentTimeMillis()优化真的有用么?

    前面已经讲过了雪花算法,里面使用了System.currentTimeMillis()获取时间,有一种说法是认为System.currentTimeMillis()慢,是因为每次调用都会去跟系统打一次 ...

  8. P5509 派遣

    题面传送门. 数论小杂烩( 由题意,对于每个士兵 \(i\),要么选,对答案产生 \(a_i(\frac{x}{i-x})\) 倍的贡献,要么不选,对答案产生 \(1\) 倍的贡献. 由此可知每个士兵 ...

  9. DirectX12 3D 游戏开发与实战第十章内容(上)

    仅供个人学习使用,请勿转载.谢谢! 10.混合 本章将研究混合技术,混合技术可以让我们将当前需要光栅化的像素(也称为源像素)和之前已经光栅化到后台缓冲区的像素(也称为目标像素)进行融合.因此,该技术可 ...

  10. 如何利用efetch从NCBI中批量下载数据?

    目录 找序列 下序列 假设我要从NCBI中下载全部水稻的mRNA序列,如何实施? 找序列 第一步,肯定是找到相关序列. 我从ncbi taxonomy进入,搜索oryza.因为要搜索mRNA核酸序列, ...