相关文章:Springboot 单元测试 Junit 深度实践
1. CI 的重要性
随着 devops 的快速发展,很多公司都已经将 devops 实践到日常运维工作中,devops 从以前最简单的写个 shell 脚本部署数据库、部署应用服务器到现在的从代码提交、项目构建、自动化测试等都有机结合了起来,这样的自动化大大减少了运维人员的工作压力,也减少了运维人员在工作中的人工失误导致的投产事故。
原来在中国银行是从 13 年开始实践 CI 的,其中用的 CI 框架就是Jenkins,当时是在笔者所在的开放平台团队试点,经过了半年的试点就感受到了 CI 带来的魅力,主要感受体现在以下几点:
1)部署速度更快了:当时我们使用的服务框架是 dubbo,所有的服务都注册在了 zk 上,大大小小服务加起来也有几十个,再加上每个服务多机互备,导致每次部署版本需要花费很长时间,因为当时没有上生产运维自动化部署,所以快速部署的优势只能体现在我们开发环境上,上了 CI 之后部署就是真的一键部署,非常方便,完全不用担心部署错了。这里说明下后来我呆过的一家电商生产环境也通过 CI 部署,将近 100 个系统,运维部署人员只有 3 个,而且每次投产都是喝着咖啡投产很惬意,有时甚至直接在家部署版本。
2)代码质量提升了:上了 CI 后因为大家提交的代码都要通过 checkstyle、findbugs 进行代码静态复查,谁都不愿意在 CI Sonar 报表里看到自己的代码一堆警告吧,为了面子也要尽自己最大怒力把代码写规范了,代码按照要求写规范了,低级问题不再发生,代码质量自然提升上去了。
3)回归测试更快了:CI 之后,通过增加单元测试和集成功能测试能够在每次提交代码触发自动化回归测试,让每次提交的代码都通过了单元测试和自动化集成测试,再次保证了提交的代码都是经过回归测试的。
好了说了那么多 CI 的优点,现在回归正题,这篇文章主要是讲下通过Jenkins如何把我们常用的 Springboot 项目运行起来,这个流程不单单适用于 Springboot 项目,同样适用于其他的项目,只是在 build 和部署的时候会有一些差异,这里我们在 CI 过程中构建用的是 maven、源码仓库用的是 Git,对于用 Ant、Gradle 构建的朋友需要装下相关的插件。
2. Jenkins 的安装
war 包直接运行,部署到 tomcat 等应用服务器中,安装包直接安装
安装完成后需要更新 plugin 插件
3. 创建 Maven 自动化部署任务
安装完成之后就可以开始创建 CI 任务了,这次我们创建的 CI 任务主要是完成从 Git 上拉取最新的源码、对源码进行编译、将编译后的 jar 、war 部署到服务器,下面就开始详细介绍下整个过程细节。
1)创建一个构建 Maven 项目
Screenshot 2018-08-17 10.55.21
点击 jenkins 左侧的新建按钮之后会展示新建页面,这里会展示一些模版,因为笔者使用的是 Maven 构建的项目,所以这里选择了第二个 Maven 构建模版,这个模版会自动帮你创建一些 maven 项目常用的步骤,如果在列出来的模版中没有你需要的构建模版,可以使用第一个选项,构建一个自由风格的软件项目,这个选项的模版中所有的作业步骤都可以自己进行定制,很方便。
2)配置 Git 下载源码
Screenshot 2018-08-17 11.00.38
先在 Repository URL 输入需要构建的项目的 git 地址,这里的地址可以是 github 这类公有的 git 仓库也可以是公司私有的 git 仓库,配置好了项目源码地址,还需要点击 Add 按钮配置 Credential,可以采用 username+password 方式或者 usrname+private key,类似于我们在自己的客户端更新 git 代码,同时别忘了配置 branch,git 默认是 master 分支,这里也可以做成参数化,后面会简单介绍下如何在 jenkins 里参数化一些东西,让整个构建更加灵活。
如果整个项目中涉及到多个 repo,那就需要点击图片右下角的 Add Repository 按钮进行创建其他的 repo 地址和 credential。
这里单独说下上面提到的需要配置 Credential,Credential 的配置需要在首页点击左侧的 Credentials 按钮
Screenshot 2018-08-17 11.06.32
这是配置好不同 repo 的页面,其中图标是小钥匙的是通过配置私钥方式创建的 Credential,图标是用户头像下面有些密码的图标是通过用户名密码创建的 Credential。因为很多 git 私服是没有配置用户名密码 pull 代码的,所以只能配置通过机器私钥 pull 代码,在配置用户名密码过程中一直失败的朋友,一定要看下是不是 git 服务器只支持通过私钥获取代码。
2)配置 JDK、Maven 版本;
下面就是配置 JDK 和 Maven 了,大家需要在Jenkins服务器上安装 JDK 和 maven,具体的如何安装 JDK 和 Maven 应该不用再介绍了吧。
在Jenkins机器都装好 JDK 和 Maven 后,还需要在Jenkins里配置下 JAVA_HOME 和 MAVEN_HOME 的环境变量,这样Jenkins构建的时候才能找到你项目需要的 JDK 版本和 Maven 版本,这里 JDK 是可以配置多个的,毕竟所有项目不可能使用一样的版本编译。
这些都是在系统管理中进行配置,具体如何配置就不讲了,太简单了,看图就知道了,就是配个 JDK 和 MAVEN 在服务器的路径,很简单。
Screenshot 2018-08-17 11.26.33
3)build 工程
Screenshot 2018-08-17 12.07.45
4)配置 ssh
大家回想下我们一般编译好项目后会怎么去部署 sprigboot 的版本?当然是把编译后的 jar 或 war 包发送到待部署服务器。可以通过配置 ssh,jenkins 就可以自己登陆到远程服务器然后执行后续的部署命令了。
配置 ssh 也比较简单,在首页找到左侧的系统设置,点进去后一直往下拉找到“Publish over SSH”,然后配置远程服务器的 HostName/IP 地址、username 和密码。配置好以后可以点击右下角的“Test Configuration”验证 ssh 配置是否有效。
Screenshot 2018-08-17 13.32.20
5)远程部署
配置好 ssh 后我们再回到刚才建的 Maven 任务的配置页面,找到 Post Steps 模块点击 Add post-build step 后从列表中选择 Send files or execute commands over SSH,这时候需要在弹出菜单中选择一个配置的 SSH 服务器并选择编译好的 jar 或 war 文件,最后就是在 SSH 登陆的服务器上执行的 shell 命令了。
Screenshot 2018-08-17 12.08.09
在“Name”中选择刚才配置的 ssh 配置;在“Source files”中输入项目编译后 jar、war 保存的相对路径地址和文件名,注意这里的相对路径是相对于项目的根目录来的,maven 项目一般都在 target 下;接下来“Remove prefix”就是用来配置去掉上一步配置的待部署文件的路径地址的,这样 jenkins 就能够知道具体的要传输的文件名了;“Remote directory”就是配置需要传输的目标地址的相对路径,这个相对路径是相对于在 ssh 中配置的用户的根目录来的;最后需要配置的就是“Exec command”就是在文件传输后需要执行的 shell 命令,这里可以将要远程执行的命令直接维护在这里,也可以将部署和运行 springboot 项目的命令写在 shell 里,我还是比较习惯于将这些启动信息维护在服务端的 shell。下面就给下这个 shell 的源码,大家要用的话改成自己的路径和文件名就可以了,代码很简单就是先配置好 jdk 环境变量,备份之前的执行码,然后通过 ps 找到正在运行的执行码进程编号,然后通过 kill 命令杀掉这个进程,再启动新编译的 jar、war。
DATE=$(date +%Y%m%d)
export JAVA_HOME PATH CLASSPATH
JAVA_HOME=/usr/lib/jvm/jdk-8u144-linux-x64/jdk1.8.0_144(改成自己的 JDK 路径)
PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$CLASSPATH
DIR=/root/xxxxx(需要修改为你项目待拷贝和运行的目录)
JARFILE=xxxxx-0.1.jar
if [ ! -d $DIR/backup ];then
mkdir -p $DIR/backup(改成自己需要将原执行码备份的路径)
fi
cd $DIR
ps -ef | grep $JARFILE | grep -v grep | awk '{print $2}' | xargs kill -9
mv $JARFILE backup/$JARFILE$DATE
mv -f /root/Jenkins-in/$JARFILE .
java -jar $JARFILE > out.log &
if [ $? = 0 ];then
sleep 30
tail -n 50 out.log
fi
cd backup/
ls -lt|awk 'NR>5{print $NF}'|xargs rm -rf
都配置好后保存就可以了,后续还可以通过 pre、post step 增加很多其他步骤,例如静态代码复查、单元测试、集成测试、邮件通知等等,这里就不详细介绍了,大家可以根据自己项目需要自己摸索,不是很难。
4. 运行 CI 任务
运行 CI 任务就很简单了,直接在首页面板找到你刚才配置的任务,点击左侧的立即执行就可以了,通过 Console Output 可以查看任务运行的日志,如果运行报错也会在这里有所体现错误日志。
Screenshot 2018-08-17 13.49.52
5.其他常用配置
这里再介绍几个常用到的配置,会对日常的 CI 工作很有帮助。
参数化构建
我们在日常开发过程中一般都会有多套环境,开发、sit、uat、生产等等,那么我们是否要配置多个 CI 任务呢?答案当然是不需要,如果配置那么多环境,那么多项目乘上那么多环境,那是要有多少 CI 任务啊,Jenkins 很贴心的提供了参数化构建功能,只要在任务配置中点选参数化构建,就可以通过添加参数来完成不同环境的部署。
实现参数化部署的前提当然也是我们开发的项目配置文件已经分环境配置了,不是那种低端的都写在一个配置文件里,通过注释手工切环境那种。springboot 的项目我们可以通过配置不同的 profile 来切换使用不同的环境参数,这里只需要配置不同环境的 ssh 和 java 启动命令中的 profile 就可以了,将这些都参数化,在运行的时候选择不同环境进行构建就行了。
Screenshot 2018-08-17 12.06.44
超时配置
在日常构建过程中功能,单机版的 Jenkins 构建任务都是串行的,所以如果一个任务卡住了那么会影响到后续任务的正常构建所以一般我们需要配置下任务的超时时间和超时后的动作,这样就能保证后续任务在一定时间内被执行到。
当然你也可以配置 Jenkins 主从版,这样各个团队可以在自己的从服务器构建,最后将结果汇总到主服务器,这样各个团队都不会互相影响。
Screenshot 2018-08-17 12.06.00
丢弃构建
之前项目组就遇到过 CI 这台服务器很快磁盘空间就满了,后来看了下原来是因为很多项目没有设置丢弃策略,这里建议大家还是配置下比较好,jenkins 默认是不丢弃,那么日记月累还是会有很多构建后的文件的。
Screenshot 2018-08-17 12.05.28
后话
自动化部署只是持续集成中的关键一步,通过自动化构建和部署已经能够很大程度上的缩减我们的代码构建和版本部署的人力了,整个持续集成还涉及到很多内容,文章开篇也提到了还涉及到单元测试、自动化功能测试等,单元测试也是整个工程活动中非常重要的一步,后面我也会好好介绍下单元测试,这个让程序猿又爱又恨的东西,单元测试用好了以后也会对整个代码质量有质的提高,敬请期待。
——————————————-课程推荐时间————————————————–
今天写的 Jenkins 自动化部署是 CI 持续集成的一部分,现在持续集成在国内大厂已经做得非常好了,很多传统 IT 企业也在开始实施持续集成,之前我所在的一家国企银行当时为了做持续集成可以花了很大的人力物力,当时没有人指导我们怎么做,只有找外部咨询,当时是找了 thoughtworks,花了很多钱,但是效果一般,今天给大家推荐的课程是携程的系统研发部总监王潇军的持续交付的课程,笔者已经看了 10 篇,对于要做持续集成的小伙伴来说确实都是干货,推荐大家学习学习,也就两顿饭的钱,绝对是物超所值的,都是国内互联网大厂的经验之谈,会解决你很多困惑,课程包含了分支管理策略、测试环境自动化管理、自动化构建集成、自动化发布监控、测试管理、持续交付等等,内容相当充实。