一、我们要解决的问题
无论是什么样的解决方案,一定要牢记我们要解决的问题是什么,切不能将解决方案当做问题本身。具体到过程改进,不管是何种方式的改进,它们所要解决的问题永远只有一个:缩短从产品想法到可用软件之间的时间周期。自动化发布正是如此,如果软件发布只做一次,我们说根本不需要自动化,但如果三次以上,那么软件开发的黄金法则DRY就必须遵守,让时间真正用到开发当中去。
二、与发布相关的问题
所谓自动化只不过是将原先手工做的工作谦让给机器做,所以自动化之前一定要先清楚与发布相关的问题有哪些,即使不自动化,这些工作也一个也不能少:
- 应用程序如何打包? 发布包能否追踪到SVN版本号?
- 对目标机器环境有什么样的要求?
- 配置信息是否需要根据目标机器信息做出调整?
- 应用程序如何安装和启动?
- 应用程序启动后如何切流量?
- 应用程序如何升级? 旧版本程序数据如何迁移?
- 升级过程中和结束后如何切流量?
- 应用程序如何卸载?
三、我们的方案
李安的少年Pi正在狂刷票房,我们的自动化发布方案也要跟上潮流:Puppet+CI我们的少年Pi。
Ø 使用CI自动化打包,追踪每个发布包的SVN版本;
Ø 使用Puppet管理发布包、目标机器环境、应用程序配置信息以及应用程序线上生命周期;
Ø 使用伽利略系统提供应用程序的命名服务和进行流量切换。
现在应用程序的发布需要两步:CI一键打包、puppet指定应用程序版本SVN提交。
四、具体方案
具体方案也就是如何解决与发布相关八个问题的过程。
1. 如何安装、升级和卸载应用程序
我们使用操作系统原生包管理系统来安装、升级和卸载应用程序,我们的应用程序打出RPM二进制包。免安装,所有机器自带,绿色的,有机的。
打包:rpm -ba ./team_member-1.spec
安装:rpm –ivh team_ member-2.0.1-48.x86_64.rpm
升级:rpm –U team_ member-2.0.1-49.x86_64.rpm
卸载:rpm –e team_ member-2.0.1-48.x86_64.rpm
程序升级前要停旧版本服务怎么办?旧版本数据要做处理怎么办?RPM已经帮我们料理好这一切,只要写出spec文件,剩下的交给我们。尽情的插入吧:
2. 如何管理目标机器环境和应用配置信息
应用程序已经打好rpm包了,但这还不够,应用程序发布到哪台机器上?应用程序对目标机器有什么要求?发布时需要修改哪些配置和参数?实际发布如何执行,难道需要登陆到每台目标机器运行rpm命令吗?
我们使用Puppet来搞定这一切,Puppet是现在应用第一的devops工具,它通过master/agent的工作模式管理机器。我们通过声明来控制我们的机器达到目标状态。同时,所有puppet文件全部在SVN里,所有对机器的修改全部codereview和可审计。
如何管理应用程序发布到哪台机器上?在回答这个问题前我们必须将应用程序在线上的生命周期再进行一次封装。
应用程序TeamMember被我们封装成一个puppet module,配置文件和参数被封装在对应templates和files里,每次发布前都要修改配置文件和传递不同的参数?out了吧,puppet帮你传参搞定:
Teammember.conf文件内容:
封装完成后的效果是这样的:
最后在管理部署的site.pp文件里声明一下,应用程序TeamMember的2146版本就被自动部署到10.128.34.141.test.back.shequ这台机器上了,我们后续的工作也就是维护这个site.pp文件了,所有应用程序的部署信息都在SVN被集中管理起来:
登陆到每台目标机器运行rpm命令?No!现在TeamMember已经被封装,我们修改完毕site.pp并提交后,puppet就自动执行命令了,要不怎么说是自动化呢。(现在puppet默认在agent每半小时同步一次,但同时支持马上触发执行)。
3. 如何追踪每次发布的SVN版本号
我们使用CI进行应用程序的打包,将build号作为包命名的一部分:
4. 如何在发布过程中切换流量
这是另外一个很大的话题,参见伽利略计划。
五、下一步工作
使用CI将环境的自动化部署与自动化测试串联起来,搭建起整个研发流程自动化平台:
六、小结
没有银弹,自动化所做的只是将之前手工工作交给计算机完成,需要做的工作一个都不能少,此外,我们还要多做一些封装或脚本工作,但是,当我们需要重复做这些事情的时候,价值就出现了。我们的目标永远是缩短从产品想法到可用软件之间的时间周期。让时间真正用到开发当中去。