架構(gòu)師講述:KeyBank如何將交付從3個(gè)月變成一周
Raffaele Spazzoli是紅帽P(pán)aaS和DevOps咨詢部架構(gòu)師,在加入紅帽之前 ,他在KeyBank銀行擔(dān)任解決方案架構(gòu)師。他所在的KeyBank銀行是一家擁有190年歷史、近兩萬(wàn)名員工、遍布15個(gè)州、一千余分行的銀行,支撐全球多個(gè)國(guó)家和地區(qū)的業(yè)務(wù)。根據(jù)客戶的不同需求,IT團(tuán)隊(duì)針對(duì)不同的項(xiàng)目進(jìn)行開(kāi)發(fā),但由于在銀行內(nèi)部存在著大量傳統(tǒng)的IT系統(tǒng),產(chǎn)品化的敏捷交付難以實(shí)現(xiàn),這些項(xiàng)目的交付周期往往以季度計(jì)算,交付周期長(zhǎng),風(fēng)險(xiǎn)大。后來(lái),在Raffaele團(tuán)隊(duì)的實(shí)踐下,KeyBank銀行實(shí)現(xiàn)了將交付周期變成一周,在本文中,他將以第一視角講述這段神奇的經(jīng)歷。
起初的費(fèi)時(shí)費(fèi)力
這是超大型地區(qū)銀行KeyBank將每季度向生產(chǎn)環(huán)境部署縮短到每周部署的歷程。在這個(gè)過(guò)程中,我們?nèi)坎捎瞄_(kāi)源軟件從WebSphere遷移到Tomcat,并使用OpenShift作為私有Linux容器云平臺(tái)。并且是在數(shù)字渠道現(xiàn)代化項(xiàng)目中做到這一點(diǎn)的,這是銀行在當(dāng)時(shí)最重要的項(xiàng)目。
數(shù)字渠道現(xiàn)代化項(xiàng)目的基本訴求,是將以Servlet為基礎(chǔ)、在內(nèi)部MVC框架之上開(kāi)發(fā)完成,并在Java 1.6以及WebSphere 7.x上運(yùn)行長(zhǎng)達(dá)15年之久的Java Web應(yīng)用程序遷移至更為現(xiàn)代的Web體驗(yàn),由此創(chuàng)建一款新的移動(dòng)Web應(yīng)用。
經(jīng)過(guò)長(zhǎng)久的發(fā)展擴(kuò)張,KeyBank銀行原有Web應(yīng)用程序的維護(hù)成本、特別是針對(duì)實(shí)際SLA要求的調(diào)整開(kāi)銷越來(lái)越昂貴。這是一款典型的單體式應(yīng)用程序,而我們的架構(gòu)升級(jí)目標(biāo)在于創(chuàng)建新的API層,借此將表示邏輯(Web或移動(dòng))與業(yè)務(wù)邏輯拆分開(kāi)來(lái)。很明顯,要達(dá)成這項(xiàng)目標(biāo),我們首先需要實(shí)現(xiàn)持續(xù)集成與部署流程的全面現(xiàn)代化。
我們最初只能按季度發(fā)布新功能,整個(gè)發(fā)布過(guò)程費(fèi)用昂貴、任務(wù)艱巨。之前的發(fā)布方式可以說(shuō)充滿了“儀式感”——我們還專門(mén)整理出一份Excel電子表格,其中囊括約70項(xiàng)手動(dòng)操作步驟。因?yàn)橘M(fèi)時(shí)費(fèi)力,工作只能在周末完成,搶在周一上午之前讓系統(tǒng)恢復(fù)在線狀態(tài)并進(jìn)行常規(guī)業(yè)務(wù)處理,這給我們帶來(lái)了巨大的壓力。
為此,我開(kāi)始研究像谷歌、亞馬遜、Facebook等科技巨頭是如何管理自己的功能發(fā)布工作。很幸運(yùn),我有機(jī)會(huì)參加Netflix的運(yùn)營(yíng)方法研討會(huì)。事實(shí)證明,從任何一項(xiàng)功能發(fā)布指標(biāo)來(lái)看,如頻率、成本、代碼完成時(shí)間以及代碼生產(chǎn)部署時(shí)間等,這些組織的效率能比我們高兩到三個(gè)數(shù)量級(jí)。
于是,我決定把交付頻率從季度發(fā)布轉(zhuǎn)化為每周發(fā)布。坦率地講,我對(duì)這個(gè)目標(biāo)沒(méi)有太認(rèn)真地考慮,但我一直將它牢記在心。在我看來(lái),銀行數(shù)字渠道有希望實(shí)現(xiàn)每周發(fā)布。這個(gè)速度還沒(méi)快到硅谷初創(chuàng)企業(yè)那種近乎荒謬的程度,但又已經(jīng)足夠快,強(qiáng)迫我們必須擺脫以往會(huì)議、手動(dòng)測(cè)試加手動(dòng)發(fā)布那種老派的運(yùn)作模式。換句話說(shuō),這樣的目標(biāo)足以敦促我們做出改變。
我在項(xiàng)目中扮演的角色是解決方案架構(gòu)師。為此,我推出了包含完全無(wú)狀態(tài)REST服務(wù)層與兩個(gè)前端的新架構(gòu):一個(gè)是基于AngularsJS的Web應(yīng)用程序,另一個(gè)則是基于Ionic框架的移動(dòng)應(yīng)用(與Web應(yīng)用大體基于相同的代碼)。
改革進(jìn)行中
首先,我要求對(duì)JDK進(jìn)行更新(由版本6升級(jí)到版本7)。只有JDK完成更新,我才能使用JAX-RS編寫(xiě)REST服務(wù)。運(yùn)營(yíng)團(tuán)隊(duì)起初比較抗拒,但在意識(shí)到當(dāng)前版本的JDK即將壽終正寢時(shí),他們果斷著手推進(jìn)升級(jí)工作。整個(gè)過(guò)程大概用了6個(gè)月時(shí)間。
我還要求使用Liberty作為應(yīng)用服務(wù)器。WebSphere在開(kāi)發(fā)人員的筆記本電腦上啟動(dòng)速度太慢,一般在5到10分鐘左右?紤]到即將開(kāi)始實(shí)施的大項(xiàng)目,我們必須盡可能提高敏捷性與速度表現(xiàn)。有人提到,要想在筆記本電腦上使用Liberty,唯一的可行方案就是繼續(xù)在生產(chǎn)應(yīng)用服務(wù)器上使用WebSphere。這樣的結(jié)論令我們難以接受,因?yàn)槲覀儐螒{直覺(jué)就知道提高產(chǎn)次對(duì)于加快運(yùn)營(yíng)速度的重要意義,否則任何對(duì)后續(xù)環(huán)境棧中的主要元素(IT、QA、生產(chǎn)等)做出變更時(shí),必然會(huì)產(chǎn)生大量無(wú)法及時(shí)修復(fù)的bug。
為此,我需要一款分布式緩存工具,借此保證服務(wù)層始終保持完全無(wú)狀態(tài)(而且無(wú)會(huì)話)。另外,出于效率的考量,我們同樣需要緩存的加持。目前還沒(méi)有官方支持的分布式緩存平臺(tái),但以后一定會(huì)有,我們得早點(diǎn)邁出這一步。
以上一切訴求,讓我意識(shí)到這條路在規(guī)劃階段就存在問(wèn)題。開(kāi)發(fā)團(tuán)隊(duì)無(wú)法以正確的方式表達(dá)自己的需求,運(yùn)營(yíng)團(tuán)隊(duì)則太過(guò)強(qiáng)調(diào)維持正常的運(yùn)行狀態(tài)——而在這兩者之間,解決方案架構(gòu)師也沒(méi)能組織起有效的對(duì)話,自然不可能以富有成效的方式做出領(lǐng)導(dǎo)與指引。
我覺(jué)得需要徹底改變這種模式,并且摒棄交付團(tuán)隊(duì)以前采用的復(fù)雜服務(wù)請(qǐng)求流程,改為由運(yùn)營(yíng)團(tuán)隊(duì)交付基礎(chǔ)架構(gòu)。另一個(gè)需要設(shè)立全新基礎(chǔ)架構(gòu)的團(tuán)隊(duì)。在其中一項(xiàng)研究中,我們發(fā)現(xiàn)運(yùn)營(yíng)團(tuán)隊(duì)要想建立一套全新的基礎(chǔ)設(shè)施,需要滿足大約四百項(xiàng)要求……不說(shuō)要求本身能不能達(dá)成,光是溝通工作就足以拖垮兩邊的團(tuán)隊(duì)。
于是我轉(zhuǎn)變了思路,覺(jué)得交付團(tuán)隊(duì)不妨自行配置基礎(chǔ)設(shè)施。我得出的結(jié)論是,最好是選擇一套私有云基礎(chǔ)設(shè)施。為此,我開(kāi)始獨(dú)立進(jìn)行研究,探索哪些工具選項(xiàng)最適合這種需求。與此同時(shí),一支小型運(yùn)營(yíng)團(tuán)隊(duì)剛剛解決了一堆令人討厭而且長(zhǎng)期存在的網(wǎng)絡(luò)問(wèn)題。利用這批空閑勞動(dòng)力,我們正好可以在KeyBank內(nèi)部嘗試建立私有云。
根據(jù)研究,我們確定Kubernetes是目前最理想的容器私有云平臺(tái)。因?yàn)槲覀円呀?jīng)意識(shí)到容器在技術(shù)層面擁有遠(yuǎn)超虛擬機(jī)的優(yōu)勢(shì),所以虛擬機(jī)云平臺(tái)這一選項(xiàng)被直接否決。我們尋找為Kubernetes提供專業(yè)支持的機(jī)構(gòu),最終發(fā)現(xiàn)紅帽及其OpenShift平臺(tái)是極為可靠的選擇。之后的工作開(kāi)始順利推進(jìn)。與紅帽合作之后,我們?cè)?個(gè)月內(nèi)就建立起了生產(chǎn)預(yù)覽,并在7個(gè)月內(nèi)開(kāi)始向第一批客戶提供生產(chǎn)支持。
我們將應(yīng)用程序從WebSphere遷移到了Tomcat,將REST引擎由Wink轉(zhuǎn)換為更流行的Jersey(此前在WebSphere中無(wú)法使用),而后添加了Hystrix,并向可用性策略中引入了斷路器模式。最后,我們還使用Redis實(shí)現(xiàn)了分布式緩存。
但技術(shù)問(wèn)題永遠(yuǎn)不是最困難的部分。我們的目標(biāo)是實(shí)現(xiàn)每周發(fā)布,因此必須實(shí)現(xiàn)基礎(chǔ)設(shè)施的自我配置能力與不變性。
持續(xù)交付管道實(shí)現(xiàn)全面自動(dòng)化
為了達(dá)成這些目標(biāo),我們需要為部署在OpenShift中的應(yīng)用程序定義所有權(quán)與支持模式。實(shí)際上,如果開(kāi)發(fā)團(tuán)隊(duì)希望以自助方式管理基礎(chǔ)設(shè)施,那又該由誰(shuí)來(lái)提供技術(shù)支持?在觀察谷歌、Netflix以及Spotify的業(yè)務(wù)體系后,我們發(fā)布了一套模型,其中由交付團(tuán)隊(duì)負(fù)責(zé)管理所需的基礎(chǔ)設(shè)施(即在容器中添加的內(nèi)容),而運(yùn)營(yíng)團(tuán)隊(duì)則負(fù)責(zé)保持OpenShift穩(wěn)定可用——很明顯,一切業(yè)務(wù)服務(wù)的可用性,都將直接由底層OpenShift的可用性所決定。此外,為了保證所有權(quán)明確清晰,我們決定將特定項(xiàng)目的OpenShift配置文件同項(xiàng)目的其余源代碼統(tǒng)一起來(lái)。
我們采用以下邏輯在Jenkins中建立了一個(gè)流程:
• 每十分鐘,源代碼repo會(huì)接受一次輪詢;一旦出現(xiàn)任何變更,則觸發(fā)新的build。
• 此build將運(yùn)行單元測(cè)試以及創(chuàng)建項(xiàng)目Docker鏡像所需要的其他一系列操作步驟。完成之后,此Docker鏡像永遠(yuǎn)不會(huì)進(jìn)行后續(xù)變更。這也是我們實(shí)現(xiàn)不變基礎(chǔ)設(shè)施的核心要點(diǎn)之一。
• 在解決方案的每個(gè)層上單獨(dú)進(jìn)行一系列集成測(cè)試。通過(guò)隔離,我們可以模擬出依賴項(xiàng)。以此為基礎(chǔ),我們即可脫離下游依賴項(xiàng)的可用性與測(cè)試數(shù)據(jù)質(zhì)量,單獨(dú)運(yùn)行一系列測(cè)試。這些測(cè)試將在臨時(shí)環(huán)境中運(yùn)行,這一點(diǎn)在OpenShift中并不難做到。
• 在IT環(huán)境中運(yùn)行一系列集成測(cè)試。
• 我們每天在QA環(huán)境上部署一次之前成功完成測(cè)試的build。QA環(huán)境用于手動(dòng)探索性測(cè)試以及手動(dòng)(后續(xù)計(jì)劃改為自動(dòng))負(fù)載測(cè)試。
• 最后一步則是每周在生產(chǎn)預(yù)覽環(huán)境中進(jìn)行一次部署。這一步需要人工核準(zhǔn)。
在生產(chǎn)環(huán)境中部署需要KeyBank的多次批準(zhǔn)。這些批準(zhǔn)以會(huì)議形式完成,即人們展示將部署的內(nèi)容,而高級(jí)領(lǐng)導(dǎo)者簽署發(fā)布命令。這個(gè)過(guò)程不適合我們,因?yàn)槲覀儧](méi)有足夠的時(shí)間每周舉行三次會(huì)議(的確,這需要三個(gè)不同部門(mén)確信發(fā)布版本的合理性)。我們可以改變這樣的流程,并且同意:如果一個(gè)版本僅影響OpenShift內(nèi)部的組件,我們就自動(dòng)批準(zhǔn)該版本的發(fā)布。
最后一部分工作,就是建立起完整的自動(dòng)回歸測(cè)試套件。很快,我們從一系列痛苦的錯(cuò)誤當(dāng)中認(rèn)識(shí)到,除非擁有完整的回歸測(cè)試覆蓋范圍,否則我們永遠(yuǎn)不可能達(dá)到每周發(fā)布的目標(biāo)。具體來(lái)講,手動(dòng)測(cè)試團(tuán)隊(duì)的處理速度,跟不上每周發(fā)布帶來(lái)的巨量更新內(nèi)容。
為此,我們以行為驅(qū)動(dòng)型開(kāi)發(fā)(BDD)原則為指引建立起測(cè)試框架。我們選擇Cucumber作為DBB工具。Cucumber的最大優(yōu)勢(shì),在于允許用戶以自然語(yǔ)言(英語(yǔ)或其他語(yǔ)言)編寫(xiě)測(cè)試用例。我們決定發(fā)揮這一優(yōu)勢(shì),由業(yè)務(wù)分析師團(tuán)隊(duì)負(fù)責(zé)編寫(xiě)測(cè)試用例。以此為基礎(chǔ),我們得以并行推進(jìn)業(yè)務(wù)代碼與測(cè)試代碼的開(kāi)發(fā),而不再像過(guò)去那樣必須先完成業(yè)務(wù)代碼、之后才能進(jìn)行(手動(dòng)或自動(dòng))測(cè)試。我們還使用Selenium對(duì)Web應(yīng)用進(jìn)行瀏覽器與操作系統(tǒng)版本測(cè)試,并通過(guò)Appium對(duì)移動(dòng)應(yīng)用進(jìn)行設(shè)備型號(hào)及操作系統(tǒng)版本測(cè)試。
總結(jié)
現(xiàn)在,我們已經(jīng)對(duì)自己的發(fā)布流程擁有更強(qiáng)的信心。每周四上午,我們都能拿出一些最新成果,并通過(guò)OpenShift開(kāi)箱即用的滾動(dòng)部署功能實(shí)現(xiàn)零宕機(jī)發(fā)布。困擾了我們很多年的問(wèn)題就這樣被OpenShift的內(nèi)置功能解決了……我們還啟用了自動(dòng)規(guī)模伸縮功能。通過(guò)在負(fù)載測(cè)試期間對(duì)這項(xiàng)功能進(jìn)行的深入測(cè)試,我們意識(shí)到現(xiàn)有系統(tǒng),或者至少在OpenShift中部署的各系統(tǒng)層內(nèi),完全可以通過(guò)橫向擴(kuò)展為負(fù)載峰值提供正確匹配的實(shí)例數(shù)量。
這在銀行內(nèi)部被認(rèn)為是一個(gè)優(yōu)秀的成功故事。下一步,我們將把同樣的流程引入其他項(xiàng)目,逐步將更多工作負(fù)載遷移到OpenShift當(dāng)中。

