架构师讲述:KeyBank如何将交付从3个月变成一周
Raffaele Spazzoli是红帽PaaS和DevOps咨询部架构师,在加入红帽之前 ,他在KeyBank银行担任解决方案架构师。他所在的KeyBank银行是一家拥有190年历史、近两万名员工、遍布15个州、一千余分行的银行,支撑全球多个国家和地区的业务。根据客户的不同需求,IT团队针对不同的项目进行开发,但由于在银行内部存在着大量传统的IT系统,产品化的敏捷交付难以实现,这些项目的交付周期往往以季度计算,交付周期长,风险大。后来,在Raffaele团队的实践下,KeyBank银行实现了将交付周期变成一周,在本文中,他将以第一视角讲述这段神奇的经历。
起初的费时费力
这是超大型地区银行KeyBank将每季度向生产环境部署缩短到每周部署的历程。在这个过程中,我们全部采用开源软件从WebSphere迁移到Tomcat,并使用OpenShift作为私有Linux容器云平台。并且是在数字渠道现代化项目中做到这一点的,这是银行在当时最重要的项目。
数字渠道现代化项目的基本诉求,是将以Servlet为基础、在内部MVC框架之上开发完成,并在Java 1.6以及WebSphere 7.x上运行长达15年之久的Java Web应用程序迁移至更为现代的Web体验,由此创建一款新的移动Web应用。
经过长久的发展扩张,KeyBank银行原有Web应用程序的维护成本、特别是针对实际SLA要求的调整开销越来越昂贵。这是一款典型的单体式应用程序,而我们的架构升级目标在于创建新的API层,借此将表示逻辑(Web或移动)与业务逻辑拆分开来。很明显,要达成这项目标,我们首先需要实现持续集成与部署流程的全面现代化。
我们最初只能按季度发布新功能,整个发布过程费用昂贵、任务艰巨。之前的发布方式可以说充满了“仪式感”——我们还专门整理出一份Excel电子表格,其中囊括约70项手动操作步骤。因为费时费力,工作只能在周末完成,抢在周一上午之前让系统恢复在线状态并进行常规业务处理,这给我们带来了巨大的压力。
为此,我开始研究像谷歌、亚马逊、Facebook等科技巨头是如何管理自己的功能发布工作。很幸运,我有机会参加Netflix的运营方法研讨会。事实证明,从任何一项功能发布指标来看,如频率、成本、代码完成时间以及代码生产部署时间等,这些组织的效率能比我们高两到三个数量级。
于是,我决定把交付频率从季度发布转化为每周发布。坦率地讲,我对这个目标没有太认真地考虑,但我一直将它牢记在心。在我看来,银行数字渠道有希望实现每周发布。这个速度还没快到硅谷初创企业那种近乎荒谬的程度,但又已经足够快,强迫我们必须摆脱以往会议、手动测试加手动发布那种老派的运作模式。换句话说,这样的目标足以敦促我们做出改变。
我在项目中扮演的角色是解决方案架构师。为此,我推出了包含完全无状态REST服务层与两个前端的新架构:一个是基于AngularsJS的Web应用程序,另一个则是基于Ionic框架的移动应用(与Web应用大体基于相同的代码)。
改革进行中
首先,我要求对JDK进行更新(由版本6升级到版本7)。只有JDK完成更新,我才能使用JAX-RS编写REST服务。运营团队起初比较抗拒,但在意识到当前版本的JDK即将寿终正寝时,他们果断着手推进升级工作。整个过程大概用了6个月时间。
我还要求使用Liberty作为应用服务器。WebSphere在开发人员的笔记本电脑上启动速度太慢,一般在5到10分钟左右。考虑到即将开始实施的大项目,我们必须尽可能提高敏捷性与速度表现。有人提到,要想在笔记本电脑上使用Liberty,唯一的可行方案就是继续在生产应用服务器上使用WebSphere。这样的结论令我们难以接受,因为我们单凭直觉就知道提高产次对于加快运营速度的重要意义,否则任何对后续环境栈中的主要元素(IT、QA、生产等)做出变更时,必然会产生大量无法及时修复的bug。
为此,我需要一款分布式缓存工具,借此保证服务层始终保持完全无状态(而且无会话)。另外,出于效率的考量,我们同样需要缓存的加持。目前还没有官方支持的分布式缓存平台,但以后一定会有,我们得早点迈出这一步。
以上一切诉求,让我意识到这条路在规划阶段就存在问题。开发团队无法以正确的方式表达自己的需求,运营团队则太过强调维持正常的运行状态——而在这两者之间,解决方案架构师也没能组织起有效的对话,自然不可能以富有成效的方式做出领导与指引。
我觉得需要彻底改变这种模式,并且摒弃交付团队以前采用的复杂服务请求流程,改为由运营团队交付基础架构。另一个需要设立全新基础架构的团队。在其中一项研究中,我们发现运营团队要想建立一套全新的基础设施,需要满足大约四百项要求……不说要求本身能不能达成,光是沟通工作就足以拖垮两边的团队。
于是我转变了思路,觉得交付团队不妨自行配置基础设施。我得出的结论是,最好是选择一套私有云基础设施。为此,我开始独立进行研究,探索哪些工具选项最适合这种需求。与此同时,一支小型运营团队刚刚解决了一堆令人讨厌而且长期存在的网络问题。利用这批空闲劳动力,我们正好可以在KeyBank内部尝试建立私有云。
根据研究,我们确定Kubernetes是目前最理想的容器私有云平台。因为我们已经意识到容器在技术层面拥有远超虚拟机的优势,所以虚拟机云平台这一选项被直接否决。我们寻找为Kubernetes提供专业支持的机构,最终发现红帽及其OpenShift平台是极为可靠的选择。之后的工作开始顺利推进。与红帽合作之后,我们在4个月内就建立起了生产预览,并在7个月内开始向第一批客户提供生产支持。
我们将应用程序从WebSphere迁移到了Tomcat,将REST引擎由Wink转换为更流行的Jersey(此前在WebSphere中无法使用),而后添加了Hystrix,并向可用性策略中引入了断路器模式。最后,我们还使用Redis实现了分布式缓存。
但技术问题永远不是最困难的部分。我们的目标是实现每周发布,因此必须实现基础设施的自我配置能力与不变性。
持续交付管道实现全面自动化
为了达成这些目标,我们需要为部署在OpenShift中的应用程序定义所有权与支持模式。实际上,如果开发团队希望以自助方式管理基础设施,那又该由谁来提供技术支持?在观察谷歌、Netflix以及Spotify的业务体系后,我们发布了一套模型,其中由交付团队负责管理所需的基础设施(即在容器中添加的内容),而运营团队则负责保持OpenShift稳定可用——很明显,一切业务服务的可用性,都将直接由底层OpenShift的可用性所决定。此外,为了保证所有权明确清晰,我们决定将特定项目的OpenShift配置文件同项目的其余源代码统一起来。
我们采用以下逻辑在Jenkins中建立了一个流程:
• 每十分钟,源代码repo会接受一次轮询;一旦出现任何变更,则触发新的build。
• 此build将运行单元测试以及创建项目Docker镜像所需要的其他一系列操作步骤。完成之后,此Docker镜像永远不会进行后续变更。这也是我们实现不变基础设施的核心要点之一。
• 在解决方案的每个层上单独进行一系列集成测试。通过隔离,我们可以模拟出依赖项。以此为基础,我们即可脱离下游依赖项的可用性与测试数据质量,单独运行一系列测试。这些测试将在临时环境中运行,这一点在OpenShift中并不难做到。
• 在IT环境中运行一系列集成测试。
• 我们每天在QA环境上部署一次之前成功完成测试的build。QA环境用于手动探索性测试以及手动(后续计划改为自动)负载测试。
• 最后一步则是每周在生产预览环境中进行一次部署。这一步需要人工核准。
在生产环境中部署需要KeyBank的多次批准。这些批准以会议形式完成,即人们展示将部署的内容,而高级领导者签署发布命令。这个过程不适合我们,因为我们没有足够的时间每周举行三次会议(的确,这需要三个不同部门确信发布版本的合理性)。我们可以改变这样的流程,并且同意:如果一个版本仅影响OpenShift内部的组件,我们就自动批准该版本的发布。
最后一部分工作,就是建立起完整的自动回归测试套件。很快,我们从一系列痛苦的错误当中认识到,除非拥有完整的回归测试覆盖范围,否则我们永远不可能达到每周发布的目标。具体来讲,手动测试团队的处理速度,跟不上每周发布带来的巨量更新内容。
为此,我们以行为驱动型开发(BDD)原则为指引建立起测试框架。我们选择Cucumber作为DBB工具。Cucumber的最大优势,在于允许用户以自然语言(英语或其他语言)编写测试用例。我们决定发挥这一优势,由业务分析师团队负责编写测试用例。以此为基础,我们得以并行推进业务代码与测试代码的开发,而不再像过去那样必须先完成业务代码、之后才能进行(手动或自动)测试。我们还使用Selenium对Web应用进行浏览器与操作系统版本测试,并通过Appium对移动应用进行设备型号及操作系统版本测试。
总结
现在,我们已经对自己的发布流程拥有更强的信心。每周四上午,我们都能拿出一些最新成果,并通过OpenShift开箱即用的滚动部署功能实现零宕机发布。困扰了我们很多年的问题就这样被OpenShift的内置功能解决了……我们还启用了自动规模伸缩功能。通过在负载测试期间对这项功能进行的深入测试,我们意识到现有系统,或者至少在OpenShift中部署的各系统层内,完全可以通过横向扩展为负载峰值提供正确匹配的实例数量。
这在银行内部被认为是一个优秀的成功故事。下一步,我们将把同样的流程引入其他项目,逐步将更多工作负载迁移到OpenShift当中。