摘要:随着持续集成技术的不断成熟,各种持续集成相关的开源和商用软件层出不穷,但是对于中小型企业的技术团队而言,往往在进行持续集成实践时会陷入工具之间的拉锯战。那么,对于中小团队而言,如何才能实现高效敏捷的持续集成方案?2017苏州云栖大会云效专场上,南京路特CTO、阿里云MVP戚俊结合实践经验为大家分享了中小团队持续集成之路。
以下内容根据演讲视频以及PPT整理而成。
虽然持续集成的概念已经火了很长时间了,但是因为各个企业的规模以及业务类型都不同,所以在持续集成中遇到的问题也各不相同。本次将结合南京路特的实践经验为大家分享中小团队的持续集成之路。本次的分享主要围绕着困境、敏捷开发、工具链、架构和收获这5个方面阐述路特自己所走过的持续集成之路。
困境
对于南京路特而言,在没有和阿里的云效平台结合之前所遇到的最为核心的3个问题就是成本问题、管理问题和效率问题。
将这3个问题更加细化拆分之后就是如下图所示的状态,如果大家也处于中小型团队之中可能也会遇到这些问题。
- 人力问题。首先,在中小型企业中,技术管理者会有很强烈的想法让专门的人来处理代码合并以及审查等工作,因为经常会出现因为某次发布没有做好代码审查导致出现故障的情况。我们希望在持续集成开始的道路之前就有专门的人来解决代码审查和合并问题。
- 资金问题。做持续集成将会面临一大堆的工具链的构建问题,这些工具部署完成之后是会带来成本的,首先是软硬件成本,因为无论是购买云服务器还是在本地搭建物理机来运行应用,都是会产生成本的。随之而来还会产生运维成本,因为只要是软件产品都是会出问题的,出现问题时需要人工解决,而人工最终也会转变成资金成本。
- 时间问题。为什么说在持续集成道路上一定会遇到时间问题呢?简单而言,使用一堆工具构建持续集成的工具链,最终实践的时候就会发现工具链会天天出问题,也可能是方法论思考的不是很透彻,而这些事情是不可能在做架构之前全部都预料到的。而一旦出现这些问题就需要拿出时间解决问题,这就会造成时间成本的上升。
- 效率问题。路特曾经遇到过一个问题就是在需要发布版本的时候,从开发、运维到测试,都非常希望整个公司的所有人都在场。出现这样的顾虑是因为过去在发布时所设计到的面非常广泛,会涉及到测试、打包、发布以及线上环境的替换等工作,如果这个过程一切顺利,只需要测试和运维这两个岗位配合就可以了,但是事实上却会遇到一些问题,比如开发人员在开发时使用了本地定制化的工具,而服务器上没有这个工具,而测试人员在本地进行测试时也忽略了这个问题,一旦发布到正式线上就会出现Bug,这时候发布失败就需要进行回滚。而如何处理这个Bug则需要决策者参与,需要决策者来判断是这个修复这个Bug的紧要程度。而如果需要现场修复Bug时也需要开发人员在现场解决紧急的问题。这样就从两个人的岗位变成了四个人的岗位,所以持续集成如果做不好带来的最大问题就是效率的下降。
- 管理问题。对于中小企业而言,往往没有专人负责管理问题。往往是新员工在HR那里办完手续入职之后,到部门主管那里用邮箱开通一系列工具的账号。如果企业拥有SSO,那么可以将这一系列工具串联起来使用一个账号,但是大部分中小型企业却不会自己搭建一个SSO门户管理整个企业内部的账号问题。另外一个问题就是代码权限,SSO解决的是账号一体化登录的问题,却无法解决代码权限问题。而这就造成需要一个权限非常高的人员每天守在电脑边为团队成员管理代码权限,而如果不管理权限,给每个人都是最高权限更会出现不可预测的问题。
平衡:敏捷开发与持续集成
在做持续集成的时候所需要面对的第一个问题就是如何协调敏捷开发与持续集成的关系。首先的一个问题就是需求及Bug如何尽快进入开发流程。路特是一家服务于媒体大数据的B2B公司,主要提供SaaS服务,所以需求的来源非常广泛,同时Bug来源也非常广泛,不光是测试人员会发现Bug,用户也会发现很多Bug,很多的需求和Bug都可能会来源于终端用户。而终端用户提出的问题要么是通过APP内部的问题反馈收集到的工单,要么就是直接打电话过来投诉。当问题反馈已经收集到了,如何将其尽快进入到流程中呢?路特在没有使用云效平台之前有自己的一套类OA系统来解决问题,将公司内部的Bug工单和需求都做了归类汇总,处理完成之后导入到JIRA里面去。当接入到云效之后,这件事情可以在云效平台里面创建需求和Bug并形成看板,之后再实现。
第二个问题就是开发成果如何快速试错。有时产品经理或者项目经理会遇到这样一个问题:有一个产品或者功能并不确定最终市场的反馈情况,但是觉得可以试一试,希望请开发人员在一周之内开发上线并让产品经理看到最终的用户反馈报告。正是因为这样的需求,导致之前路特每年也会上一两百个小模块,而到了第二年的时候就是大浪淘沙,一两百个小模块最终只剩下三五十个,但是中间的过程成本却是存在的,因为如果不上线就不知道产品的最终反馈如何。就路特本身而言,肯定会比自己的媒体客户更懂技术,但是在对行业的理解上却不如客户,而行业客户却未必能够用技术语言将需求描述得很好,所以更需要试错的过程,这就产生了对于持续集成生态链快速响应的要求。在使用云效平台之前试错是很麻烦的,即便是实现一个小的需求往往需要经历一两周才能随着大版本一起上线。
第三个问题如何依托持续集成完成快速迭代全流程。在持续集成搭建之前,在构建部分往往是“东一榔头,西一棒槌”的状态,在构建完之后通过Jenkins的发布组件发布到服务器,之后进行统一的批量更新。在接入到云效之后,就可以通过比较好的流水线的方式解决整个持续集成的发布迭代的过程,进而简化了整个过程。从需求、Bug进入到云效平台,到开发人员定向地针对这个需求拉分支进行单独开发、Push并触发自动构建、测试环境的自动部署等一系列流程完全都是自动完成的。
现有流程的梳理
如上图所示的是现有流程的梳理。在代码的管理上,会确保系统库中有三个代码分支:dev、rc和release,这三个分支是固定的,并且不允许任何开发人员push代码,因为代码的破坏往往发生在不经意的无心之失。现有的流程中,首先开发人员会拉一个dev分支并进行命名,之后进行开发,开发完成之后合并到dev上去,所以永远不可能出现将dev拉下来修改再提交的情况。当将代码合并到dev之后,在云效平台会完成一个dev代码的构建和测试,这部分根据选择的编程语言不同会产生不同的构建效果。单元测试通过之后会推送到dev测试环境,也就是将当前代码进行构建并运行单元测试,之后通知容器集群将镜像跑起来,然后就可以拿到配好域名的URL,之后就可以进行线上dev分支的代码测试。路特现在使用了阿里的ACM,可以帮助实现分布式的配置管理。因为容器的代码源都是一样的,但是又是无状态的,所以在代码中不可能出现写死使用的数据库或者缓存的情况,所以对于这套代码,如果可以在测试环境运行应该就能在正式环境运行,可以借助配置管理工具实现环境的区分和隔离。
这套流程执行起来是比较规范的,是通过平衡效率和风险实现的架构。但是问题是路特的产品线比较多,这就意味着整套流程需要跑四五次,所以如果不使用云效平台则会使得成本比较高,维护也比较麻烦。
平衡:持续集成与工具链
路特在应用持续集成工具链时也遇到了一些坑,第一个就是“用户坑”,使用的一些开源或者商用的集成管理工具都会产生一个问题就是用户无法管理。第二个问题就是“碎片数据坑”,路特使用Jenkins最顶峰的时候总共有6个节点,其中包括1个主控节点和5个构建节点,这就造成每次构建完成之后的日志无法进行管理,需要进行一系列的转化才能变成可视的内容报告,而这一系列转变却是非常困难的。并且Jenkins内跟踪的东西如何进入企业内部的知识库也是非常困难的,这些问题对于中小型企业而言往往是难以实现的。第三个就是“运维坑”,实现持续集成会使用到一系列的工具链,每个工具看似很稳定,但是当真正部署到线上,将几个工具串成一串使用的时候就会发现往往会出现一些莫名奇妙的问题。而这些问题就会给运维人员造成很大的伤害,因为所需要解决的属于周边性的问题,而非产品的问题,所以这使得运维人员会很累。使用的工具越多、越复杂,出现问题的频率也会越高,这就会形成一个死结。
钉钉+云效=更高效
路特结合上述的业务痛点在架构上进行了一定的调整,通过钉钉+云效可以完美地解决上述所有的问题。首先是代码权限问题,云效接入钉钉企业版之后,可以为新入职的员工分好组,员工就可以自动获取该组对应的Git代码。与此同时也解决了账号的问题,因为云效是一个一体化的平台,代码的构建工作全部都是在云效上面做的,使用钉钉账号就能进入云效平台,并且基于钉钉账号就能配置好代码管理权限。此外,对于流程控制而言,结合钉钉和云效开发也会非常方便。
路特和云效产品/团队的渊源
路特在最开始的时候没有使用任何阿里云的产品,而是通过自建的脚本进行构建和部署的,当时还涉及到使用Windows和Liunx两种平台以及三种语言进行构建。大概在2015年到2016年的时候,路特切入了阿里的CRP平台,这个平台可以视作现在云效平台的前身,但是其没有项目管理功能,只能进行构建和发布。而CRP平台一开始的时候对于一些构建方面的问题不能够很好地解决,并且对于新兴的技术和语言都不能很好的支持,虽然后来都支持了,但是却错过了路特调整架构的时机,所以后来路特放弃了CRP平台。之后,路特重新部署了Jenkins一系列工具,这套工具大概使用了一年多的时间,就遇到了前面所提到的痛点和问题,虽然这套工具链能够解决持续集成的每一个问题,但是串起来的过程却很痛苦。最后,在考察了云效平台之后,路特决定将所有业务迁移到云效平台上去。整个迁移的过程大概花费了3个月的时间,其中路特的技术团队和云效技术团队进行了广泛的合作,云效的团队也能够聆听用户的意见并且不断迭代和修复自己的产品。
基于云效平台的持续集成,路特也调整了自身的整体架构。之前没有使用Docker容器技术,而现在全部改成了微服务和容器的模式。用户的请求从公网进来到容器集群中去,容器集群再去分应用,应用里面有服务,服务里面有容器,目前云效平台可以做到在服务粒度的持续集成,这个粒度已经非常细化了,这离容器已经非常近了。
演进路线图——我们一直在试图寻找平衡
在2015年,路特的技术团队刚开始做持续集成的时候,采用的还不是容器模式,而是单独的分布式部署模式。在转向持续集成的时候发现,SVN的钩子比较少,所以将SVN换成了Git,因为Git的API和钩子都比较多,所以能够做的事情也非常丰富,不像SVN所能够定制化的点非常少。之后大概在2015年的下半年,实现了自定义脚本的构建和部署,因为涉及到3个语言2个平台,所以这个过程也非常痛苦,而自定义脚本也出现了非常多的发布事故。到2016年的时候,发现3种语言所造成的负担过大,所以调整成了容器架构,重构了一部分应用,尤其是使用Java重构一部分.Net的应用。大概在2017年初的时候达到了阵痛期,这个时期开源产品用的多了之后就感觉很难受,因为需要考虑各个工具之间的问题。经过多个开源产品之间的拉锯和抉择,在2017年末已经基本上全部切入到云效平台上,并且目前基本上已经稳定了。以上就是路特技术团队从2015年到2017年所做的关于持续集成的事情。
阶段性收获
- 通过阿里云系列服务及本身架构上的调整,目前在持续集成方面的成本上一年大约可以节约20-25万左右。
- 通过与钉钉等办公产品的有机结合,让持续集成的流程性变得更简单,且集成的过程变得更敏捷了。
- 多产品、多项目的持续集成通过云效的自定义流水线,可以解决原来的一些不够敏捷的问题,降低了中层成员的时间成本并提高了效率。