Jenkins代码发布流程
前面已经对jenkins界面有了一些大概的介绍,jenkins可以干很多事情,当前其中很重要的一项就是发布代码,当然发布代码的方式也有一些不同,下面我们就一个开源项目做一次发布。
一、job的简单创建
1.1 实现代码的构建
#我们先什么都jenkins页面化操作,所以先需要安装一个Maven Integration插件,因为我们先拿一个MVC框架的java程序入手。
创建job:

配置job:

#如果出现下面的报错,就是git地址没有代码拉取权限或者git地址真心配置的不对:
Failed to connect to repository : Command "git.exe ls-remote -h https://github.com/youzan/bugCatcher/tree/master.git HEAD" returned status code 128:
stdout:
stderr: remote: Not Found
fatal: repository 'https://github.com/youzan/bugCatcher/tree/master.git/' not found

#注意这里一般就是mvn clean install,这样能保证每次编译的时候依赖包是最新的。这里有一篇关于mvn clean install和mvn install的区别的文章:
https://blog.csdn.net/qq_38245537/article/details/78563284?locationNum=4&fps=1
#当然一般都会跳过单元测试:
mvn clean install -DskipTests
或者
mvn clean install -Dmaven.test.skip=true
#当然也可以在pom.xml文件中标注跳过单元测试:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
#很多时候环境分开发测试环境、qa测试环境、正式上线环境,所以呢可能连接的数据库啊等一些上游地址是不同的,如何实现呢,就是maven的profile构建不同环境配置.
#例如在pom.xml文件中配置:
<profiles>
<!-- 开发 -->
<profile>
<!-- profile的id -->
<id>dev</id>
<properties>
<env>src/main/resources/dev</env>
<env.name>develop</env.name>
</properties>
<activation>
<!-- 默认激活此配置 -->
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<!-- 测试 -->
<profile>
<id>test</id>
<properties>
<env>src/main/resources/test</env>
<env.name>test</env.name>
</properties>
</profile>
<!-- 线上 -->
<profile>
<id>online</id>
<properties>
<env>src/main/resources/online</env>
<env.name>online</env.name>
</properties>
</profile>
</profiles>
#上面pom.xml这样配置以后,然后在源代码的src/main/resources目录下面分别创建dev,test,online这三个不同的目录,然后目录里面分别创建同名文件但是里面的db连接之类的不同。
#然后在编译的时候执行:
线上环境:mvn clean install -P online -Dmaven.test.skip=true
测试环境:mvn clean install -P test -Dmaven.test.skip=true
编译测试:
#上面就是一个最简单的编译,编译一下。

#再看下界面的数据,太长只截取部分(点击控制台输出就可以查看完整的构建过程)。
#先看错误的输出:

#再看成功的输出:


