本文共 4981 字,大约阅读时间需要 16 分钟。
凌云时刻 · 技术
导读:当一个骑自行车人的准备提速,是该换轮胎,还是该换引擎?
作者 | 高启
来源 | 凌云时刻(微信号:linuxpk)
背景
最近,跟朋友聊天的时候,见到过一个使用docker的例子,但使用方法相当的野蛮暴力。
大概的流程如下:
代码上传git
jenkins对代码打jar包
jar 包上传docker的宿主机
docker run -v 的方式将jar包载入容器
这种发布流程引来了大伙的群嘲——完全是为了docker而docker嘛,这和直接丢几个jar包到物理机上run起来有何区别?
我没有加入群嘲,因为我也曾经用过这样的一套发布系统,内心里,更多的是理解他们为什么要这么做。
背景
发布框架
本文会细致到该发布系统的配置项,在深入之前,让我们先来看一下架构图,从全局上对这套发布系统有个大致的了解。
流程说明:
开发将代码提交到 Dev git中。
在jenkins里可以配置git hook,发现代码提交时,自动触发构建动作,生成war包。
Maven 私服略过不表。
在完成war包的构建之后,jenkins将该war包以日期+当天构建批次为tag,commit到Publish git中。
发布代码存于jenkins本机,jenkins以ssh方式访问测试vm,执行war包的部署脚本,将war包拖入tomcat的webapps目录。(记忆中应该是这个目录吧,时间太长,有点忘了。)
测试vm上功能验证完毕,再将war包发布于生产vm。
这里只对java代码的发布进行一个流程说明,实际上js/css等静态文件的发布,也可以使用这套流程,只需简化代码构建流程即可。
详细配置说明
了解了该发布系统的架构后,接下来就是实操;通过看配置,来理解jenkins是如何将工作流给串起来的。
新建项目
新建项目这块不再详细说明,我直接以之前jenkins镜像里的项目做说明。如下图:
从命名上,大家应该能看出来,第一个项目主要是用以构建war包。第二个项目则是在war包完成构建之后,将war包部署到机器上。
构建配置
首先看一下构建war包项目的配置项。
源码读取
配置源码的git库。(图中是svn,逻辑一样)
构建war包
这里是构建war包的脚本,里面有两个信息比较重要。分别是war包构建完成之后要commit的git地址以及提交的版本号。
这里面用到了一个cap命令,该命令并非linux系统自带的,其实是Rails的一个自动化部署工具。
版本号的生成规则如下:
也就是任务名+日期+构建批次
进入部署工作流
war包构建完成后,可以直接在jenkins上配置工作流的触发,进入项目部署的任务中。配置如下:
war包部署
支持传入的参数
先来看一下这个流程支持的功能:
当然这些功能是我们自己定义的,后面会说明在哪里调用、定义。
调用部署脚本
这里我们假设要部署的机器为192.168.180.152(可填入多个),依然是利用cap调用前期写好的脚本,通过ssh方式在192.168.180.152机器上执行这些脚本,完成war包的分发和部署。
后面的一大堆参数实际上都是传给了cap调用的脚本读取。
干活脚本
从上图我们可以看到cap实际上是将CapfileKjt2这个脚本在远端主机上调用并执行,而 支持传入的参数
小节中提到的功能,也正是该脚本提供的能力。该“面条”脚本信息如下:
#!/usr/bin/rubyCapistrano::Configuration.instance(true).load do namespace :atdp do def git_clone(git_server, git_name, git_local_name) git_path = "/opt/applications/#{git_local_name}" git_clone="if [ ! -d #{git_path} ]; then mkdir -p #{git_path} && git clone git://#{git_server}/#{git_name}.git #{git_path}; fi;" return git_clone end def git_cmd(git_local_name,tag_name) app_bin = "/xxx/nginx/sbin" git_path = "/opt/applications/#{git_local_name}" git_cmd="cd #{git_path}&&git clean -f -d&&git reset --hard&&git fetch&&git reset --merge #{tag_name}; chmod u+x #{app_bin}/*;" return git_cmd end def nginx_deploy(app_action) nginx_deploy = ". /etc/profile&&/gensee/nginx/sbin/nginx #{app_action};" return nginx_deploy end def config_backup() backup_path = "/opt/backup/nginx/" config_path = "/xxx/nginx/conf/" config_backup = "if [ ! -d #{backup_path} ];then mkdir -p #{backup_path}; cp #{config_path}*.conf #{backup_path};fi; if [ -f #{backup_path}nginx.conf ];then rm -rf #{backup_path}*.conf; cp #{config_path}*.conf #{backup_path};else cp #{config_path}*.conf #{backup_path} ; fi;" return config_backup end def conf_recovery() backup_path = "/opt/backup/nginx/" config_path = "/xxx/nginx/conf/" conf_recovery = "if [ -f #{config_path}nginx.conf ];then rm -rf #{config_path}*.conf; cp #{backup_path}*.conf #{config_path};else cp #{backup_path}*.conf #{config_path} ; fi;" return conf_recovery end def modify_conf() nginx_deploy = ". /etc/profile&&sh /xxx/nginx/sbin/modify_conf.sh;" return nginx_deploy end def add_context(git_name, middleware_ctl) git_path = "/opt/applications/#{git_name}" if middleware_ctl =~ /nginx/ app_path = "/xxx/nginx" app_bin = "/xxx/nginx/sbin" add_context="if [ ! -d /xxx ]; then mkdir -p /xxx; fi;if (ls #{git_path}); then rm -rf #{app_path}*;ln -s #{git_path}/`ls #{git_path}` #{app_path}; fi; chmod u+x #{app_bin}/*; " else puts "param error!" exit 1 end return add_context end task :static_git_up_tag, :max_hosts=>1 do if !exists?(:git_local_name) git_local_name2 = git_name else git_local_name2 = git_local_name end if tag_name == "init" run git_clone("192.168.101.132",git_name,git_local_name2) + add_context(git_name, middleware_ctl) + modify_conf() elsif tag_name =~ /static/ run config_backup() + git_clone("192.168.101.132",git_name,git_local_name2) + git_cmd(git_name, tag_name) + conf_recovery() elsif tag_name == "stop" run nginx_deploy("-s stop") elsif tag_name == "start" run nginx_deploy("") elsif tag_name == "re" run nginx_deploy("-s reload") else puts "param error!" exit 1 end end endend
脚本中的以下部分,定义了所有支持的功能。
回滚
如果上线的代码存在严重bug,那么我们需要针对发布的war包进行一个快速的版本回滚。前面我们提到,每次构建war包的时候,都会打上一个版本号。通过该版本号,即可实现问题版本的快速回滚。
详见下图:
小结
该发布流程实现了从源码的打包到发布的全链路,基本上能够满足小企业的日常发布需求。以今天的眼光来看,这套发布系统是落后的,但在当时,还没有docker/k8s,salt、ansible刚刚起步(印象中是刚起步,记错勿喷)的时期,确实也从流程上减少了很多人肉的步骤,一定程度上提升了运维效率。
思考
对于这套发布系统的一些个人思考:
没有正规的CMDB,所有的主机信息和配置都写在jenkins中做维护,需要发布的项目多的时候,很难做维护。
只考虑了发布,未考虑服务发现场景。
其实,很多系统都是这样的,先入为主:一旦用的习惯,很难去做改动。一是改动成本高,另一方面是看起来好像没有改动的意义:我这套东西用的好好的,够用了,为什么还要再搞一套新的发布系统呢?
所以,在公司的长期技术发展中,如何制定目标?能力应该如何分配?预算如何规划?这些,都是企业决策者应该思考的问题。
END
往期精彩文章回顾
长按扫描二维码关注凌云时刻
每日收获前沿技术与科技洞见
转载地址:https://lingyun.blog.csdn.net/article/details/107036630 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!