自动增量升级方案的设计及实现
2014-11-27 21:19
218 查看
文档转载自:http://tech.uc.cn/?p=1621
问题背景:
能否以某种简便甚至自动化的方式,将修改过的文件以增量的方式同步到线上而不影响应用的正常运行。除了文件同步外,能否自定义某些脚本,在升级时自动执行。
如果发现升级后的版本有问题,能否快速回滚到原来的版本。
写作目的:
以SVN为例子,学会基于版本库的自动增量升级。无需依赖任何文件同步工具,只需简单的几个shell脚本便可完成从自动增量打包到自动增量升级的整个过程。
适合阅读对象:
想从繁琐乏味的升级工作中解放出来的运维人员。担心因修改文件数目多而可能导致升级遗漏的开发人员(尤其是web项目开发者)。
想了解自动增量升级设计思想的人员。
不涉及的内容:
暂未包含基于hg或git版本库的增量升级的实现,但思路与SVN是类似的。本文侧重业务应用的增量升级,不涉及个人软件或者系统软件的增量升级,尽管这两者存在一些相似的地方。
脚本下载地址:
https://github.com/joerong666/auto_patch.git
正文:
增量升级这个名词相信已经不是什么新鲜事物了,甚至我们每天在不经意间也已经做了该事。比如windows的自动更新,就是增量更新的一种。先撇开系统软件的升级不说,作为一个业务应用开发者,笔者这里就自己所了解,介绍一下业务应用在做增量升级方面都采用哪些方法。
升级方法比较
方法一:逐个文件拷贝覆盖
这个是最原始的增量升级方式,虽然简单,但繁琐且易漏易错,相信稍有点规模的应用都不会采用这种方式。想想如果有分布在不同子目录中的上百个文件被修改过了,你得执行拷贝覆盖多少次,更悲催的是,你花了九牛二虎之力才把文件拷贝好,结果却发现覆盖错了。
方法二:使用类似rsync的文件同步服务器
相对来说,使用rsync可以确保文件不会被误覆盖,也能保持目录结构的一致性。但个人觉得这只是一种文件同步,跟升级还是有一定的区别,如果我们的升级仅仅是涉及文件的覆盖或删除,或许采用rsync是一个不错的选择。但如果想在升级的同时自动执行某些定制的程序或脚本,那么rsync就显得有点爱莫能助了。另外rsync的引入,也需要额外的成本去搭建和监控它,自然也就需要额外的维护成本。而且rsync与版本库的无缝结合也是个值得考验的问题,能否由rsync直接从版本库中获取增量的部分,还是得额外写个脚本将增量部分写到rsync的同步目录中,再由rsync客户端来获取?
方法三:由开发人员手工编写升级脚本
一般来说,采用这种方法,首先需要开发人员记录下哪些文件涉及改动,当然可通过查看版本历史的方式来判断哪些文件需要做更新;然后再针对这些文件,逐条编写相应的用于覆盖或删除线上应用的copy或rm语句;最后将包含这些语句的脚本随增量文件一起打包给运维人员,让运维人员到线上执行。从可靠性的方面考虑,这种方式还不如第二种方法,但相对来说,这种方式的可控性比较灵活,可以灵活自定义升级脚本,而不是简单的同步文件。比如可以定义在升级的同时执行某个特定的程序,最常见的就是在升级的同时重启原来的某些服务。
方法四:自动增量升级
该方法是对方法三的一种增强,一方面是升级脚本是根据版本历史自动生成的,不再需要人工编写;另一方面,支持自定义升级扩展,也就说除了生成简单的增量覆盖升级脚本外,还支持以可插拔式的方式将自定制的程序让升级脚本自动执行。这是笔者选择的升级方法,也是本文的讲述重点。下面针对这种方法具体展开描述。
自动增量升级
下面先从流程方面来大概介绍一下自动增量升级的整个思路,然后再从程序的角度解释一下本文中所涉及的脚本的作用。升级流程分两个阶段,第一阶段为增量打包操作,一般由开发人员执行;第二阶段为升级操作,可由运维人员执行。
增量打包流程
流程描述:更新版本库 ===> 生成增量清单文件 ===> 检查并修剪清单文件(以及编写自定义升级程序) ===> 生成增量补丁包对应命令或脚本:svn update ===> gen_manifest.sh(需将结果重定向到PATCH_MANIFEST清单文件) ===> 添加或删除清单文件(PATCH_MANIFEST)中无需做更新的记录(同时根据需要编写想让升级程序自动执行的脚本,如demo_custom_script.sh) ===> gen_patch.sh
升级流程
流程描述:获取增量包 ===> 执行升级操作并生成增量包的回滚备份包对应命令或脚本:可通过wget获取增量包 ===> patch.sh(执行完后会生成增量回滚包,如patch_recover_20130626113450)
程序解释
生成清单文件gen_manifest.sh
123 | $ ./gen_maifest.shUsage: ./gen_manifest.sh revision1[:revision2] [sub_dir] |
清单文件PATCH_MANIFEST
大体如下:1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #revision:A/D/C:src_file[:dest_dir] r2061:A:sub_dir/dir1/a.java r2065:A:sub_dir/dir2/b.sh r2069:A:script/dir3/c.ini:sub_dir/script/dir3 #r2111:D:sub_dir/test/kkk/tt.txt #r2112:A:sub_dir/test/kkk2 #r2112:D:sub_dir/test/kkk #r2113:A:sub_dir/test/kkk2/tt2.txt r2124:A:sub_dir/conf/log4j.properties #r2197:A:sub_dir/conf #r2197:A:sub_dir/conf/config.conf xxxxx:A:sub_dir/db/patch.sql xxxxx:C:patch_script/demo_custom_script.sh:sub_dir/autoscript |
行首带#号的为注释行,gen_patch.sh不会解析。由于有些配置文件(如这里的config.conf)我们在版本库上虽做了修改,但我们不能更新到线上应用去,毕竟配置不一样,故直接把相应的行注释掉即可(注意记得把相应的目录也注释掉,如这里的”#r2197:A:sub_dir/conf“行)。
第一行是一个样例,标识每行记录需遵守的格式,一行最多只有4项,每项用冒号分隔。revision为版本号;A/D/C分别表示为“添加或修改(Add)/删除(Delete)/自定义命令(Comand)“;src_file为涉及文件在版本库中的目录结构;dest_dir(这里是目录,而不是文件)为src_file在发布包中的目录结构,如果没指定则表示涉及的文件在版本库和发布包中的目录结构一样。
后面的版本号为xxxxx的行是一些自定义操作行,这些操作并没有或者无法在版本库中体现。如
xxxxx:A:sub_dir/db/patch.sql ===> patch.sql文件在指定的版本号范围内并没有相应的更改历史,也许它根本就不在版本库内,但我们又想让它随本次的增量包拷贝到线上应用去,所以采用这种定制的方式委婉的将它纳入增量包中。
值得注意的是操作为”C”的行,如这里的最后一行:
xxxxx:C:patch_script/demo_custom_script.sh:sub_dir/autoscript ===>C操作的行并非简单的表示将src_file拷贝到dest_dir,事实上它并没有被拷贝到线上应用中去,而只是仅仅打进增量包中,然后作为一种自动化的程序,在运维人员执行升级(patch.sh)操作时被自动执行的程序,有点被回调的味道。该程序一般需要开发人员根据实际需要编写,一般是一些执行服务的操作,如重启某些服务。如这里提到的demo_custom_script.sh。
自定义升级脚本demo_custom_script.sh
12345678910111213141516171819202122232425 | #!/bin/env bash src_dir=$1 ## 这个参数是由升级程序patch.sh执行时传递进来的,表示增量包在线上被解压的临时目录dest_dir=$2 ## 这个参数也是由升级程序patch.sh执行时传递进来的,表示线上应用所在的目录(即patch.sh所在的目录) export LANG=en_US.UTF-8 target_dir=my_target/bintarget_proc=my_service function err_out(){ echo "Reload my_service failed" >&2 exit 1} cd $dest_dir/$target_dir && \./my_service reload ## 升级时(一般是执行完增量清单中的其它操作之后)重启我的服务 if [ $? -ne 0 ]; then err_outfi exit 0 |
生成增量包gen_patch.sh
1 2 3 4 5 | $./gen_patch.sh Usage:./gen_patch.sh<OUTPUT> <OUTPUT>:patchfilelike<OUTPUT>-patch20130607.tar.gzwillbegenerated Attention:amanifestfilenamed'PATCH_MANIFEST'isneededundercurrentdirectory |
执行升级操作patch.sh
123 | $ ./patch.shUsage: ./patch.sh patch.tar.gz |
1 2 3 4 5 6 7 | myapp-1.1.0-rc5-bin-x86_64 |--approot |--app-patch20130624.tar.gz |--patch.sh |--patch_recover_20130613182709===>升级时生成的增量回滚快照 |--patch_20130626.log===>升级时执行的日志 |
结束
虽然前面洋洋洒洒写了好多,感觉好像很复杂的样子,其实想要表达意思的很简单,就下面三个步骤:生成增量包
$ ./gen_manifest.sh 2061 >PATCH_MANIFEST
$ ./gen_patch.sh app ===>生成app-patch20130624.tar.gz
执行升级
$ ./patch.sh app-patch20130624.tar.gz
您可能感兴趣的文章
基于Func自动化部署:方案思索及演进TCP洪水攻击(SYN
Flood)的诊断和处理
在LVS上实现SNAT网关
相关文章推荐
- 自动升级系统的设计与实现(源码)
- Android应用的自动升级、更新模块的实现完整方案理解
- 自动升级系统OAUS的设计与实现(续) (附最新源码)
- 自动升级系统的设计与实现(续2) -- 增加断点续传功能 (附最新源码)
- Android应用的自动升级、更新模块的实现完整方案+参考程序
- Android 实现应用升级方案(暨第三方自动升级服务无法使用后的解决方案)
- 自动升级的设计思路与实现
- 自动升级系统的设计与实现(源码)
- 自动升级系统的设计与实现(源码)
- Android应用的自动升级、更新模块的实现完整方案+参考程序代吗
- Android应用的自动升级、更新模块的实现完整方案+参考程序
- Winform自动升级系统的设计与实现(源码)
- 自动升级系统的设计与实现(源码)
- 自动升级系统的设计与实现(续2) -- 增加断点续传功能 (附最新源码)
- 可复用的自动升级系统实现(一)
- 2005中ClickOnce实现程序的自动升级功能。
- C#实现软件自动升级
- ASP 程序实现自动升级功能
- ASP.NET2.0实现网站的自动升级
- 在WinForm中使用Web Services 来实现 软件 自动升级( Auto Update ) (C#