博文来自:www.51niux.com
查看下载jar包的位置目录:
#因为我们是115节点执行的编译操作,所以要上115上面去查看。
# vim /usr/local/apache-maven/conf/settings.xml
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
|
| Default: ${user.home}/.m2/repository
<localRepository>/path/to/local/repo</localRepository>
-->
#从上面的内容可以看出来走的默认${user.home}/.m2/repository
# ls -l /home/work/.m2/repository/ #所有下载的jar包都在这个目录下面
总用量 0
drwxrwxr-x. 3 work work 25 11月 3 18:55 aopalliance
drwxrwxr-x. 4 work work 35 11月 3 19:20 asm
drwxrwxr-x. 3 work work 38 11月 3 19:21 backport-util-concurrent
drwxrwxr-x. 3 work work 17 11月 3 18:56 ch
drwxrwxr-x. 3 work work 25 11月 3 18:57 classworlds
drwxrwxr-x. 5 work work 54 11月 3 19:20 com
drwxrwxr-x. 3 work work 31 11月 3 18:56 commons-beanutils
drwxrwxr-x. 3 work work 25 11月 3 18:57 commons-cli
drwxrwxr-x. 3 work work 33 11月 3 19:20 commons-collections
drwxrwxr-x. 3 work work 30 11月 3 19:20 commons-digester
drwxrwxr-x. 3 work work 24 11月 3 19:20 commons-io
drwxrwxr-x. 3 work work 26 11月 3 19:20 commons-lang
drwxrwxr-x. 3 work work 29 11月 3 18:55 commons-logging
drwxrwxr-x. 3 work work 31 11月 3 19:20 commons-validator
drwxrwxr-x. 3 work work 28 11月 3 19:21 doxia
drwxrwxr-x. 6 work work 72 11月 3 18:56 javax
drwxrwxr-x. 3 work work 19 11月 3 18:56 junit
drwxrwxr-x. 3 work work 34 11月 3 18:55 mysql
drwxrwxr-x. 3 work work 16 11月 3 18:56 net
drwxrwxr-x. 12 work work 165 11月 3 18:57 org
drwxrwxr-x. 3 work work 17 11月 3 19:20 oro
drwxrwxr-x. 3 work work 22 11月 3 19:20 xml-apis
drwxrwxr-x. 3 work work 22 11月 3 19:00 xpp3
# ls -l /home/work/.m2/repository/org/slf4j/slf4j-api/1.7.5/ #这是根据上面截图最后一个jar包的url找的其所在位置,可以看到其目录结构就跟URL一样。
总用量 96
-rw-rw-r--. 1 work work 235 11月 3 19:27 _remote.repositories
-rw-rw-r--. 1 work work 26084 11月 3 18:57 slf4j-api-1.7.5.jar
-rw-rw-r--. 1 work work 40 11月 3 18:57 slf4j-api-1.7.5.jar.sha1
-rw-rw-r--. 1 work work 2689 11月 3 18:56 slf4j-api-1.7.5.pom
-rw-rw-r--. 1 work work 40 11月 3 18:56 slf4j-api-1.7.5.pom.sha1
-rw-rw-r--. 1 work work 47186 11月 3 19:27 slf4j-api-1.7.5-sources.jar
-rw-rw-r--. 1 work work 40 11月 3 19:27 slf4j-api-1.7.5-sources.jar.sha1
#为什么要展示这里,因为java编译就是依赖于各种各样的jar包,你不了解这层关系以后在编译报错排错的时候就稍微有点费劲,很多时候可能是依赖包问题导致编译失败。
查看编译出来的jar包:
# ls -l /data/jenkins_workspace/workspace/bugCatcher----Permission-sandbox-mvc-single/ #首先先看这个目录,这就是我们创建的job名称,下面直接就是代码了,所以没有git组的概念你也看不出下面是什么git地址的代码
总用量 32
-rw-rw-r--. 1 work work 18804 11月 3 18:16 pom.xml
drwxrwxr-x. 2 work work 228 11月 3 18:16 README
-rw-rw-r--. 1 work work 4891 11月 3 18:16 README.md
-rwxrwxr-x. 1 work work 167 11月 3 18:16 setup.sh
drwxrwxr-x. 4 work work 30 11月 3 18:16 src
drwxrwxr-x. 10 work work 231 11月 3 21:14 target
# cd /data/jenkins_workspace/workspace/bugCatcher----Permission-sandbox-mvc-single/
# ls -lh target/
总用量 12M
drwxrwxr-x. 9 work work 134 11月 3 21:14 classes
drwxrwxr-x. 2 work work 4.0K 11月 3 21:14 dependency-maven-plugin-markers
drwxrwxr-x. 3 work work 25 11月 3 21:14 generated-sources
drwxrwxr-x. 3 work work 30 11月 3 21:14 generated-test-sources
drwxrwxr-x. 2 work work 28 11月 3 21:14 maven-archiver
drwxrwxr-x. 5 work work 71 11月 3 21:14 pfcase
-rw-rw-r--. 1 work work 34K 11月 3 21:14 pfcase-sources.jar
-rw-rw-r--. 1 work work 12M 11月 3 21:14 pfcase.war #这就是最后编译出来的war包,要丢到tomcat的webapps目录下面的。
drwxrwxr-x. 2 work work 6 11月 3 21:15 surefire
drwxrwxr-x. 3 work work 17 11月 3 21:14 test-classes
#为什么是pfcase.war而不是ROOT.war包呢,就得看下面的pom.xml文件了。
# vim pom.xml
<build>
<finalName>pfcase</finalName>
</build>
1.2 将构建好的war包发布到指定机器上面去
将war包发到指定机器上面去:

#直接看通知台数据看最后的结果吧,都是文字就不截图了省点带宽:
channel stopped
[bugCatcher----Permission-sandbox-mvc-single] $ /bin/bash /tmp/jenkins4595475323755118241.sh
inet 192.168.1.115 netmask 255.255.255.0 broadcast 192.168.1.255
Set build name.
New build name is '#13'
Finished: SUCCESS
#通过测试我们可以明确如果job里面制定了从节点,那么shell里面的操作发起者就是哪台机器。
被发布机查看一下:
#登录192.168.1.151这台机器。
$ ls -l /usr/local/tomcat/webapps/
总用量 11832
drwxr-x---. 14 work work 4096 11月 3 19:21 docs
drwxr-x---. 6 work work 83 11月 3 19:21 examples
drwxr-x---. 5 work work 87 11月 3 19:21 host-manager
drwxr-x---. 5 work work 103 11月 3 19:21 manager
drwxr-x---. 5 work work 71 11月 3 22:07 pfcase #可以看到已经将war解压成指定的目录了。
-rw-rw-r--. 1 work work 12109266 11月 3 22:07 pfcase.war #可以看到这是做好的war包
drwxr-x---. 3 work work 283 11月 3 19:21 ROOT
#访问url:192.168.1.151:8080/pfcase/

#通过web结果看到代码发布成功了,页面也正常的显示出来了,当然是否完全OK不确定,还要查看日志或者访问指定的探测接口之类的。
二、针对上面的job做一些优化
2.1 发布主机应该改成参数的形式
#上面scp主机写死了IP的形式,要发布哪个主机应该是由发布者来定的。而且war包所在的目录写死了明显也不合适。

#先来个参数化构建

#这样的话基本都是变量适用性就会好很多。

