原文:http://refcardz.dzone.com/refcardz/continuous-delivery-patterns
这篇文章基本上是continuous delivery的总结,浓缩版,有时间咱还是建议去看书哈~
CD是agile思想的重要组成部分。
With Continuous Delivery (CD), teams continuously deliver new versions of software to production by decreasing the cycle time between an idea and usable software through the automation of the entire delivery system: build, deployment, test, and release. CD is enabled through the Deployment Pipeline, which encompasses a collection of patterns described in this Refcard.
CD强调的是持续性的交付,快速部署代码。因此可以将CD理解为两个方面的指导原则:
1,完成一小部分代码后,立即交付。而不要累积。
2,为了实现快速部署而实现高度自动化。
最终ideally的效果是,每天程序员交付的代码第二天就会在production上运行,一切都自动完成。
或许我们并不需要大规模的人工测试,我们只需要运行测试用例。
另外一句领导的话:有的时候想想,将修改的代码快速的提交到production,真的那么可怕吗?
但是这里有一个段很重要的话:
The most important distinguishing characteristic of Continuous Delivery is that any and every successful build that has passed all the relevant automated
tests and quality gates can potentially be deployed into production via a fully automated one-click process and be in the hands of the end-user within minutes. However, the process is not automatic: it is the business, rather than IT, that decides the best time to deliver the latest changes.
在CD中,强调迅速交付代码到production,但这不是必须的。比如,虽然新功能能马上部署到production,但是用户需要进过培训才能掌握新功能。因此,并非所有的用户都喜欢马上在production上看到新功能。
所以在CD中部署到production通常不是自动的,而是手动触发的。选择一个好的时机,才会部署。
只不过在手工触发的过程中,我们应该实现one-click deployment。
下面是CD的好处。
• Empowering Teams: Because the deployment pipeline is a pull system, testers, developers, operations, and others can self service the application version into an environment of their choice.
授权让team做更多事情。
• Reducing Errors: Ensuring the correct version, configuration, database schema, etc. are applied the same way every time through automation.
通过每一次相同的自动化过程,保证正确的版本,配置,数据库对象,等等。
• Lowering Stress: Through push-button releases to production and Rehearsing Deployments, a release becomes commonplace without the typical stress.
降低压力:通过一键安装,反复的演练部署过程,一次release会变得越来越平常,而不会有额外的压力。而不是像我们现在这样,几个月一次的release,基本每次都会出错,大家也都很紧张。
• Deployment Flexibility: Instantiate a new environment or configuration by making a few changes to the automated delivery system.
只需要更改自动交付系统的一小部分就可以创建一个新的环境或配置。
• Practice makes Perfect: Through the deployment pipeline, the final deployment into production is being rehearsed every single time the software is deployed to any target environments.
通过反复的练习而让软件快速顺利的部署在任何一个环境。
任何一个经历了项目延期的痛苦的程序员和项目经理,都应该理解CD带来的巨大好处。除以上文中列举的好处外,还有:
1,由于每次完成了少量的代码更改后就进行交付,让每个release之间的差异很小。因此每一次release的风险也更低。如果release出现任何问题,可以快速恢复到上个release。
2,程序中的问题可以更早暴露。想象一个时间长达三个月或半年的release上线后,随之出现的问题必然也是这三个月或半年期间的累积。而快速提交小版本,可以让问题变成更小的麻烦,并快速被发现。
3,让程序更符合客户的要求。客户将在最短的时间内看到产品,并将持续看到产品的改变。通过不断的沟通和修正,将保证产品在最大程度上符合用户的要求。而不是半年一年之后,客户终于看到产品后惊呼“这不是我想要的!”。
CD is concerned with “…how all the moving parts fit together:configuration management, automated testing, continuous integration and deployment, data management, environment management, and release management.”
因此CD关注的是一个非常广泛的范围,包含代码从repository,到最终delivery的一所有阶段。
CD是通过Deployment Pipeline实现的,Deployment Pipeline包含从源码到最终部署的所有阶段。而该文的主要内容就是介绍deployment pipeline中各个阶段,及其指导原则,以及这些阶段适用的工具。
下面开始:
Configuration Management is “the process by which all artifacts relevant to your project, and the relationships between them, are stored, retrieved, uniquely identified, and modified”.
为什么配置管理变得重要,并且被单独提出?很简单,continuous delivery提倡的快速部署,离不开配置管理。
只有良好的配置管理才能实现快速的在各个环境自动化配置需要的一切。
1,可配置的第三方软件
好的做法:使用如SVN这种第三方软件来自动化存储配置信息。使用SVN后,我们可以在脚本中,用命令方便的自动修改,读取配置信息,在每一次build中自动使用最新的配置。
糟糕的做法:不使用第三方软件来管理配置信息,或者使用那些不提供API或命令行方式,只能用图形化节目操作的工具。
2,配置目录 configuration catalog
好的做法:维护包含程序所有可能选项的目录。例如程序app,将来会被部署到3个环境a,b and c。那么我们应该为该程序维护三个目录,分别包含程序和三个环境的不同配置。
在真正部署时,直接应用对应目录里的内容即可完成部署。
同时,在每一次build时,自动产生这些目录。
糟糕的做法:不这样做。同时,不同环境的不同要求没有被记录下来。每次部署都靠小部分人的经验来完成。
3,主线mainline
好的做法:有主线。即在一条主线上开发,其实就是我们常说的trunk。同时最小化branch的数量,从而最小化需要merge和管理的代码。
糟糕的做法:每个项目都有多个branch。
这个不多说了,branch多了真是件烦人的事情。。。。
4,Merge daily
好的做法:修改的代码至少每天一次提交到trunk上,同时也要merge到每一个branch上。
糟糕的做法:频率大于1周或更长。
这个。。。难度大点。。。反正我们现在做不到,尤其是merge到branch上,基本都是一周以上一次。
5,受保护的配置信息
好的做法:将配置信息存放在远程的安全的地方,例如数据库(有备份)等。
糟糕的做法:仅放在一台机器上,同时使用人人都知道的密码。
6,Repository
好的做法:所有的源文件,包括源码,配置信息,环境信息,数据 都应提交到有版本控制的repository。
糟糕的做法:Some files are checked in, others, such as
environment configuration or data changes, are not.
Binaries – that can be recreated through the build
and deployment process – are checked in.
有一些提交了,但是另外一些例如环境配置信息,或数据的改变则没有。存储多余的信息,即那些可以通过build或部署过程,被重建出来的东西,也被check in了。
例如c#中的什么bin目录,什么obj目录,就不要随便乱往svn上扔了。不该check in的东西不要乱check in。
7,短命的branch Short-lived branch
搞笑一下。
好的做法:其实就是说,branch的时间不能太长,通常存在几天就行了。而且永远不要超过一个迭代。(所谓迭代是agile里的一个概念,指一个较短的开发周期,通常由几个星期组成)
糟糕的做法:超过一个迭代。
既然要求快速部署,那么每一个branch应该被迅速的release到production上。一旦release完毕,这个branch就被下一个branch替代。
这个目前我们很难做到。。。因为我们还没有开始用CD :)
8,Single command enviornment
好的做法:check out出版本控制的源码,用一个命令build和部署到任何需要的环境,甚至包含本地的开发环境。
糟糕的做法:开发人员不得不自己定义,配置环境变量。开发人员不得不为了让程序工作而手工安装多个配套的软件。
这个比较牛,难度也很大。而且是需要多次反复实践才能达到的状态。但是非常值得,因为没有人喜欢干这个。
9,Single-path to production
好的做法:对整个系统所有组件都进行统一的配置管理。包括所有的源码,环境,配置和数据。任何主见的一点小的变化,都可以通过版本控制而让整个系统回退到上一个版本。
糟糕的做法:一部分系统没有版本控制。无法让系统简单的回退到上一个状态。
好理解,万一快速提交的代码有什么问题,咱还可以马上把新版本撤下来,不让客户看见~
1, Build threshold 就是什么时候build
好的做法:当项目的rule被打破时,就不要build了。例如过多的branch,缓慢的测试或者代码标准没有被遵守。
糟糕的做法:人工的review代码。在开发之后才开始注意代码质量问题。
我理解这条的意思是,如果一些基本原则被打破,就不要急于build。停下来把问题搞定,再做持续集成。
2,经常提交代码
好的做法:每一个team member都应该规律性的往trunk提交代码。至少每天一次,最好每个task完成后都出发一次CI。.如果task时间比较长,比如两天,也要一天提交一次。
糟糕的做法:一天都不check in一次。
3,持续反馈
好的做法:将CI的结果自动反馈给每一个cross-functional team member。
糟糕的做法:反馈没有被发送。反馈被忽略。反馈内容不够好,不够有用,导致成了垃圾邮件。
我们使用cruisecontrol的功能将每一次build的结果发送给maillist中指定的对象。当然,很多时候确实有点spam。
其实更好的做法是用一个小工具叫cctray。这个小东西就显示在屏幕右下角,你可以同时监控多个build,默认5秒刷新一次状态。有成功或失败的build,它都会提醒你。
有问题直接打开cruisecontrol的web界面去看怎么回事儿。
有了这个东西,基本不需要看邮件了。
4,持续集成
好的做法:对每一次提交到repository的更改都运行build和测试。
糟糕的做法:使用定期的build或者完全不build。
意思就是有更改就build,而不是定时的去build。这个我们的做法是兼而有之:每次提交都会触发build,但每天晚上还有定时的整个system的build。
5,停下来解决问题
好的做法:一旦发现问题就马上停下来去fix。fix bug成为最高优先级的事情,不要往一个broken的build再提交代码。
糟糕的做法:build失败很长时间。以至于开发人员都不能check out代码了。
6,独立的build
好的做法:写一个独立于IDE的build script,进而可以被CI调用。
糟糕的做法:build script依赖于IDE中设置的一些配置或变量。build script不能被命令行调用。
7,可见的dashboards
好的做法:使用dashboard来查看build的详情。例如cruisecontrol的website。
糟糕的做法:仅仅是发一封邮件告诉大家build失败了,或者连邮件都没有。
1, 自动化的测试
好的做法:通过自动化的unit, component, capacity, functional, 以及deployment测试,自动完成软件的验证。
糟糕的做法:手工完成上述类型的测试。
下面是这几个测试的简单说明:
Unit- Automating tests without any dependencies.
Component- Automating tests with dependencies to other components and heavyweight dependencies such as the database or file system.
Deployment- Automating tests to verify the deployment and configuration were successful. Sometimes referred to as a “smoke tests”.
Functional- Automating tests to verify the behavior of the software from a user’s perspective.
Capacity- Automating load and performance testing in nearproduction conditions.
2, 独立的测试数据
好的做法:如果数据存储在数据库中,则使用事务来进行数据的存取。当测试进行完毕时,回退所有数据的更改。使用小数据集来提高测试效率。
糟糕的做法:使用production数据进行最后的测试。基于共享数据库运行测试。
这点的核心意义在于,不要让测试数据在每次测试之后留下任何影响。
3,并行测试
好的做法:在多个硬件上同时运行多个测试,从而在最短的时间内完成测试。
糟糕的做法:在一台机器上运行测试。运行的测试之间有依赖关系,导致无法并行测试。
4,Stub system 这个不知道该怎么翻译,知道mock工具的应该会明白。大概的意思是指定一个对象的行为。
好的做法:使用stub来模拟外部系统的行为,从而减少部署的复杂度。
糟糕的做法:手动安装和配置这些外部系统。
例如一个新系统基于已经安装的数据库。当测试部署脚本的时候,可以stub一个虚拟对象来模拟数据库,而不是真的的再去安装一个数据库用于测试。
1, Deployment Pipeline
好的做法:A deployment pipeline is an automated implementation of your application’s build, deploy, test, and release process.
糟糕的做法:部署需要除了点一下button以外的人工干预。或部署完成后,不是完全的prodution系统,不能直接给用户使用。
2,Value-stream map
好的做法:创建一个map,用于说明从代码check in到版本发布的每一步,从而定位这个process中的瓶颈。
糟糕的做法:独立的看待每个步骤而不是整体。
有意思的是,文章最后列举的CD中涉及的工具,在CI一栏中并没有我熟悉的cruisecontrol和hudson。
个人理解cc和hudson仅仅用于完成持续集成,我们仅仅是用它们持续运行源码,运行测试用例。而文中推荐的工具,如bamboo则包含从持续集成到部署管理的一系列功能。