在第13期云栖TechDay活动上,王健先以自己的亲身经历说明持续交付的重要性 ,然后利用技术雷达分别从实践、工具和人的角度讲解持续交付的发展和未来。
下面是演讲内容整理。
技术雷达
技术雷达的本质是采用图形化方式将各种技术归类为技术、工具、平台和语言及框架四个象限。技术雷达其实是代表着对于未来的一个前瞻,大家可以想象用现实中的雷达来看,它不是预测未来,它根据一些蛛丝马迹来提前的感知一些东西。
技术雷达分四个环:
- 暂缓区在最外层。很多人理解技术雷达,觉得暂缓不该用,但并不是这样。我们认为,有可能在暂缓里面的内容是我们需要再缓一缓。因为有可能它很新,有可能也会改变世界,但是现在还不成熟,所以你要尽量地暂缓来使用
- 评估阶段:为了查明它如何影响企业,值得做一番研究。我们觉得它很有意思,它可能会改变未来,但是我们还不知道它有什么样的问题有什么样的影响。
- 实验阶段:值得追求,我们自己的项目当中开始琢磨,但我们仍然认为它有可能有一些问题和风险。所以我们强烈建议大家在一个风险可控的环境当中运用。
- 采用区在最内层,强烈建议大家采用。
所以大家在看项目里面的每一个item的时候,一定要结合它所在的区域,放在一个暂缓区和一个采用区是不一样的。
持续集成持续交付的发展
2010年的一月份我们已经在实验阶段里面提出了Continue Deployment,持续部署。
2011年的7月份,我们将持续部署变成了持续交付,并且把它移到了采用的区域里面,同时写了一本书叫Continuous Deployment。
持续部署跟持续交付有什么区别?为什么把持续部署更名为持续交付呢?通常认为我们只要不断的持续把产品部署到产品环境,或者把app交到客户的手中,就叫持续的交付,其实不对。
持续部署是一个部署的过程。
持续交付,交付的不是产品,而是产品背后的价值。我们要保证这个价值是有用、有质量保障、并且是客户需要的。持续交付其实是一种开发的方式 : 构建产品需要保证在任何时间都有把它交给客户的能力。而不是说要一直不停地交付。如果你需要,我现在就可以给你,如果你不需要,那我也会持续的给你提供这种随时准备的能力,叫持续交付。
现在大部分人,包括敏捷,都采用迭代的方式。比如画一个蒙娜丽莎,是通过迭代的方式不断的把它完善。在持续交付之前,我们迭代,还可以采用任何一种敏捷的方式,临上线了再最终集成,把它release给客户。而如果采用持续交付,会是小步快跑。最小步的极限就是,每一个commit都有可能变为产品的最终形态发布到产品合作商。那我们每一个commit有可能它就具备发布到产品环境的能力。我们认为这才叫持续交付,而不是一键部署的能力。
2012年的3月,持续交付就已经有了一个非常大的发展,技术雷达上出现了大量跟持续交付相关的内容。比如说我们要做数据库的智能部署,要做对于部署的可视化,我只要做一个自动化脚本然后一个点button,它看起来很简单。但这属于部署,我们要做持续交付的话,你不能保证你部署方案的东西是没有问题的。能不能做一种快速的回归,包括对产品环境的监控,这些都需要整个的生态环境,一套系统来支持,而不光是一套固定的脚本。
基础设施自动化 : 我们内部一般认为注释写多了不好。因为你的代码不能描述你代码本身的功能,必须通过注释来附加,说明代码不够clear。如果你一个人走了,之后就没有人可以维护你的基础设施,那证明你的基础设施没有做到足够好。我们经常说代码即文档,你需要把它作为代码,或者作为容器,把它沉淀下来,这就是我们说的基础设施自动化。
对于持续交付来讲,我们一般讨论三件事情:实践、工具和人。
从技术雷达看持续交付
首先,我们一开始认为持续交付只是一个流程,我们从提交代码开始,做自动化的构建、设置、部署、交付给客户。很多时候我们认为,持续交付主要解决的问题是部署问题。如果把这个产品自动化部署了,我们的产品环境就可以持续的交付了。我们知道,如果要想做好持续交付,是要从提交开始做起的。
第一个要讲的内容就是功能开关Feature Toggle,它允许我们没有伤害的,将我们的功能随时的发布到产品环境上。
我们在12年10月份的时候,已经把功能分支Feature Branching放到了暂缓区域。功能分支,就是我做一个新的功能我就要先拉一个分支出来。但我们认为它是在暂缓,你尽量避免用,要思考下为什么你要做这件事情。
我们在15年5月份把长生命周期Gitflow放到了暂缓区域,现在如果你去看社区,仍然在发Gitflow的文章,我们发了一篇叫Gitflow的有害论,其实在这里会引起比较大的反响。那是一种组织开发的方式。
Gitflow
是一种开发的方式。如果一个很简单的项目,维护一个Master,主干分支。每一份提交就是一次release。但并不一定你每一次提交都可以发布到产品环境,所以需要一个开发分支,按功能分支,邮件功能报表功能,做完回复(Merge)到分支里。然后发现1.0版本有问题,拉一个Hotfix分支。来一个发布分支(Release),这样我发布1.0版本,同时也在做2.0版本的功能。
它的问题在于,你每一个merge的点都是集成的过程,如果你落了一个分支,那就代表你已经在避免持续集成。就是为了隔离开才要拉一个分支,因为这个功能我现在不想merge,想放到最后一起集成。但是,只有master的线才会被连接到持续集成的pipeline,里面的过程就没有办法做到持续交付。
我们要做这种以主干分支为基础的开发方式。
主干连着持续交付的pipeline,开发的时候直接check out到本地的环境,做完直接提交。但是有一个问题,假设你做的是2.0的功能,你还没做完,很多的功能是一半的,你直接把它push到产品环境,比如这个功能做了一半,我虽然还能上传文件,但是它只有一半的功能,那客户用了之后就会出现问题。所以需要Feature Toggles。
Feature Toggles
我们可以建一些开关,把某些功能关掉,把某些功能开启。这个开关可以是在代码里面,也可以数据库一张表。功能只要不想让客户看到,我就把它开关先关着,这样我们就可以做到持续的交付。
13年5月份的时候,我们提出了自动化部署流水线,以及在云环境做持续交付和持续部署,当时是在实验阶段。现在已经有一些软件,阿里的云平台就是这样的工具。
16年4月份,我们说要将部署同release分离出来。有人可能会觉得做一次部署就是做一次交付,其实这是不对的。工作还没有做完,但我就已经可以部署了,但我并没有release,只不过在Feature Toggle打开之前,它一直属于一个没有release的状态.。
持续构建的工具
部署流水线对于持续交付是一条命。
持续构建的工具常用的是Jenkins,但它更多关注的是持续集成,它关注比如说代码提交设置能不能通过,能不能出包。这还是在对一个局部来进行集成的工作,而并不是一条流水线的概念。有人说可以装插件,很多pipeline的插件做到了持续交付。但我们认为它仍然把关注点更多的放在持续集成上,没有把持续交付的流水线放到它的core内容里,它仍然是以插件的方式提供的。如果你的pipeline够复杂,你会发现Jenkins非常难管理。
我们公司的Go.CD是以deliver为主,原生支持流水线,提供的可视化非常好。
这一期技术雷达还推荐了一个CI工具叫Compose,界面非常精美,
Build Pipelines as code
持续交付的一个原则是自动化可以自动化的的所有事情,包括版本控制。Pipeline能不能做到自动化?我们自己项目也遇到过问题。我们有一个非常大的Go的Server,配置非常复杂的一个xml,有一天一些机器挂了,我们恢复Go整整用了一周的时间。但如果代码提交到Git,其实就牵涉不到恢复的问题。
大家在说持续交付的时候,都会谈论到一条很清晰的路线。我们在11年的时候就提出架构是需要演进的。现在随着架构的演进,我们没有一个架构是这么简单的。
最近比较火的一种架构方式就是微服务,那我们看见,微服务架构是在2010年4月份提到的,单个的CI实例我们也把它放到暂缓区。例如一个60人的团队只有一个CI,我们认为是有问题的。比如说,一开始项目开始非常的简单,非常的优雅,只有一条pipeline,每天产品交付。随着我们的服务划分,随着系统复杂度的增加,服务都会集成统一的发布,这时候有什么问题?你在集成的这个点其实是个堵塞的点,一旦集成出了问题,所有的pipeline都需要重做。如果我第二条一提交,导致我中间的集成坏掉,那我第一个第三个就不能提交了。这样的话我们没办法做持续的集成。
测试
我们要做pipeline这种提交方式,提交之后要有一条清晰的判断。可以通过一些以判断为核心概念的,包括以feature toggle为核心概念地部署流水线,持续交付跟持续部署很大的一个区别是,交付不能让用户的产品环境出问题。我们需要在开发过程中,对我们的产品进行各个层次不断的验证,就需要一套完整的测试和保证。
- 集成测试
它很重,很难修,而且依赖于环境,而且也没有人对它负责,因为每个人都关注自己产品的。
- 约定测试
我们约定把contract本身写成一个测试。根据我的调用,自动生成一个契约。现在有很多工具支持它这种contract测试,可以测服务间的集成。那每一个服务想部署到产品环境上,你不需要跟其他做真正的部署,你只要把作为所有的测试跑一遍,没有问题就可以部署。这样的话可以将我们把所有的服务产品,那个扣解开了。我们是可以做到更细腻度的,基于产品和服务级别的持续交付。
- 性能测试
我们能不能把UT作为一个功能一样保护你的性能。因为现在的产品性能是它产品的一部分,甚至都不存在功能性和非功能性的区别,你的产品慢就没有人用了。
- 其他
部署脚本也有测试,可以对部署脚本同样做重复做优化。
基础设施的准备,同样也可以有测试。
产品的视角改善也有测试。比如现在有一些工具可以基于于这种截图方式,做截图的页面对比。
我们在很早之前就提出了测试金字塔的概念。它在流水线里面就会跑完所有的结点,在UT会跑70、80%,这样它可以做到快速反馈。因为UT反馈的力度比较强,它跑起来非常快,在我们的判断里面比较靠前的阶段;所以从这个阶段来讲,我们可以得到这种快速的反馈,甚至在提交之前我们就可以知道现在有功能被破坏了。
基础设施自动化
在16的4月份,和13年5月份,我们就提出了不要再用application server,tomcat这些,因为它很难被自动化。
第一代自动化是我们自己写脚本,get一个包,然后把它移到那块儿。Ant和Maven是我们第一代。它是声明式,基于结果的。
第二代是什么?比如后来说Ansible,以及说的Tarraform,可以做云设施的基础设施自动化。
3.0就是Docker。
Docker
之前也说到,集装箱改变我们的世界。容器给我们提供了标准化、一致性,隔离以及分装。通过它,我们部署很简单,就把项目从这儿翻上船,再弄一根线这么简单。以后有可能我们不再关注是DB,微服务,后台服务,或者是一个什么网站,最后都是Docker。我们就用Docker把它拼装起来,包到箱子里pull到开发环境、产品环境,测试环境。基础设施的管理可能会很简单,你只要把你的东西在构建产品的时候创建一个Docker就行。
最新的,还有一些新的架构像无服务器架构。无服务器架构就是说,像函数式一样,我输入,你计算结果给我。把函数pull上去,它就会启动后台,就已经进行了结果的交流。
DevOps
我们对于代码的重构,对于架构的重构,包括产品的发布,是不是可以做到Health check ?我旧的1.0放在那儿,我把2.0发布测试没问题了,就切换过去使用。有问题再切换回来使用。我觉得如果系统这么去部署,那10分钟用不着就可以了。
我们可以构建一套凤凰环境,凤凰涅盘是吧?比如包括一些现在的工具,把这个工具放到环境里,它会定期的随机给我制造一些各种各样的问题,比如把服务器的网断了,把那台数据库的内容某个文件删了,把某个文件的系统目录给隔离。这种工具我放在一个环境里,把产品持续地经过这样一个环境,它是不是可以帮我验证,在这种复杂不可控的环境下,我的系统是不是可以做到足够的健壮?
我们很早就认为,日志是数据,你不要出问题就找它。要把它结构化,需要把它可以做的可以修复,甚至可以统计。这样可以帮我们在客户之前发现问题,在过程中改进。包括一些常规的系统和服务器监控的稳定,这些其实都可以做到早发现问题、提前避免问题,让我们产品更有信心的持续交付到环境下。
从人的角度看持续交付
康威定律 : 设计系统的组织及产生的设计和架构,等同于组织间的沟通。
康威逆定律 : 如果你想改进你的架构,改进这种开发的方式,必须要逐渐的改进你团队和组织的结构,才能保证你想达到的最终的一种在技术上的改进可以成功。
这是我们理想中的,一个持续的在微服务架构下的一个持续交付的流水线。但是这个项目没想象那么顺畅。比如说开发不断的在提交,测试团队来测试,有专门一帮人做集成测试,有一些运维人帮做发布,要是这样,它就像一堵墙一样。提交的还没测,那我不管,反正我就继续提交,但是测试完了,那边干嘛不过啊?
我们希望把组织打平,像特种兵团队,一个个角色为了达到一个目标统一地配合。只有这样这条路才能畅通,我们才能做到实际的持续交付。
关于分享者
王健
ThoughtWorks首席咨询师。一直从事国内外大型企业级软件的设计与开发。做过架构师,当过 PM ,干过咨询,一直保持着对技术的热爱,享受着编码的快乐,热衷于技术分享。