原文:http://www.oschina.net/question/12_32393
CloudFoundry雲開發大會:http://www.infoq.com/cn/zones/vmware/
VMware在今年4月份突然發布了業內第一個開源的PaaS——CloudFoundry。發布至今的這幾個月裡,筆者一直關注它的演化,並從它的架構設計中獲益良多,覺得有必要寫出來與大家分享一下。
本文會分為兩個部份:第一部份主要介紹CloudFoundry的架構設計,從它所包含的模組介紹起,到各部份的訊息流程向,各模組如何協調合作;第二部份會在第一部份的基礎上,以如何在你的資料中心裡面用CloudFoundry部署一個私人PaaS為目標,把第一部分介紹到的架構知識使用起來。
第一部份講的很多內容,會引用Pat在10月12日的VMwareCloud Forum上面關於CloudFoundry架構的演講。Pat是CloudFoundry Core的負責人,他的那次演講很值得一聽。如果你當時在場,並且理解他所說的內容,本部份可以選擇直接跳過。我除了會把說的內容講具體點外,不太可能可以講得比他好。
架構及模組
從總體地看,CloudFoundry的架構如下:這個架構圖以及下文所用到的各模組架構圖均來自Pat的PPT。從能夠看到CloudFoundry主要有以下幾大組件組成:
1、Router路由分發:顧名思義,Router組件在CloudFoundry中是對所有進來的Request進行路由。進入Router的request主要有兩類:首先是來自VMCClient或者STS的,由CloudFoundry使用者發出的,管理型指令。
例如:列出你所有apps的vmcapps,提交一個apps等等。這類request會被路由到AppLife Management組件,又叫CloudController組件去;第二類是外界對你所部署的apps訪問的request。這部份requests 會被路由到Appexecution,又或者叫做DEAs的組件去。所有進入CloudFoundry系統的requests都會經過Router組件,看到這裡可能會有朋友會擔心Router成為單點,從而成為整個雲的瓶頸。
但是CloudFoundry作為雲系統,其設計的核心就是去單點依賴,組件平行擴充,且可替代的以保證擴充性,這是CloudFoundry,甚至所有雲端運算系統的設計原則,後文會討論CloudFoundry如何做到這點,目前只要知道,系統可以部署多個Routers共同處理進來的 requests,但是Router上層的LoadBalance不在CloudFoundry的實現範圍,CloudFoundry只保證所有的 request是無狀態的,這樣就使上層均衡附載選擇面非常非常大了,例如可以通過DNS做,也可以部署硬體的LoadBalancer,或者簡單點,弄台ngnix作負載平衡器,都是可行的。
Router組件,目前版本是對nginx的一個簡單封裝(http和反向 Proxy伺服器)。熟悉ngnix的朋友應該知道,它可以一個通訊端檔案(.sock檔案)作為輸入輸出。所有安裝CloudFoundry的Router元件伺服器都會安裝一個nginx。從整體的來看,Router組件的結構如下:
外界httprequest進入CloudFoundry伺服器,nginx會首先接到request,nginx通過sock與 router.rb進行互動,於是真正處理請求的是Router組件。router.rb裡面根據傳入的url,使用者名稱密碼等,進行邏輯判斷,到 CloudController組件或者DEA組件取資料並且返通過與niginx串連的.sock檔案返回。
router.rb是對nginx進行了邏輯封裝。熟悉CloudFoundry的朋友肯定知道,CloudFoundry給每一個app分配了一個url訪問,如果直接使用VMware所託管的CloudFoundry.com的話,那你的app的url可能就是 xxx.cloudfoundry.com,無論通過命令給你的app擴充了多少個instances,都是從這個url訪問的,這裡面的url轉換路由就是由router.rb實現的。
可以看到router核心還是轉換和分發路由,除這個外再處理下鑒權方面的事情,由於router是所有外部request的唯一入口,很多這方面事情都可以在router做。
2、DEA(Droplet Execution Agency): 首先要解析下什麼叫做Droplet。Droplet在CloudFoundry的概念裡面是指一個把你提交的原始碼,以及CloudFoundry配套好的運行環境,再加上一些管理指令碼,例如Start/Stop這些小指令碼全部壓縮好在一起的tar包。還有一個概念,叫做Stagingapp,就是指製作上面描述這個包,然後把它儲存好的過程。CloudFoundry會自動儲存這個Droplet,直到你start一個app的時候,一台部署了DEA模組的伺服器會來拿一個Droplet的copy去運行。所以如果你擴充你的app到10個instances,那這個Droplet就被會複製十份,讓
10個DEA伺服器拿去運行。
是DEA模組的架構圖:
Cloud Controller模組(下面會介紹)會發送start/stop等基本的apps管理請求給DEA,dea.rb接收這些請求,然後從NFS裡面找到合適的Droplet。前面說到Droplet其實是一個帶有運行指令碼的,帶運行環境的tar包,DEA只需要把它拿過來解壓,並即行裡面的start指令碼,就可以讓這個app跑起來。到此,app算是可以訪問,並start起來了,換句話說就是有這台伺服器的某一個連接埠已經在待命,只要有request
從這個連接埠進來,這個app就可以接收並返回正確的資訊。可以理解為dea是一個容器,對部署的應用進行了二次封裝,該容器可以動態建立,託管和運行。
接著dea.rb要做些善後的工作:1、把這個資訊告訴Router模組。我們前面說到,所有進入CloudFoundry的requests都是由Router模組處理並轉寄的,包括使用者對app的訪問request,一個app起來後,需要告訴router,讓它根據loadbalance等原則,把合適的request轉進來,使這個app的instance能夠幹起活;2、一些統計性的工作,例如要把這個使用者又新部署了一個app告訴 CloudController,以作quota控制等;3、把運行資訊告訴HealthManager模組,即時報告該app的instance運行情況。另外DEA還要負責部份對Droplet的查詢工作,譬如,如果使用者通過CloudController想查詢一個app的log資訊,那DEA需要從該Droplet裡面取到log返回等等。
3、CloudController:CloudController是CloudFoundry的管理模組。主要工作包括:
- a) 對apps的增刪改讀;
- b) 啟動、停止應用程式;
- c) Staging apps(把apps打包成一個droplet);
- d) 修改應用程式運行環境,包括instance、mem等等;
- e) 管理service,包括service與app的綁定等;
- f) Cloud環境的管理;
- g) 修改Cloud的使用者資訊;
- h) 查看Cloud Foundry,以及每一個app的log資訊。
這似乎有點複雜,但簡單的說,可以很簡單:就是與VMC和STS互動的伺服器端。VMC和STS與CloudFoundry通訊採用的是 restful介面,另一方面CloudController是一個典型的Rubyon Rails項目,從VMC或者STS接到JSON格式的協議,然後寫入CloudController Database,並發訊息到各模快去控制管理整個雲。和其他ROR項目一樣,CloudController的所有API可以從 conf/routes.rb裡看到。開放的Restful介面好處在於第三方應用開發和整合,企業在用CloudFoundry部署私人雲端的時候,可以通過這些介面來自動化控制管理整個Cloud環境。這部份內容將在第二部份論述。是Cloud
Controller的架構圖:
圖中Health Manager和DEA是外部模組,CCDatabase就是CloudController Database,這個是整個CloudFoundry不能做HP的地方。CloudController Database的並發性不會很多,應用層級的資料庫訪問是由底下的Service模組處理的,這個資料庫存的是Cloud的配置資訊。讀操作主要來自 DEA啟動,作為初始化DEA的依據;以及healthmanager模組會從這裡讀取預期的狀態資訊,這部份資料會與從DEA得到的實際狀態資訊進行比對。
NFS是多個CloudController的共用儲存,CloudController其中一個重要工作就是StagingApps。 Droplets的儲存是在叢集環境的唯一的。而CloudController是叢集運行,換言之,就是每一個控制Request可能由不同的 CloudController處理,假設一個簡單的使用者情境:我們需要部署一個app到CloudFoundry中。我們在敲完那條簡單的push命令後,VMC開始工作,在做完一輪的使用者鑒權、查看所部署的apps數量是否超過預定數額,問了一堆相關app的問題後,需要發4個指令:
- 1.發一個POST到”apps”,建立一個app;
- 2.發一個PUT到”apps/:name/application”,上傳app;
- 3.發一個GET到”apps/:name/”,取得app狀態,看看是否已經啟動;
- 4.如果沒有啟動,發一個PUT到”apps/:name/”,使其啟動。
如果第2和第4步由不同的Cloud Controller來處理,而又無法保證他們能找到同一個Droplet,那第4步將會因為找不到對應的Droplet而啟動失敗。如何保證這一連串指令過來所指向的Droplet都是同一個呢?使用NFS,使CloudController共用儲存是最簡單的方法。但是這個方法在安全性等方面並不完美。在10月12日的VMwareCloud Forum上,Pat告訴我們下一版本的CloudFoundry這裡將會有大調整,但是在那部份代碼公開前,我不方便在這評價太多。
CloudController可以理解為核心的調度模組,它從HealthManager擷取效能和健康資料,根據調度策略動態建立,停止執行個體,包括執行個體到router的掛接。整個方案類似原有的應用虛擬化的方法,並不一定需要有負載平衡硬體的支援。
4、HealthManager: 做的事情不複雜,簡單的說是從各個DEA裡面拿到運行資訊,然後進行統計分析,報告等。統計資料會與CloudController的設定指標進行比對,並提供Alert等。HealthManager模組目前還不是十分完善,但是CloudManage棧裡面,自動化health管理、分析是一個很重要的領域,而這方面可以擴充的地方也很多,結合OrchestrationEngine可以使雲自管理、自預警;而與BI方面技術結合,可以統計運營情況,合理分配資源等。這方面CloudFoundry還在發展之中。
5、Services:Cloud Foundry的Service模組從原始碼控制上看就知道是一個獨立的、可Plugin的模組,以方便第三方把自己的服務整合入 CloudFoundry生態系統。在Github上看到service是與CloudFoundry Core項目vcap獨立的一個repository,為vcap-service。Service模組其中設計原則是方便第三方服務提供者提供服務。在這方面CloudFoundry做得很成功,從Github上看,已經有以下服務提供:a)MongoDB;
b) mysql; c) neo4j; d) PostgreSql; e) RabbitMQ; f) Redis; g)vBlob。基類都是放在base檔案夾中。
第三方如果需要自己開發CloudFoundry的服務,需要繼承改寫它裡面的兩個基礎類:Node和Gateway;而裡面一些操作,如:Provision,可以在base的provisioner.rb基礎上加入自己的邏輯,同樣的還有Service_Error和 Service_Message等。關於如何寫自己的Service,ELC的部落格會推出相應文章詳細論述,並不在本文的討論範圍裡面,從架構瞭解上來說,只要知道服務間的關係,知道個服務與base間透過繼承關係來橫向擴充,而CloudFoundry與apps調用Service是通過base來完成這一簡單的架構方法即可。
6、NATS(Message bus): 從CloudFoundry的總架構圖看,位於各模組中心位置的是一個叫nats的組件。NATS是由CloudFoundry的架構師Derek開發的一個輕量級的,支援發布、訂閱機制的訊息系統。Github開源地址是:https://github.com/derekcollison/nats。其核心基於EventMachine開發,代碼量不多,可以下載下來慢慢研究。
CloudFoundry是一個多模組的分布式系統,支援模組自發現,錯誤自檢,且模組間低耦合。其核心原理就是基於訊息發布訂閱機制。每個台伺服器上的每個模組會根據自己的訊息類別,向MessageBus發布多個訊息主題;而同時也向自己需要互動的模組,按照需要的資訊內容的訊息主題訂閱訊息。譬如:一個DEA被加入CloudFoundry叢集中,它需要向大家吼一下,以表明它已經準備好服務了,它會發布一個主題是”dea.start”的訊息:
我們可以看到整個CloudFoundry的核心就是一套訊息系統,如果想瞭解CloudFoundry的來龍去脈,去跟蹤它裡面複雜的訊息機制是非常好的方法。另一方面,CloudFoundry是一套基於訊息的分布式系統,面向訊息的架構是它節點橫向擴充,組件自發現等雲特性的基礎。
Cloud Foundry的架構簡單介紹至此,其實作為第一款開源的PaaS,CloudFoundry架構有很多可以學習借鑒的地方,很多細節上的處理是很精妙的,這些內容如果有可能會在後續文章繼續探討,本文題雖為深入CloudFoundry,其實也只是淺嘗即止,把總體架構介紹一下,目標在於使我們有足夠的背景知識去用CloudFoundry搭建企業內部的私人PaaS。總結一下,筆者從CloudFoundry的結構中學到的東西:
1、基於訊息的多組件架構是實現叢集的簡單、且有效方法。訊息可以使叢集節點間解耦,使自註冊,自發現這些在大規模資料中心中很重要的功能得到實現;
2、適當的抽象層,模板模式的使用,方便第三方可以方便在CloudFoundry開發擴充功能。CloudFoundry在DEA及 Service層都做了抽象層處理,相對應地使開發人員可以容易地為CloudFoundry開發Runtime和Service。例如,在 CloudFoundry剛推出的時候,只支援Node.js,Java, Ruby,但第三方供應商、開源社區快速跟進,為CloudFoundry添加了PHP,Python的支援。這得益於CloudFoundry精巧的 DEA架構設計,如何開發新的Runtime支援,會在後續博文中有所論述.