Cloud Foundry技術(shù)全貌及核心組件分析
本文在從架構(gòu)組成、核心模塊功能、源代碼分析等角度來全面剖析Cloud Foundry,同時(shí)會(huì)結(jié)合各行業(yè)的典型案例來講解Cloud Foudry在具體應(yīng)用場(chǎng)景中的表現(xiàn)。
架構(gòu)設(shè)計(jì)及核心組件
從總體上看,Cloud Foundry的架構(gòu)如圖1所示。
圖1 Cloud Foundry架構(gòu)圖
經(jīng)過一年多的發(fā)展,Cloud Foundry的組件增加了很多。但核心組件并沒有變化,增加的組件是原架構(gòu)基礎(chǔ)上的細(xì)化和專門化。Stager組件解決了打包(Stage)過程需要操作大量文件且操作時(shí)間長(zhǎng)的問題,所以它作為獨(dú)立進(jìn)程,使打包工作異步進(jìn)行,不阻塞作為核心組件的Cloud Controller。
下面是對(duì)Cloud Foundry核心組件的描述。
Router。顧名思義,Router組件在Cloud Foundry中是對(duì)所有進(jìn)來的請(qǐng)求進(jìn)行路由。進(jìn)入Router的請(qǐng)求主要有兩類。
***類是來自VMC Client或者STS的,由Cloud Foundry使用者發(fā)出,叫做管理請(qǐng)求。這類請(qǐng)求會(huì)被路由到Cloud Controller組件處理。
第二類是對(duì)所部署的App的訪問請(qǐng)求。這部分請(qǐng)求會(huì)被路由到App execution,即DEA組件中。簡(jiǎn)單地說,所有進(jìn)入Cloud Foundry系統(tǒng)的請(qǐng)求都會(huì)經(jīng)過Router組件。Router組件是可擴(kuò)展的,由多個(gè) Router共同處理進(jìn)來的請(qǐng)求。但如何對(duì)Router做負(fù)載均衡不屬于Cloud Foundry的實(shí)現(xiàn)范圍。Cloud Foundry只須保證所有Router都可以處理任何請(qǐng)求,而管理員可用DNS實(shí)現(xiàn)負(fù)載均衡,也可部署專用硬件來實(shí)現(xiàn),或者簡(jiǎn)單點(diǎn),弄個(gè)Nginx做負(fù)載均衡。
在***個(gè)版本中,Router工作由router.rb來做,所有請(qǐng)求都必須經(jīng)過Ruby代碼處理轉(zhuǎn)發(fā)。這個(gè)設(shè)計(jì)簡(jiǎn)單直接,只是容易引起性能問題,新版中做了如下改進(jìn),如圖2所示(左側(cè)為***版本,右側(cè)為新版)。
圖2 Router工作過程(新舊版對(duì)比)
- 使用Nginx的Lua擴(kuò)展,在Lua中加入U(xiǎn)RL查詢和統(tǒng)計(jì)的邏輯。
- 如果Lua不知道當(dāng)前的URL應(yīng)該路由給哪一個(gè)DEA,則會(huì)發(fā)一個(gè)查詢請(qǐng)求到router_uls_server.rb(也就是圖2中的“Upstream Locator SVC”)。
- router_uls_server.rb是一個(gè)簡(jiǎn)單的Sinatra應(yīng)用,它存儲(chǔ)了所有URL與DEA IP:Port對(duì)應(yīng)關(guān)系。另外,它也管理了請(qǐng)求的Session數(shù)據(jù)。
這樣一來,大量的業(yè)務(wù)請(qǐng)求在Lua查詢過并保存位置后,都由Nginx直接轉(zhuǎn)發(fā),不再經(jīng)過Router,性能和穩(wěn)定性都大幅提高。
Router的設(shè)計(jì)中有個(gè)難點(diǎn):我們知道HTTP請(qǐng)求是有上下文的,那如何保證請(qǐng)求的上下文完整呢?簡(jiǎn)單來說,就是如何保證有上下文的請(qǐng)求每次都可以找到同一個(gè)DEA處理?Cloud Foundry是支持Session的,當(dāng)Router發(fā)現(xiàn)用戶請(qǐng)求中帶了Cookie信息,它會(huì)在Cookie里暗藏一個(gè)應(yīng)用實(shí)例的id。當(dāng)有新請(qǐng)求時(shí),Router通過解析Cookie得到上次的應(yīng)用實(shí)例,然后轉(zhuǎn)發(fā)到同一臺(tái)DEA上。這信息與上面的查詢類似,會(huì)先存在于Upstream Locator SVC中,當(dāng)Lua知道后會(huì)保存在Nginx內(nèi)部提高效率。
#p#
DEA (Droplet Execution Agency)。首先要解釋下什么叫做Droplet。在 Cloud Foundry中,Droplet指把提交的源代碼及Cloud Foundry配置好的運(yùn)行環(huán)境(如Java Web就是一個(gè)Tomcat),再加一些控制腳本,如start/stop等,全部打包在一起的tar文件。Staging App是指制作Droplet,然后把它存儲(chǔ)起來的過程。Cloud Foundry會(huì)保存這個(gè)Droplet,直到啟動(dòng)(start)一個(gè)App時(shí),一臺(tái)部署了DEA模塊的服務(wù)器會(huì)來拿這個(gè)Droplet的副本去運(yùn)行。因此,如果將App擴(kuò)展到10個(gè)實(shí)例(instance),那么這個(gè)Droplet就會(huì)被復(fù)制10份,供10臺(tái)DEA服務(wù)器運(yùn)行。
圖3是DEA模塊的架構(gòu)圖(左側(cè)為***版本,右側(cè)為新版)。
圖3 DEA模塊架構(gòu)圖(新舊版對(duì)比)
Cloud Foundry剛推出時(shí),用戶部署的應(yīng)用可以在內(nèi)網(wǎng)暢通無阻,跑滿CPU,占盡內(nèi)存,寫滿磁盤。因此,Cloud Foundry開發(fā)出了Warden,用這個(gè)程序運(yùn)行容器解決這一問題。這個(gè)容器提供了一個(gè)隔絕環(huán)境,Droplet只可以獲得受限的CPU、內(nèi)存、磁盤訪問權(quán)限和網(wǎng)絡(luò)權(quán)限。
Warden在Linux上的實(shí)現(xiàn)是將Linux 內(nèi)核的資源分成若干個(gè)namespace加以區(qū)分,底層的機(jī)制是CGROUP。這樣的設(shè)計(jì)比虛擬機(jī)性能好,啟動(dòng)更快,也能夠獲得足夠的安全性。
DEA的運(yùn)行原理沒有發(fā)生根本改變:Cloud Controller模塊會(huì)發(fā)送start/stop等基本的App管理請(qǐng)求給DEA,dea.rb接收這些請(qǐng)求,然后從blobstore下載合適的 Droplet。前面說到Droplet是一個(gè)帶有運(yùn)行腳本和運(yùn)行環(huán)境的tar包,DEA只需要把它拿過來解壓,并執(zhí)行里面的start腳本,就可讓應(yīng)用運(yùn)行起來,App也就可以被訪問了。換句話說,就是這臺(tái)服務(wù)器的某一個(gè)端口已經(jīng)在待命,只要有request從這個(gè)端口進(jìn)來,這個(gè)App就可以接收并返回正確的信息。
接著,dea.rb要做以下一些善后的工作。
把這個(gè)信息告訴Router模塊(前面說到,所有進(jìn)入Cloud Foundry的請(qǐng)求都是由Router模塊處理并轉(zhuǎn)發(fā)的,包括用戶對(duì)App的訪問請(qǐng)求。一個(gè)App運(yùn)行起來后,需要告訴Router,讓它根據(jù)負(fù)載均衡等原則把合適的請(qǐng)求轉(zhuǎn)進(jìn)來,使這個(gè)App的實(shí)例能夠干活)。
- 一些統(tǒng)計(jì)性的工作。例如要把這個(gè)用戶又新部署了一個(gè)App告訴Cloud Controller,以作quota控制等。
- 把運(yùn)行信息告訴Health Manager模塊,實(shí)時(shí)報(bào)告該App的實(shí)例運(yùn)行情況。
另外,DEA還要負(fù)責(zé)部分對(duì)Droplet的查詢工作。例如,如果用戶想通過Cloud Controller查詢一個(gè)App的log信息,那么DEA需要從該Droplet里取到log返回等。
#p#
Cloud Controller。Cloud Foundry的管理模塊。簡(jiǎn)單來說,就是與VMC和STS交互的服務(wù)器端,它收到指令后發(fā)消息到各??欤芾碚麄€(gè)云的運(yùn)行,相當(dāng)于Cloud Foundry的大腦。
以部署一個(gè)App到Cloud Foundry為例。在輸入push命令后,VMC開始工作。在做完一輪用戶鑒權(quán)、查看所部署的App數(shù)量是否超過預(yù)定數(shù)額、問了一堆相關(guān)App的問題后,需要發(fā)4個(gè)指令。
- 發(fā)一個(gè)POST到“apps”,創(chuàng)建一個(gè)App;
- 發(fā)一個(gè)PUT到“apps/:name/application”,上傳App;
- 發(fā)一個(gè)GET到“apps/:name/”,取得App狀態(tài),查看是否已啟動(dòng);
- 如果沒有啟動(dòng),發(fā)一個(gè)PUT到“apps/:name/”,使其啟動(dòng)。
***版的Cloud Controller是基于Ruby on Rails的,新版的Cloud Controller用Sinatra進(jìn)行了重寫,并把部分工作獨(dú)立成組件, 使Cloud Controller變得更輕。另一個(gè)重要的改進(jìn)是,***個(gè)版本的Droplet是通過NFS共享的,這樣會(huì)帶來安全、性能等方面的問題,新版中采用了自己開發(fā)的blobstore存放Droplet。
隨著Cloud Foundry逐漸成熟,權(quán)限管理功能在新版本中逐漸完善。在原有的用戶模型基礎(chǔ)上,加入了組織和用戶空間等概念,細(xì)化了管理模型。用戶模型的認(rèn)證是由 UAA模塊實(shí)現(xiàn)的。在企業(yè)環(huán)境中,如果用Cloud Foundry的開源代碼搭建私有云,那么它可以與企業(yè)已有的認(rèn)證系統(tǒng)進(jìn)行整合,例如LDAP、CAS等。權(quán)限控制是由ACM模塊實(shí)現(xiàn)的。圖4給出了用戶訪問Cloud Controller某個(gè)API的過程。
圖4 用戶訪問Cloud Controller某個(gè)API的過程
#p#
Health Manager。它做的事情不復(fù)雜,簡(jiǎn)單地說,是從各個(gè)DEA獲得運(yùn)行信息,然后進(jìn)行統(tǒng)計(jì)分析、報(bào)告、發(fā)出告警等。
Services。服務(wù)應(yīng)屬于PaaS的第三層。Cloud Foundry把Service模塊設(shè)計(jì)成一個(gè)獨(dú)立的、插件式的模塊,便于第三方方便地把自己的服務(wù)整合成Cloud Foundry服務(wù)。在GitHub上有以下兩個(gè)相關(guān)的子項(xiàng)目值得關(guān)注。
- vcap-services-base:顧名思義,它包括Cloud Foundry服務(wù)的框架及核心類庫。如果開發(fā)自定義服務(wù),需要引用到里面的類。
- vcap-services:目前Cloud Foundry支持的,包括官方及大部分第三方貢獻(xiàn)的服務(wù)。這個(gè)項(xiàng)目的根文件目錄是根據(jù)服務(wù)名稱劃分的,可以選擇其中自己感興趣的來研究。
由此可見,Service模塊十分方便為第三方提供自定義服務(wù)。從架構(gòu)來說, Cloud Foundry服務(wù)部分使用了模板方法設(shè)計(jì)模式,可通過重寫鉤子方法來實(shí)現(xiàn)自己的服務(wù)。如果不需要特別邏輯則可以使用默認(rèn)方法。
現(xiàn)實(shí)情況中,種種原因使有些系統(tǒng)服務(wù)難以或不愿意遷移到云端,為此Cloud Foundry 引入了Service Broker模塊。
Service Broker可以使部署在Cloud Foundry上的應(yīng)用能訪問本地服務(wù)。Service Broker的使用方法如下。
- 準(zhǔn)備被訪問的服務(wù)。以PostgreSQL為例,配置好程序和防火墻,讓其可以通過類似 postgres://xyzhr:secret@db.xyzcorp.com:5432/xyz_hr_db的URI訪問。
- 注冊(cè)以上URI到Service Broker。
使用Service Broker暴露的服務(wù)與使用Cloud Foundry的系統(tǒng)服務(wù)無異,準(zhǔn)備被訪問的服務(wù)中的訪問服務(wù)的URI通過環(huán)境變量傳給App。App通過URI訪問暴露出來的服務(wù),這過程不必通過 Service Broker。這個(gè)過程如圖5所示,與使用系統(tǒng)服務(wù)類似,此處不再贅述。
圖5 使用Service Broker所暴露的服務(wù)的過程
#p#
NATS (Message bus)。 Cloud Foundry的架構(gòu)是基于消息發(fā)布和訂閱的。聯(lián)系各模塊的是一個(gè)叫NATS的組件。NATS是由Cloud Foundry開發(fā)的一個(gè)基于事件驅(qū)動(dòng)的、輕量級(jí)的消息系統(tǒng)。它基于EventMachine實(shí)現(xiàn)。***版本Cloud Foundry被人詬病的一個(gè)問題就是NATS服務(wù)器是單節(jié)點(diǎn)的,讓人不大放心。新版NATS能支持多服務(wù)器節(jié)點(diǎn),NATS服務(wù)器間通過THIN來做通信。NATS的GitHub開源地址是:https://github.com/derekcollison/nats。代碼量不多但設(shè)計(jì)很精妙,推薦研究它的源代碼。
Cloud Foundry各種優(yōu)秀特性均源于消息通信架構(gòu)。每臺(tái)服務(wù)器上的各模塊會(huì)根據(jù)當(dāng)前的行為,向?qū)?yīng)主題發(fā)布消息,同時(shí)也按照需要監(jiān)聽多個(gè)主題,彼此以消息進(jìn)行通信。
可以說,Cloud Foundry的核心是一套消息系統(tǒng),如果想了解Cloud Foundry的來龍去脈,跟蹤它里面復(fù)雜的消息機(jī)制是非常好的方法。舉個(gè)最簡(jiǎn)單的例子,一個(gè)裝有DEA組件的服務(wù)器為加強(qiáng)云的計(jì)算能力,被加入到 Cloud Foundry集群中。它首先需要表明已準(zhǔn)備好隨時(shí)提供服務(wù),Cloud Controller可將App部署到它這里,Router也可將相關(guān)的請(qǐng)求交給它處理;Health Manger可定時(shí)為它體檢等,它會(huì)發(fā)布一條消息到主題“dea.start”:
- NATS.publish(‘dea.start’, @hello_message_json)
@hello_message_json包括DEA的UUID、ip、 port、版本信息等內(nèi)容。Cloud Controller、Router、Health Manger及其他模塊會(huì)監(jiān)聽這個(gè)主題,得到通知,各自干活。
理解Cloud Foundry的***方法其實(shí)是選定某一操作,如部署一個(gè)App、創(chuàng)建服務(wù)等,以消息為線索,跟蹤到各模塊,看其如何處理。這樣就可以觀察到整個(gè) Cloud Foundry的工作流程。本專欄第2篇文章將專門介紹如何以NATS為主線理解Cloud Foundry原理,這里就不做過多敘述了。
總結(jié)
在過去的一年中,Cloud Foundry發(fā)生了很多改變,足可看出Cloud Foundry社區(qū)的活躍。非常希望本文已把Cloud Foundry的原理講得足夠明白,但請(qǐng)不要把本文作為參考手冊(cè)使用,在VMware中國(guó)開發(fā)者關(guān)系團(tuán)隊(duì)的努力下,Cloud Foundry的文檔相當(dāng)完善,強(qiáng)烈推薦以其作為參考(網(wǎng)址:www.cloudfoundry.cn)。