作者简介 大家好,我是王鹏,目前在美团点评的酒旅研发团队负责工具链。今天我给大家分享的是在我们内部已经运转了一年多快两年的“持续交付工具链”的实践。
这个标题前面的定语有两个含义,第一反应了持续交付工具链的有效和高效性,第二是工具链的核心点“触发”,为什么说触发是其中的一个核心点?我后面再给大家详细介绍。
这张图大致可以反映一个研发团队的研发生产力情况,大家从上面可以看到每天、每周、每月的Push和PR情况(当然实际的数字远大于标称的),版本管理、代码管理工具采用git的同学应该都知道的。
今天我主要从以上四个方面给大家讲一下,第一个是持续交付,持续交付是什么、为什么、怎么做。第二是现在大部分公司已经应用了的微服务化。第三是结合实践,怎么从0到1打造一个高效的工具链。最后跟大家一起做一些深入的讨论和思考。
1. 持续交付
开始之前,我先做一个小的调查,在座有多少是开发团队的?有多少是测试团队或者工程质量团队的?大家都是产品或者运维的同学吗?其实我想说什么呢?持续交付工具链跟我们的研发团队,PM,RD,QA组成一个研发团队,紧密相关。持续交付工具链能够帮助我们整个研发团队高效协同。
首先我们看一下持续交付到底是什么,我们经常会说持续交付、敏捷开发、持续集成、持续部署、DevOps,刚刚顾宇老师把 DevOps 的最新实践给大家做了介绍。通常怎么区分这些呢?大家可以看下这张图,看看自己的团队目前处在哪个环节。
我们今天说持续交付和持续部署的区别,这里有一个定义,上面的英文定义是我从wiki里摘取的大家都认可的定义。
持续交付是一个软件工程的方法,能够帮助开发团队很快的生产软件,在一个很短的周期内,生产保证这个软件以更可靠的方式发布,任何时候都可以发布,而且有必要的情况下手动发布到生产环境。英文比较绕,英文怎么理解它呢?我认为是“一个研发团队如何将想法/feature/服务,快速交付给最终用户的方法”,这些方法最终会落地到工具链上。
为什么我们要做持续交付?我觉得这个可能不需要太多给大家强调,因为所有参加DevOps会议的人都有一个目标,希望能够提高研发生产力、提高公司或者团队或者个人的交付效率,这个交付效率怎么去衡量?我们怎么样去把一个想法变成产品、变成最终交付给用户的服务的周期能够变短?交付质量怎么样在这个过程中能够提升起来?怎么样做到快速的反馈、质量的闭环,还有RD、QA、SRE怎么做到无缝协同?这些通过持续交付工具链都可以完成。另外是通过后台技术架构微服务化的做法,我们怎么样做到高效的工程效率和工程质量。
刚才说了一些是什么、为什么要做;我们再看看要达到这些目标面临哪些障碍?这是一个调查,跟我们的内部实践也非常接近,最大的是一个公司或者一个团队的组织文化,或者我们通常说的工程师文化主导的公司或者团队更有优势一些。
另外是在开发、运维、甚至包括测试团队的合作上,平常可能没有什么事情的时候还好,但是通常情况下一出了事故开发和运维之间就开始互相扯皮、互相甩锅,所以这个合作上也是有很大的问题。另外是技术障碍,技术障碍有两种,一种是公司内部的研发基础设施,另外一种是持续交付工具大规模基础架构,还有缺乏理解。
两年前我们从底层做起实施的时候也面临这些问题,具体怎么做?公司有没有效率为先、质量为先的工程师文化氛围,第二是结合公司的业务、技术架构、公司团队能力是什么样的,缺少以上条件强制引入持续交付,不对公司业务、技术、团队进行深入分析和基于现状做升级,其实都会背道而驰。
能不能做好持续交付?公司的现有研发基础设施很重要,我一会儿讲到实践环节的时候,你会发现很多时候,我们不是被选择某一个工具挡住了,可能是公司测试环境不具备、自动化测试不具备、各种各样的基础条件不具备挡住了,你要一个一个点解决问题,你会非常痛苦,你搞了好几年都搞不出来,可能抱怨这个、抱怨那个,但是这些最终还是要去解决的。另外一个是要选择合适的CI/CD工具,还有自动化测试,自动化测试在这里是一个很重要的环节。
右边的图是现在很容易看到的,不管是特斯拉、还是丰田等汽车厂商,其实现在已经在汽车的生产上,当供应商送来零部件,全自动化的生产整车很快就能完成,不管是从汽车安装、喷漆全套出来基本上接近全自动。
但是我们号称互联网要去改造传统行业、改造什么的时候,我们会发现还是要手工环节,还是要各个不同系统之间手工构建、手工打包、手工部署、搭建测试环境、手工发布,这个还是一个很常见的现象。去年我在北京的一个分享上和大家了解到的实际情况是,大部分团队其实还是处于这种现状。
这个是 DevOps 或者持续交付所用到的所有工具的一个集合体,目前不管从构建的环节、运维的、部署等环节都有大量工具可以用,实际上我们在每个环节上都不缺乏称手的或者可用的工具,或者说我们公司特殊用不了这个、用不了那个的情况。CI/CD工具,从全球最大的某交友网站上看,这两个占比比较高,很正常。大部分公司我了解到的,背后实际上大部分用的还是Jenkins,63%基本上都选择Jenkins作为CI/CD工具,当然还有一些其它的。
实际Jenkins这几年的发展也非常快,我这里不是给 Jenkins 做广告,我们团队也是基于Jenkins打造CI/CD工具本身,另外在去年年初的时候 Jenkins 的作者来我司做了一次深入的分享讨论。目前大部分团队还是停留在Jenkins1.x年代,但是从2014、2015年开始,Jenkins已经迈入2.0阶段,就是Pipeline as Code,这个非常重要,因为现在多仓库、多模块、多任务、多stage是一个很普遍的现象,动态分配的测试环境也是被广泛运用的。
再看看业务技术和团队,第一是为什么要看业务呢?因为不同的业务对集成的要求是不一样的。比如说像微软的office和windows交付周期都很长,一年、两年、三年。传统公司一套主机控制软件大概5个G的代码两张DVD光盘,每个项目即使有之前的积累最短也要一年以上,这样的交付周期是非常长的。
交付质量要求也是不一样的,像医疗器械厂商有一个是FDA或者审查,非常严格的审查,另外它是人命关天的事情,如果你做任何一个手术的时候down机了,用户可能直接挂在手术台上了。但互联网公司的交付周期肯定是不一样的。
另外一个,你所在的公司的业务技术栈是什么,环境、框架、监控、反馈,还有团队规模、开发模式,只有一两个人的时候只要简单的环境搭在那里就可以了,当你有上百人或者上千人团队的时候,这样做肯定是不行的,你需要一套持续交付工具链的可扩展架构,最终持续交付可以帮助研发团队实现更快的向用户交付。
接下来的分享,给大家介绍一下我们是怎样从0到1打造高效持续交付工具链。第一是一定要基于公司现有的研发基础设施现状,第二是使用开源的CI/CD工具,不要指望着说我买一套什么或者直接在某某云上用DevOps,可能一些刚起步的公司适合这种情况,但是上千人规模的公司有一套工具链是非常必要的。第三是零成本打造持续交付工具链,基于开源的框架和基础设施。
2. 微服务
我刚工作的时候业界主要是单体系统,大部分的项目的周期都在一两年或以上,做完可能几张DVD光盘或ISO包向用户交付最终的软件,后面构建打包安装差不多要花一天时间。
当时我们也做了一些改进,就是把时间降到几个小时,把它分模块、分布式构建,用各种各样的RPM包打在一起。后来加入美团点评之后,美团旅行的业务大概是这样的,一个是有面向用户的美团和点评两个超级APP,另外一个是面向生态端的有酒店、旅游B端的APP。另外在主要APP上面境外度假、境内度假等,有这些频道。这些APP和频道背后基本上是成千上万的微服务。
本来我们觉得微服务之后可能世界会清晰很多,结果微服务化后各个服务间的调用关系变得纷繁复杂,这个怎么做?仔细分析之后,实际上单体和微服务架构各有各的优势、各有各的劣势、面临一些挑战。
一开始刚刚起步的公司,其实也不用追求微服务架构,选择合适的架构快速支持业务,不要追求潮流。对于大规模的公司面临每天上亿流量的情况下,可以横向扩展和部署,需要多个团队之间很好的协作,并且各个服务之间又能够独立开发,独立运营和独立测试。
对于这些挑战,我都是亲身经历过的,当时我们面临一个跨国的团队,很多团队协同,非常痛苦。每天不同的时区,大家的接口定义调用怎么做,维护的成本、打包、构件不同的协同,用复杂性理解,基本上到最后只有架构师很多年才能全部掌握,扩展起来非常困难。只能单方面提升你的硬件能力。
互联网后台服务就好多了,微服务进行横向扩展和部署,很快性能跟上去了。
3. 我们的实践
再回到我们刚才说的业务是怎样的,当时我们面临的一个情况,这是美团点评之前的研发基础设施,在构建环节内部有后台的、安卓的、测试系统、部署系统、测试环境、代码管理等,实际上大部分也是在开源框架基础上构建的。还有监控的,系统监控,还有CAT目前开源到3.0,天网是我们内部级业务监控系统。
上面的绿巨人是我们基础的弹性伸缩容器平台,Cargo在HULK系统上构建了一套动态的测试环境管理系统。PLUS是我们的一个发布系统。
接下来说一说我们是如何从0到1做好持续交付工具链。第一个是路径规划,前面我说了,要做到这些第一是从你的业务出发,搞清楚你的研发基础设施、搞清楚公司内部的环境,相应的配置中心是什么样的,接入,触发场景,自动化测试建设怎么样,整体自动化测试是一个什么样的覆盖情况,虽然说我们不强调100%覆盖或者怎么样,但是覆盖是符合自动化测试建设水平的。整个质量准入是怎么做到的,反馈机制怎么样快速反馈给相应用户,还有一个落地运营。
最终的总结,我们认为要有一个Pipeline引擎,有一套测试环境,我们公司叫做Cargo,实际上是类似于K8S的弹性伸缩的容器环境。还有一个配置中心,这个我们团队开发的叫CodeQuality。另外还需要一套触发机制,这个触发我们称之为Hook Service,需要一套统一的触发机制,能够做服务扩展。
这是一个更详细的,我们要搞清楚一家公司从代码管理、发布系统、测试环境、容器平台、CI工具、在微服务架构上的服务治理、项目管理、开发框架、测试框架、构建工具、通信工具、监控工具,监控可以帮助你很快的反馈你的服务部署完的实时状况或者构建过程中的状况或者服务运转的一些情况。
看起来很清楚,但是实际上真正动手建设的时候,你会发现挑战非常多。一个是测试环境是一个很大的问题,你的测试环境搭建常规情况下用几个物理机或者虚拟机很快就搭建出一套测试环境来,但是当你面临上千个团队或者成千上万个仓库服务的时候,你的测试环境怎么样快速的伸缩、扩展,因为很多情况下是先部署再测试的。架构跑起来你会发现出现各种问题,什么问题呢?整个CI工具不工作了,高峰期的时候能不能扛的住。
大家可以从刚才图的上可以看到,每周一、周二、周三是代码的高峰期,其实每天下午2点到6点间基本上是所有的互联网公司都是一样的产出代码最高的高峰期,在这个高峰期你的测试环境也不够用,然后就卡住了,你所谓的持续交付就停在这儿了。
现有的也存在很多问题,虽然插件架构设计得非常好,但是实际上很多插件没有更新。我们还做了两个,比如说你会面临多个仓库怎么样同时获取Cargo覆盖率,有的直接互相之间覆盖了,你能取到有一个,有的时候你所依赖的基础服务都挂掉了,你有紧急上线怎么解决,各种各样的问题,我就不一一细细说了。
详细说一下测试环境,公司基础架构提供了一套泳道的机制,它的基本机制是因为微服务有时候链路会非常长,我见过一个业务线差不多所有的服务加起来4、500个,其实也就可能是某一个频道的。
你每一次都把4、500个服务一下子都布、一下子都弄,消耗非常大,只是其中一两个服务或者最多十几个服务。这种泳道的架构可以为大家提供什么帮助呢?你可以先部署好一个骨干链路,这是常规不变的服务,其实也代表了当前你的现实跟当前现象部署的服务都是一模一样的。
另外你可以提供这种泳道,像我们游泳池里面人为划分出来的泳道一样,这里有一个基本约定,当泳道存在这个服务的时候请求是不会被打到主干上去的,当这个服务泳道里没有的时候就会自动打到主干。
这解决了一个什么问题呢?当你部署或者是监控的时候,你可以只用布AB两个服务,剩下的C在泳道里面找不到就自动到主干上寻找,这样可以帮大家搭建一个最小化的很快构建出弹性的测试环境,而且各个项目之间是完全隔离的,完全可以做开发,互相不干扰,而且可以共享。我们可以解决稳定性监控,目前能够保证到链路的稳定性。
接下来是配置中心,实际上大家知道通常我们的一个仓库或者一个服务跟我们的自动化测试、项目干系人和各种构件方式、部署方式、综合测试、其它等等一些信息基本上是完全分开的,也没有办法做到当你想通知谁的时候去通知谁,这是仓库中心和结果展示中心,可以方便的把这些关联起来,剩下是一些自动获取。
再接下来说接入部分,测试团队需要一个前置的质量准入,开发团队也想自动的做代码质量检查,CR,但是苦于没有办法,只能平常通过在群里面说、跟同学们强调、大家形成一些wiki上的流程规范,很难有效的运转起来。在公司内部基本上有成千上万个仓库、服务,你需要一个个去配也是很痛苦的事情。
我们实现了自动接入,当一个仓库被创建出来的时候,它就自动的被配置到相应的持续交付Pipeline工具链,默认Master分支作为主分支,默认做一些质量检查,其它是可以自定义调节的,你可以变更你的配置。一个仓库可以配置多条自动交付Pipeline的。下面是我们每次都会推送的,哪些已经自动接入了,提示相应开发同学和测试同学做配置。除了排除不打算上线的仓库之外,目前只是作为一些调研的,基本上99.9%的仓库已经全部接入。
再一个是触发,前面我说到触发是里面的一个核心条件,为什么呢?这中间有4个核心点,第一个是自动触发,不要每一个环节都让大家跑到某个系统UI里面点一下,你应该做到用户是无感知的,当用户Push代码的时候做自动的代码检查,当他做PR的时候,不管是向Master PR还是往其它分支PR的时候,这是代码准入,可以做相应的检查。
还有一个是提测,基本上我所知道的大部分公司都会存在这样的多多少少的测试系统,在持续交付工具链里面提测触发可以帮助大家做到自动提测,当你的代码开发完以后你只需要填几个必要条件,相应提测就会被触发出来,验证提测结果会发给相应的QA同学,通过后就会到QA同学那里流转,如果没有通过就要做进一步修改代码,要重新去做。还有一个是集成,再另外一个是上线,这是大致的一个示意图。
另外一方面是自动化测试,实际上要让持续交付工具链很好的运转起来,最后达到持续部署,自动化测试的建设是中间很重要的一步。因为功能测试、集成测试的质量把控,最终要靠自动化测试来完成,代替人工的测试去完成。通常所说的一个测试金字塔,越往底下成本越低,越往上维护的稳定性没有那么高,维护成本很高。
美团内部主要是两种接口:HTTP、Thrift,两种接口有不同的框架,当把这些东西集成在一起的时候,面临一个麻烦的问题是各种框架的统一,维护起来非常麻烦,产生的结果和各种各样的构建运转都会出现各种各样的问题,统一测试框架是非常必要的,可以降低开发成本,框架一致、维护方式一致的情况下,不管是哪个同学维护结构都是一样,只需要配相应的数据。
我们希望能够做到几个设计原则,第一是代码组织标准化,你看这些结构都是一致的,只要熟悉开发的同学都能够很快的上手,接管不同业务线的自动化测试case。另外一个是技术栈标准化,不管是底层做校验的、还有HTTP,我们都用统一的框架做封装。
另外怎么做到数据驱动,用更少的代码,我们会自动生成框架性代码,更加标准化,但是也不剥夺大家开发的权利,不是说完全变成一个在上面点点点的UI式综合性测试开发,更多的是校验。
质量准入,这个点也非常重要。我们从4个环节:自测、提测、集成测试、上线前测试,4个不同的研发阶段给不同的质量准入。自测主要是反馈快,基本上是几十秒内就可以反馈相应结果,告诉你提交的代码质量如何,主要是做静态和代码的分析。针对提测会更多,冒烟测试、自动部署、代码冲突检查、分支规范检查等。
反馈机制:每次Push代码、PR代码等都会有相应的IM消息通知,git系统Comments通知,告诉你通过还是被打回了,PR、Push检查通过,你的结果是怎样的,蓝色字体方面是相应链接,可以点击进去查看更详细的进一步的信息。当你提一个PR的时候,因为公司目前所有的代码管理都在上面,一个PR提出来是什么样的状况。如果没有就打回,你再修改。
这是持续交付工具链的大致架构图,基础层是内部的研发基础设施和服务,CI工具,现在用的是2.X版本,Cargo测试环境,Pixel Jar包管理系统,Plus发布系统,JIRA项目管理系统等;在服务层自动接入、触发服务,忽略一些没有那么严重的问题,快速上线。综合测试框架,需要配置中心和结构展示中心,还有相应消息中心接管通知到不同的各方。
Moka是Mock系统,因为微服务链路非常长,不可能把所有服务都搭一遍,或者你需要短链路测试的时候,Mock是最佳的选择,而且更加稳定。
因为有时候涉及到第三方依赖的或者外部依赖的,你没法控制对方的服务稳定性的时候,你把它Moka掉是非常好的选择。在应用层我们提供自测Pipeline、提测Pipeline、集成Pipeline、发布Pipeline,监控也是分了多级监控、业务系统监控、服务监控、缓存机制。
持续交付工具链自身也是分层的微服务架构设计;高峰期执行机够不够用,可靠性够不够。我们内部做了多Master、多slave集群的架构,我们高峰期会自动扩容。Master我们内部是两个集群,在这种情况下才能支撑每天大概上万次、一个月大概十几万次的持续交付Pipeline。
我不知道有没有同学关注过最新的在今年4月份Jenkins官方推出JenkinsX的项目,应该属于Jenkins的子项目。实际上这个X的架构跟我们去年的设计是不谋而合的,也是在K8S上直接部署Jenkins,支持slaves的扩展,我们也在试验采用JenkinsX替换老的设计。
这是持续交付Pipeline的运行机制,当你在分支Push代码的时候会收到这样的同志,合并代码到非主分支会有这样反馈。当合并代码道主分支的时候链路会更长,检查会更充分。同时我们刚才说到还有一个提测Pipeline,未通过提测系统的需求和自行上线的需求都会有相应标志,我们会打上相应的标志,一些预算合并分支就删除掉了。
在紧急状况下,一个是你可以跳过申请检查,因为我们已经假定基础服务不是那么稳定的,我们时刻做到跳过检查,让它不上线,但是跳过要防止被滥用,我们后台做了相应记录,要有相应的同学去批准,而且每周有相应周报发出来,告诉大家哪些可能是被滥用的,都会发给相应的质量负责人。
另外一点,我们会做自动的服务降级,也有手动的服务降级,当然底层的不管是代码管理、测试环境管理、Jenkins本身、弹性伸缩容器平台基础设施故障的时候,能够让它做自动的服务。
回到我最前面跟大家说的后台最终结果图,这是5周、一个月,可以明显看到周一开始爬坡,周二、周三、周四基本上到了一个顶峰,大家开发代码的Push和PR的情况。周四、周五的时候还是有几十个同学还在加班写代码,对代码有多么的热爱,周末还在加班去做。周五会慢慢降下来,你提交了也没有人测试,也没法上线,大家会把这样的工作慢慢降下来。每周大概在十几万,每个月就更多了。还有一个数据比较关系,就是Push和PR的关系,基本上一次Push会有几次PR。
持续交付工具链可以反映出整个研发团队的研发生产力的情况、研发效率、研发质量,你在这个环节不管是代码分析、接口测试、集成测试、上线前全链路测试、场景测试、功能测试的情况,其实可以很清楚的反馈出每个团队或者每个个体的开发能力、开发质量、开发效率。所以这个的建设不仅提升了整个团队的研发效率,也能够提高研发质量,能够清晰的看到每个团队的能力状况。
4. 一些思考
最后给大家回顾一下,怎么样从0到1建设持续交付工具链的情况。第一是找准切入点非常重要,不是说一开始就要直接买一套什么工具或者搭一套什么工具就用起来,刚才说到从业务、研发基础设施、团队的基础情况搞清楚,找到切入点。最早的时候是从代码扫描入手,给大家提供最基础的服务,当你Push代码的时候自动帮你做代码分析扫描,慢慢扩展到整体的持续交付系统。因为你要建立自动化测试环境、自动化测试框架,让它的稳定性达到一定程度。
第二是不要从开头开始造轮子,这是不好的,我要自己写一套,陷入这种环节永远达不到效果。先解决最关键的问题,比如说代码问题先解决。
第三是在这条路上是没有捷径的,不是做完了持续集成就完了,下一步还要持续交付、持续部署,工具链本身要不断迭代和演化,走敏捷开发路径。
第四是我们认为最好的工具链是有效的,其次是高效的,反应非常快,第三是无感知的,无感知不是不知道,而是它在背后悄悄为你服务,不需要你配这个、点这个、点那个,你只需要Push代码、PR代码,其它都来了。你在这里要让它落地真正的运营发挥作用,自动接入、自动触发、质量准入、自动运营这4个点是非常重要的。
我们从思维模式到工具框架,平常做的时候一开始先有一个开放的思维模式和封闭的思维模式,另外要接受持续迭代改进,我们要认清楚持续交付的基本原则,找到在公司的实践模式,把它落实为一些流程规范。一开始只是纸面形式或者宣讲形式的要求,怎么样通过工具链把它落实到工具框架里,真正让它发挥作用。先在一个小团队或者是几个优秀的个人身上先做落地实践,保证先让个体接受,再提升整个团队的工程素养,让整个团队接受,最后把它发展成团队文化,是这样的一个倒三角。
做好这些之后,我刚才也说到,怎么样有一个代码质量方面的度量,我们内部会有一个度量。这些都是从工具链本身立马可以拿到的实际数据,在开发效率的提升上构建、打包、环境、联调都做到了,但是每个环节都有很大的空间可以挖掘,你的构建速度可能之前需要1分钟,你是不是可以直接把它压到几十秒或者10秒钟、几秒钟就完成了,你的环境自动伸缩能不能从分钟级的变成秒级的,你的联调效率能不能快速提升。测试的效率通常测试团队准备的时候、自动化测试准备、环境准备上都要花大量时间,持续交付工具链的体系下这些东西自动化可以帮你完成,你要做的事情是写好自动化测试,把这些以自动化测试通过持续交付工具链以质量服务的形式交付给开发的同学、交付给开发团队。
最终是怎么衡量交付效率,从代码到服务的Cycle time,通常有一个衡量标准是发一行代码放到网上需要花多长时间,我们现在是很快就能完成,包括测试。最终我认为持续交付是让整个研发团队高效协同的工具链,也能够做到质量服务化、测试服务化,最终通过持续交付工具链做到服务化,让大家高效的协同工作。
说明:本文为美团王鹏老师在 DOIS 2018 · 深圳站的分享。