2.2 优化Build History的输出
现在构建历史哪里只是数字号码排序,也看不出来是谁发布的,发布的哪个主机等等,好的那就再改一改。

#下面分别用两个用户发布,然后看看效果:

#这就很明显了哪个用户做的什么事一眼就看出来了,当然还可以继续加变量,系统不自带就自定义就行。
2.3 可以选择指定的版本发布而不是发布最新的代码
先设置一下:
#首先要安装插件:Git parameter,不然参数化构建哪里没有这一项。


#要注意如果你只是这样设置了,不拿着$release_tag这个变量去做点事情发布的依旧是最新的代码,所以还要进入到工作空间里面进行git checkout操作。

下面验证一下:

下面直接在115机器上面看一下:
$ pwd
/data/jenkins_workspace/workspace/admobadapter----Permission-sandbox-java-single
$ git status
# 头指针分离于 v1.4.5
无文件要提交,干净的工作区
2.4 jenkins来点提示信息
jenkins发布出问题该找谁,出现的报错信息应该看什么链接等等,一些提示信息怎么展示呢?


博文来自:www.51niux.com
2.5 Jenkins发布邮件通知
jenkins发布时发布了,但是发布是否成功并且谁发布的什么时候发布的,只有操作jenkins的人知道,其他人并不知情,怎么让发布通知出来呢?
#这里先来一个最简单的: Jenkins配置邮件通知。(当然做技术的都知道邮箱基本被各种信息填满所以发邮件并不是一个多好的方式)
配置邮箱服务器:
系统管理=》系统设置

#注意上图中的Reply-To-Address如果只是用于job发布失败报警可以不填。
#上面有个验证报错,要注意的是我这里其实都填OK了但是还提示下面的报错:
Failed to send out e-mail
com.sun.mail.smtp.SMTPSenderFailedException: 553 Mail from must equal authorized user
at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:1587)
Caused: com.sun.mail.smtp.SMTPSendFailedException: 553 Mail from must equal authorized user
;
nested exception is:
com.sun.mail.smtp.SMTPSenderFailedException: 553 Mail from must equal authorized user
at com.sun.mail.smtp.SMTPTransport.issueSendCommand(S80)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1097)
#上面的报错是因为好少了一个管理员邮箱,那里没有填写,当然填写的邮箱用户跟上图中的是一致的:

job配置邮件发送:
构建后操作==》E-mail Notification

找个job发布测试一下:

看眼邮件的大概内容(jenkins地址以及发布信息):
See <http://192.168.1.104:8080/jenkins/job/admobadapter----Permission-sandbox-java-single/13/display/redirect>
------------------------------------------
Started by user admin
Building remotely on jdk_salve_115 in workspace <http://192.168.1.104:8080/jenkins/job/admobadapter----Permission-sandbox-java-single/ws/>
> /usr/bin/git rev-parse --is-inside-work-tree # timeout=10
Fetching changes from the remote Git repository
> /usr/bin/git config remote.origin.url https://github.com/clockbyte/admobadapter.git # timeout=10
Fetching upstream changes from https://github.com/clockbyte/admobadapter.git
> /usr/bin/git --version # timeout=10
> /usr/bin/git fetch --tags --progress https://github.com/clockbyte/admobadapter.git +refs/heads/*:refs/remotes/origin/*
2.6 Jenkins使用email-ext替换Jenkins的默认邮件通知
#先要安装插件:Email Extension
#还有管理员邮箱还是要继续设置的不然依旧是不能发送邮件的。
全局配置:


#上面要注意的是收件人都是可以写多个收件人的就是逗号隔开就行
Default Content(这里就是一个HTML页面了,下面为具体内容):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
</head>
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
<tr>
<td>(本邮件由程序自动下发,无需回复!)</td>
</tr>
<tr>
<tr>
<td>
<h2><font color="#FF0000">构建结果 - ${BUILD_STATUS}</font></h2>
</td>
</tr>
<tr>
<td><br />
<b><font color="#0B610B">构建信息</font></b>
<hr size="2" width="100%" align="center" />
</td>
</tr>
<tr><a href="${PROJECT_URL}">${PROJECT_URL}</a>
<td>
<ul>
<li>项目名称:${PROJECT_NAME}</li>
<li>GIT路径:<a href="${GIT_URL}">${GIT_URL}</a></li>
<li>构建编号:${BUILD_NUMBER}</li>
<li>触发原因:${CAUSE}</li>
<li>构建日志:<a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
</ul>
</td>
</tr>
<tr>
<td>
<b><font color="#0B610B">变更信息:</font></b>
<hr size="2" width="100%" align="center" />
</td>
</tr>
<tr>
<td>
<ul>
<li>上次构建成功后变化 : ${CHANGES_SINCE_LAST_SUCCESS}</a></li>
</ul>
</td>
</tr>
<tr>
<td>
<ul>
<li>上次构建不稳定后变化 : ${CHANGES_SINCE_LAST_UNSTABLE}</a></li>
</ul>
</td>
</tr>
<tr>
<td>
<ul>
<li>历史变更记录 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a