Java代码自动部署
【 ①Java代码自动部署-总结简介】
代码部署是每一个软件开发项目组都会有的一个流程,也是从开发环节到发布功能必不可少的环节。对于Java开发者来说,Java代码的发布部署也是经常需要做的一件事,特别是互联网公司。代码的发布上线关系到保证生产环境能够正常启动及功能是否能正常运行,所以代码部署在整个项目开发周期还是占据很重要的地位。
由于本人近期在学习Java代码自动发布相关的知识,此系列文章是对此次学习到的知识进行巩固和总结;同时,也希望能够帮助到和我一样对此方面知识感兴趣的同行们。言不多说,直接进入真题。下面针对此次系列文章做一个简要的概述。
1、学习代码自动部署的目的
高效且简化代码的部署发布
2、使用的相关工具及技术
1、 CentOS操作系统(可以使用虚拟机安装Linux系统)
2、 Maven
3、 Git
4、 Shell脚本
5、 Jenkins
3、学习代码自动发布相关技术的顺序
阶段1:
优点:部署流程简单方面,开发完成后开发人员在开发环境即可进行代码部署上线。
缺点:发布流程粗糙,代码部署不够严谨,不建议生产环境使用此方式。
阶段2:
优点:由Git进行项目版本管理,降低了代码发布的风险,发布过程有运维人员进行发布。
缺点:由于代码的发布由运维人员发布,需开发人员配合进行代码发布部署,与发布部署不成功,得由开发人员查找问题,增加了部署复杂性。
阶段3:
优点:由Jenkins工具进行代码的发布部署,规范了代码的发布流程,提供可视工具监听整个发布流程等。
缺点:对技术要求更高了,需要了解Jenkins工具,会编写Shell脚本等。
4、Java代码自动部署总结分为以下系列
①总结简介
②使用Maven进行代码部署
③使用Shell进行代码部署
④使用Jenkins进行代码部署
⑤课程总结及心得
【 ②使用Maven进行代码部署】
在使用maven进行代码发布的时候,需要用Maven工具的相关插件将需要部署的项目发布到指定的服务器的部署目录中。
在学习此技术时,我用的的是一个秒杀项目的ssm版,大家在学学习此技术的时候可以用简单一点的Maven项目进行测试。因本项目是学习如何进行部署项目技术的,本次就针对具体项目进行介绍。
1、 使用Maven进行部署项目要求
1) 项目本身属于Maven项目(必要条件)
2) 需要部署的是war包
3) 引入插件
在需要部署的项目的pom,xml文件中引入tomcat插件,在project->build-> plugins节点引入tomcat插件。
<build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <!-- 引入tomcat插件 --> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <!-- <url>http://localhost:8080/manager</url> --> <!-- tomcat6部署管理路径 --> <url>http://192.168.25.133:8080/manager/text</url> <!-- tomcat7部署管理路径 --> <!-- tomcat控制台账号 --> <username>admin</username> <!-- tomcat的管理员账号 --> <!-- tomcat控制台密码--> <password>admin</password> <!-- 本地运行时指定的端口号 --> <port>8080</port> <path>/seckill-manager</path> <!-- 部署路径 --> <charset>UTF-8</charset> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> |
4) 执行Maven的redeploy操作
执行的命令:tomcat7:redeploy
在eclipse下配置的命令如下:
2、需要注意的问题点
1、在将项目发布到远程Tomcat时需要启动远程Tomcat管理控制台账号
开启tomcat管理控制台账号地址为:Tomcat安装目录/conf/tomcat-users.xml文件
在tomcat-users.xml文件中需要配置允许访问纯文本接口权限,以便maven的tomat插件能够通过此方式进行部署项目。
在tomcat-users节点新增role属性和user属性,如下:
<role rolename="manager-script" /> <role rolename="manager-gui"/> <user username="admin" password="admin" roles="manager-gui,manager-script"/> |
解释:给账号admin配置manager-script及manager-gui权限
Tomcat角色解释图:
2、在需要远程发布到的目标Tomcat应该是运行状态,保证Maven的tomcat插件能够访问到目标Tomcat完成项目的部署。
【③使用Shell进行代码部署】
在使用Shell脚本进行重新部署项目时,需要掌握Shell脚本的编写,Shell脚本需要完成以下功能:
1、 将代码clone到服务器指定目录
2、 根据pom.xml文件将代码打包成war包
3、 将war发布到指定服务器
环境要求:
1、 安装Maven并配置环境变量
2、 Git客户端,并配置环境变量
3、 熟悉Shell脚本相关知识
1、编写Shell脚本
在Linux的指定目录新建shell脚本,我是在项目的专用tomcat根目录新建了shell脚本,方便进行tomcat集群部署操作。脚本内容如下:
#!/bin/bash #shell功能概要:seckill的service提供者构建shell #发布service提供者的服务器的进程名 serverName="seckill_provider" #获取发布service提供者的服务器的进程PID PID=$(ps -ef | grep $serverName | grep -v grep | awk '{ print $2 }') #java代码本地仓库地址 javaBaseSrc="/opt/java_project_src/" #项目路径 javaProjectSrc="sekill/seckill-manager/seckill-service/target/seckill-service.war" #发布的tomcat集群,数组方式存储 projectServicersPath=(/opt/seckill-tomcat/seckill-tomcat-02 /opt/seckill-tomcat/seckill-tomcat-03) projectName="sekill" #循环强制停止指定tomcat for var in ${PID}; do echo "准备强制停止PID:$var" kill -9 $var done echo "kill $serverName sucess" #切换到git本地仓库目录 cd $javaBaseSrc #删除仓库库中代码 rm -rf $projectName echo "从/opt/java_project_src仓库中删除项目$projectName成功" #从远程仓库下载代码,因涉及到账户信息,此处更改为描述信息 git clone 远程git仓库项目URL cd $javaBaseSrc/sekill/seckill-manager #安装项目并跳过测试 mvn -Dmaven.test.skip=true clean install #判断执行上面mvn操作的返回值是否为0 if [ $? -ne 0 ] then echo "构建失败,请查看代码问题!" exit 1; fi #循环将项目部署到集群tomcat中 for projectServicer in ${projectServicersPath[@]} do cp $javaBaseSrc$javaProjectSrc $projectServicer/webapps echo "$projectServicer 代码发布成功!" sh $projectServicer/bin/startup.sh if [ $? -ne 0 ] then echo "$projectServicer 启动失败" exit 1; else echo "$projectServicer 启动成功"; fi done echo "启动 $serverName 成功" |
2、需要注意的问题点
在编写Shell脚本时需要知道每句Shell的含义,尽可能将所有问题点都能考虑到,比如:
a) 强杀进程问题
进行PID=$(ps -ef | grep $serverName | grep -v grep | awk '{ print $2 }')时,要确定查询的只是目标Tomcat的进程pid,防止在后续强制停止时将其他应用Tomcat误强行停止,这里建 议给每一个目标Tomcat设置指定的进程名,设置方法为:
在指定tomcat的bin/ setclasspath.sh文件中找到if [ -z "$_RUNJAVA" ]判断语句,进行以下设置即可
if [ -z "$_RUNJAVA" ]; then #_RUNJAVA="$JRE_HOME"/bin/java cp "$JAVA_HOME/bin/java" "$JAVA_HOME/bin/seckill_consumer01" _RUNJAVA="$JRE_HOME/bin/seckill_consumer01" fi |
b) Shell脚本尽可能通用
我吸取了现在比较流行的一句话“约定大于配置”及平时所看所想,在编写Shell脚本时可以提取可变或多处使用的变量,使整个Shell脚本尽可能提炼成通用,以便类似项目部署可以使用现有脚本进行更改后使用,减少重新编写新Shell脚本带来不可控的问题。
【④使用Jenkins进行代码部署】
在使用Jenkins进行项目部署时,需要将Jenkins的war包放在服务器的指定位置。Jenkins的war的下载可以去Jenkins的官网进行下载。
使用Jenkins进行代码部署时需要的环境支持:
1、安装Maven并配置环境变量
2、Git客户端,并配置环境变量
3、熟悉Shell脚本相关知识
4、对Jenkins有一定了解
使用Jenkins进行代码部署如下:
1、 启动Jenkins工具
在jenkins.war目录执行以下命令操作启动Jenkins工具。
[xiongshx@localhost jenkins]$ java -jar jenkins.war
Jenkins工具初始化的一些操作可以百度或者去Jenkins查看可以参考【https://www.cnblogs.com/cheng95/p/6542036.html】
初始化后需要进行的配置
工具配置
【系统管理】->【全局工具配置】
Jdk配置:
Git配置:
Maven配置:
2、 新建任务
需要注意的点:
1、填写源码仓库地址
2、构建时操作及自定义shell代码
Shell代码如下:
#!/bin/bash #shell功能概要:seckill的Web消费者构建shell #引用的技术有:git、maven #发布web消费者的服务器的进程名 serverName="seckill_consumer" #获取发布web消费者的服务器的进程PID PID=$(ps -ef | grep $serverName | grep -v grep | awk '{ print $2 }') #需要在脚本开始时添加export BUILD_ID=dontKillMe。 #原因:因为Jenkins执行完当前任务之后需要执行下一个任务,此时Jenkins会直接把tomcat进程杀掉, #因此在脚本中编写的tomcat启动命令是不会执行的。 export BUILD_ID=dontKillMe #java代码本地仓库地址 javaBaseSrc="/home/xiongshx/.jenkins/workspace/" #项目路径 javaProjectSrc="seckill/seckill-web/target/seckill-web.war" #发布的tomcat projectServicersPath=(/opt/seckill-tomcat/seckill-tomcat-01) projectName="sekill" for var in ${PID}; do echo "准备强制停止PID:$var" kill -9 $var done echo "kill $serverName sucess" #如果上一个命令执行失败,执行的状态码不为0 if [ $? -ne 0 ] then echo "构建失败,请查看代码问题!" exit 1; fi for projectServicer in ${projectServicersPath[@]} do cp $javaBaseSrc$javaProjectSrc $projectServicer/webapps echo "$projectServicer 代码发布成功!" /bin/bash $projectServicer/bin/startup.sh if [ $? -ne 0 ] then echo "$projectServicer 启动失败" exit 1; else echo "$projectServicer 启动成功"; fi done echo "启动 $serverName 成功" |
3、 启动项目
【立即构建】->【点击构建的链接】->【控制台输出】即可查看整个代码部署过程中的信息输出。
4、需要注意的问题点:
1、Jenkins的war问题
最简单jenkins.war的启动方式是在控制台终端执行命令:java -jar jenkins.war;但是此方法会占用一个终端窗口,且关闭后Jenkins工具就不能进行访问,可以使用命令进行后台执行,命令如下:
nohup java -jar jenkins.war --httpPort=9090 > /dev/null 2>&1 &
命令解释:
nohup 后台执行操作
--httpPort=9090表示指定占用9090端口进行访问
> /dev/null 将日志输出到/dev/null
2>&1 & 用来将标准错误2重定向到标准输出1中的此处1前面的&就是为了让bash将1解释成标准输出而不是文件1。最后一个&,则是让bash在后台执行。
另外一种更优雅的方式是使用Shell脚本控制Jenkins工具的启动、停止、重启等操作。
样例如下:
#!/bin/bash #功能描述:用于Jenkins运行,停止,重启 #将此脚本放在jenkins.war同级目录 #获取Jenkins的进程id pid=$(ps -ef| grep "jenkins.war" | grep -v grep | awk '{print $2}') #jenkins默认端口号 jekinsDefaultPort=9090 #如果用户有自定义端口号,则使用用户自定义的端口号启动jenkins if [ x$2 != x ] then jekinsDefaultPort=$2 fi #启动jenkins start(){ if [ x$pid != x ] then echo "jenkins已经是启动状态..." exit 1 fi nohup java -jar jenkins.war --httpPort=$jekinsDefaultPort > /dev/null 2>&1 & echo "jenkins启动成功,端口号为:$jekinsDefaultPort..." return $? } stop(){ echo "准备停止jenkins..." if [ x$pid != x ] then kill -9 $pid echo "jenkins已经停止..." exit $? else echo "jenkins的进程id不存在,无法进行停止操作..." exit 1 fi } # 重新加载Jenkins restart() { stop start echo "jenkins重新加载成功,jekins端口号为:$jekinsDefaultPort..." } case "$1" in start) start ;; stop) stop ;; restart) stop start ;; *) echo $"提示: 请在jenkins后输入以下参数:{start|stop|restart} 端口号(不填写时默认端口9090)" exit 1 esac exit $? |
2、Jenkins中自定义Shell问题
#需要在脚本开始时添加export BUILD_ID=dontKillMe。
#原因:因为Jenkins执行完当前任务之后需要执行下一个任务,此时Jenkins会直接把tomcat进程杀掉,#因此在脚本中编写的tomcat启动命令是不会执行的。
export BUILD_ID=dontKillMe
【⑤课程总结及心得】
学习代码自动部署的缘由一来是由于在平时开发过程中经常会遇到代码部署的环节,希望通过学习此知识后,如果后续有机会针对自己学会的方案进行评估后简化项目中的项目部署,二来是巩固自己近期来学习到的一些知识,通过层层迭进来学习代码的自动部署方案。虽然目前自己的这些流程方案可能还有所欠缺,且还没有经过实际项目考验,但能学到很多实际的知识也足够了,比如Maven相关知识、Shell相关知识以及Jenkins相关知识,这些是只能通过自己动手慢慢去实践才能获取到的经验。如果对代码部署也感兴趣且觉得我写的东西对你有帮助的同行们,我建议可以按照我的学习步骤去学习自动构建技术。
此系列文章可能写的还不够好,并且很多地方我都进行了一些精简。其实我希望给大家提供的是一个思路。比如学习整个项目部署的思路,由Maven插件部署到Shell脚本部署再到Jenkins部署项目,其实越到后面,Jenkins只是对一些操作做了集成封装,但是我觉得如果我们能从最基本做起,了解其中的流程及原理,真正使用Jenkins进行代码部署时,我们能知道所以然,那样我觉得可以更好的使用Jenkins工具。另外,比如Jenkins.war的启动,我很自然的想到使用Shell脚本将它的启动、运行、重启等命令进行封装,并把它设置为开机启动,我觉得这是一个优雅的方式,以后有类似的情况时,我也会考虑这么做。
本文中还有一些没有提及和没有实现的内容,我希望以及对此技术感兴趣的同行们,都可以发散思维,把事情尽善尽美,做到最优做好。通过编写此系列文章,我巩固了我此类技术的知识的了解以及拓展,也希望能够帮助到大家。如果大家在学习此类技术上遇到疑惑或问题,可以百度查看解决办法,也可以给我留言进行探讨。
最后,希望所有人在不久的将来都能遇到一个优秀的自己。