落后产能的实现路径 | 凌云时刻
发布日期:2021-06-30 18:31:01 浏览次数:4 分类:技术文章

本文共 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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:在中国在行其道的智慧城市,为何折戟多伦多? | 凌云时刻
下一篇:跑赢业务的同时如何实现技术成长? | 凌云时刻

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年04月13日 00时01分48秒