這是一篇「溫和有趣」的技術文章,若是你初識Docker,對微服務充滿興趣,不妨一讀。或許你的第一次微服務體驗,就從本文開始……node
在本文中,Mesos、Zookeeper、Marathon、Bamboo + HaProxy、Logstash、MesosDns、ElasticSearch和Kibana + Nginx等紛紛亮相,並配有詳細的代碼說明。本文旨在從最初的安裝和環境基礎創建開始,一步步指引你搭建本身的集羣,實現你的目標架構,並在其上運行分佈式服務。算法
小數友情提示:本文篇幅很長,乾貨多多,值得收藏。docker
當開發者開始構建本身的第一款微服務應用程序時,你們一般不會過多考慮編排之類的問題。這時咱們掌握的有兩到四臺服務器,而Ansible腳本已經可以解決大部分問題。不過一旦你們的應用程序規模更大,或者各位決定使用一套環境承載多個不一樣項目,那麼必然須要更多服務器……還有一款用於管理各服務器之上運行的服務。服務器
不過剛剛咱們已經提到了Ansible,難道它還不足以解決問題?這個嘛……答案是否認的。Ansible只能解決一項難題——部署。利用它,你們仍然須要搞定其它多種與微服務相關的問題:咱們必須記得每臺服務器中還有多少剩餘資源、手動管理各清單文件以匹配服務器容量、監控應用程序是否正常運行、當節點出現故障時進行服務回彈以及控制端口號衝突等等。若是你們擁有四臺服務器與十項服務,那麼這些問題就變得比較明顯了。網絡
而以此爲基礎,咱們就須要求助於Mesos了。Mesos是什麼?這是一款集羣管理器,其可以幫助你們在分佈式環境之下運行應用程序。Mesos的關鍵優點包括:架構
資源管理與使用效率;負載均衡
應用程序生命週期控制;框架
Docker容器支持能力。curl
最後一點也使得Mesos成爲咱們最爲完美的解決方案選項。tcp
因爲找到七臺無需使用的服務器對於任何企業都是一項難題,所以咱們在這裏使用Vagrant(這是一款管理虛擬化流程的完美工具)在一臺本地設備(惠普Z230,i7-4770 3.40 GHz,16 GB內存)上構建本身的集羣。另外,咱們也提到了Ansible是一種便捷的部署方式,所以咱們徹底能夠將整個安裝流程拆分紅多個Ansible角色,從而封裝其內部所須要使用的標準Linux命令。
首先,咱們須要創建Mesos集羣基礎——這是一系列虛擬機系統,供咱們在如下步驟中使用。這項工做利用Vagrant可以輕鬆完成。
如下爲來自Vargantfile的部分代碼:
如你們所見,咱們可使用一點Ruby代碼執行如下步驟:
基於CentOS 7.1鏡像構建虛擬機;
設置各虛擬機的資源上限(CPU與內存);
將其與一套網絡相結合;
*利用每臺主機上的一組預約義變量啓動一套Ansible劇本(ansible/master.yml)。
簡單來說,Vagrant文件負責描述如何構建7套虛擬機系統:3套主虛擬機、3套從虛擬機與1套日誌存儲(從技術層面講,這部分也應該進行分佈處理,不過主機設備的資源較爲有限)。你們須要作的是利用下面這條簡單命令將其投入運行:
`vagrant up`
前三步都是由Vagrant實現的,也不屬於咱們今天的討論重點。接下來讓咱們正式進入主題,經過Ansible設置集羣。
正如你們在Vagrantfile當中所見,這裏有3套主劇本及其各自角色:
主角色- 主機包含:
Mesos主實例;
Zookeeper實例;
Marathon實例;
Bamboo + HaProxy實例;
節點- 主機包含:
Mesos從實例;
Docker服務;
Logstash實例;
MesosDns實例;
日誌- 主機包含:
ElasticSearch實例;
Kibana + Nginx實例。
接下來,咱們將分別考慮各個角色,但這裏須要首先強調一點:每一個角色都取決於「OS」角色。該角色與本地網絡及YUM repo的DNS配置設置相關。嚴格地講,咱們應當將這種關聯性從劇本層級中剝離出來,但爲了簡單起見,這裏咱們先讓其保持原狀。
Zookeeper屬於咱們系統中的一大重要組成部分。它將幫助咱們構建集羣並容許來自Mesos生態系統中的其它應用程序(例如Bambbo、MesosDns)與之進行通訊。
Zookeeper的安裝過程很是簡單,並且不須要什麼技巧——從RPM軟件包中獲取一套repo便可。我發現不少朋友傾向於利用現有源代碼構建應用,但在這裏咱們將使用基於供應商的Mesosphere軟件包。
你們須要的就是安裝該軟件包,設置節點ID,更新配置並啓動該服務。
下面來看Zookeeper安裝任務中的代碼片斷:
在這裏,咱們須要回顧一下前面提到過的Vagrantfile——你們還記得下面這部份內容嗎?
Vagrant將所有必要的變量傳遞至Ansible,所以咱們能夠輕鬆在角色中對其加以利用。
正如Zookeeper的配置同樣,咱們只須要對其中的主機IP進行配置:
如下爲咱們集羣最終狀態下的簡單Zookeeper UI(簡稱ZK UI)屏幕:
正如以前所提到,MesoSphere的工做人員很是貼心地把Mesos軟件包加以整合,所以整個安裝流程也將變得更加輕鬆。
其中唯一須要注意的是,Mesos實際上由兩部分構成:
主節點(負責所有管理邏輯);
從節點(負責運行應用並收集與主機資源相關的信息);
換句話來講,咱們須要爲主節點與從節點實現不一樣的安裝邏輯。幸運的是,Ansible可以很是輕鬆地完成這項任務。
如下爲Mesos安裝任務的代碼片斷:
面向這兩者,咱們須要安裝「mesos」軟件包(請記住,相關repo由「OS」角色提供)與Zookeeper URL。
下一站是進行設定。在這裏,咱們只提供諸如主節點quorum size與從節點docker支持等強制性設定。若是你們但願瞭解更多與特定配置相關的內容,不妨閱讀Mesos官方說明文檔。
因爲MesoSphere軟件包同時提供主與從服務,所以咱們須要根據當前角色(主/從)禁用其中的冗餘部分。
爲實現這一目標,你們應當使用Ansible的「conditional」機制。若是你們曾經認真閱讀過「master」劇本,就會發現咱們已經傳遞了一條特殊的mesos_type變量:
在Mesos安裝完成後,你們能夠審視其Web UI並嘗試點擊其中的按鈕:http://192.168.99.11:5050。
須要注意的是,若是當前主機並不是Mesos Master的集羣主節點,那麼UI會將你們從新定向至主節點主機。另外,因爲咱們在虛擬機當中使用了DNS快捷方式(例如「master1」),所以你們也應當在本身的主機設備上使用一樣的快捷方式。
好了,就是這樣——咱們的集羣已經構建完成了。
在痛飲慶功酒以前,咱們還須要回顧其中一些有趣的細節。
首先,你們須要記住——每一個任務都擁有本身的背景信息,咱們將其稱爲「sandbox」。你們能夠將其打開並分析所有輸出結果(可參閱Marathon部分的截屏內容)。須要注意的是,Docker容器必須首先進行pull——所以,若是你們沒有分配足夠的時間用於容器啓動,那麼任務可能沒法在UI中w/o任何消息(你們仍然可以在相關節點的/var/logs/messages中看到消息內容):
要對其進行修復,須要如以上片斷所示配置其中的
另外,也不要忘記設置運行狀態檢查的寬限時長(Java應用每每會長時間處於活動狀態)。不然你們的應用極可能被關閉,並在其從新啓動前進行回彈(運行狀態檢查設定問題稍後咱們再繼續討論):
因爲咱們須要在本身的從主機上運行Docker容器,所以在這些主機上安裝Docker本體就成了必要任務。幸運的是,其安裝過程很是簡單:
下面來看Docker安裝任務中的代碼片斷:
該步驟後的集羣狀態:
儘管咱們的Mesos集羣已經上線並開始運行,但咱們仍然沒法在其上運行本身的Docker容器。嚴格地講,這時咱們可以在Mesos上直接運行的只有一套Mesos框架。固然,咱們還擁有另外一個更符合需求的選項——Marathon。
從技術角度來看,Marathon只是一款簡單的Java軟件包,且可以經過jar命令進行啓動。但好在咱們還擁有一套RPM軟件包,所以咱們不須要擔憂其「後臺化」、配置與控制等問題。此外,因爲咱們的軟件包由MesoSphere負責提供,所以其使用的是一樣的配置文件(Zookeeper URL),因此咱們不須要對其另行設置。
Marathon安裝任務中的代碼片斷:
Marathon還擁有一套Web UI,你們能夠經過URL: http://master1:8080
進行訪問。
下面讓我們找點樂子,部署一項簡單的REST服務(該服務及部署設定稍後另行討論):
如今咱們已經能夠監控其狀態以及分配端口:
所以,咱們能夠對其進行調用並檢查其是否正常工做(固然,結果一切正常)。
咱們甚至能夠對服務進行規模擴展——若是有必要的話(目前規模擴展尚未任何意義):
另外,經過「sandbox」分析其日誌(經過Mesos UI):
在以上示例當中,咱們只部署了一個服務實例。不過若是咱們但願在其中使用大量實例與負載均衡機制,又該如何處理?這個嘛,做爲答案的一部分,咱們將採用HaProxy。這確實是一款很是出色的負載均衡器。不過如何對其進行配置?很簡單,交給Bamboo項目處理便可——它可以與Zookeeper相對接,讀取Mesos狀態並生成HaProxy配置(利用每款Mesos應用的用戶定義角色)。
其安裝過程原本很是簡單,不過遺憾的是目前尚未任何集成有Bamboo軟件包的公共RPM repo。你們能夠對其進行手動構建,並經過本地文件實現安裝,但整個過程其實有點複雜。
如下爲Bamboo安裝任務中的代碼片斷:
在Bamboo安裝完成以後,你們能夠經過其Web UI進行設置: http://master1:8000
另外也能夠經過HaProxy訪問咱們的服務: http://master1/services/fibonacci/1
請注意,咱們在Bamboo安裝中使用了單獨的Ansible劇本(master_bamboo.yml)。之因此這樣處理,是由於咱們須要藉此保證其RPM軟件包在於劇本內運行以前被上傳至虛擬主機當中。
因爲Vagrant會在虛擬機初始化過程當中自動執行Ansible配置任務,所以唯一的解決辦法就是將Bamboo相關內容提取至單獨的劇本當中,並執行如下算法:
利用vagrant up啓動虛擬機;
將RPM文件經過SCP上傳至虛擬機當中;
對Vagrantfile中的ansible.playbook進行變動;
運行vagrant provision master1命令。
如你們所見,Bamboo是整套生態系統中最爲雜亂的部分。因此咱們不妨瞭解其替代方案——例如Marathon負載均衡器。
該步驟後的集羣狀態:
咱們一直沒有談到一個重要的問題——若是咱們的服務須要彼此進行通訊,該如何加以實現?咱們是否可以立足於單一Mesos集羣內部實現服務發現?是的,答案是確定的!相關方案也很是明確——MesosDns。這裏咱們的解決思路很是明確——讀取Mesos集羣狀態並經過DNS(A與SRV記錄)及HTTP API進行發佈。後一點很是重要,由於這將幫助咱們輕鬆構建客戶端負載均衡w/o【1,2】。
整個安裝過程稍有些麻煩,不過沒什麼特別之處須要注意。
如下爲MesosDns安裝任務中的代碼片斷:
Config文件中也沒有什麼值得一提的內容:
你們能夠經過如下SRV記錄請求檢查已安裝的實例:
http://172.17.42.1:8123/v1/services/_fibonacci-service._tcp.marathon.mesos.
歡呼!咱們距離成功已經很近了!必須認可,若是你們已經耐着性子讀到這裏,那麼這個議題確定很是有趣。
值得慶幸的是,這部分並無太多內容可談。日誌記錄就是日誌記錄。咱們只須要將Logstash安裝在所有Mesos從節點當中便可……
如下爲LogStash安裝任務中的代碼片斷:
另外對其config文件進行配置,確保將數據發佈至日誌節點當中:
與此同時,咱們還須要在這些節點上安裝ElasticSearch與Kibana。
ELK安裝任務中的代碼片斷:
這裏使用Docker的唯一理解就是其更爲簡便。固然,咱們也不須要也不該該將日誌數據保存在容器當中。
在安裝完成以後,你們就能夠經過Kibana的Web界面分析ES當中的日誌了:http://log1:5601
下面就是咱們的目標架構,或者說咱們的最終構建成果。看起來不錯,對吧?
圖十八
在咱們的腳本當中,唯一的單點故障來源就是HaProxy/Bamboo。不過你們能夠將兩者部署至所有主節點當中並面向用戶使用基於DNS的輪循機制,從而輕鬆解決這個問題。
到這裏咱們已經擁有了本身的集羣。如今,是時候考慮咱們計劃運行於其上的分佈式服務了(運行簡單應用太過無聊,這裏再也不贅述)。
我已經開發出了一套基於REST服務的小巧SpringBoot,其可以計算斐波那契序列中的第N個數字。這項服務的核心功能在於,其能夠調用自身其它實例以計算該序列中的前一個值。
我知道,這種實現方式效率極低並且很容易致使死鎖(你們不妨想一想這是爲何),但我在這裏主要是藉此對跨服務通訊進行說明。
該服務利用MesosDns HTTP API進行服務發現:
另外還有一套客戶端負載均衡機制(咱們固然須要儘量減小故障點數量,對吧?):
在咱們開始部署工做以前,首先須要爲本身的應用程序構建一套Docker鏡像。在這裏我就不贅述整個流程了,感興趣的朋友能夠查看Gradle配置與Docker說明文件瞭解相關內容。
完成以後,咱們將該鏡像發佈至一套Docker註冊表當中(也能夠經過Gradle實現),這樣Marathon就可以經過從節點上的Docker實例對其進行下載了。你們能夠在這裏找到我建立的示例: https://hub.docker.com/r/krestjaninoff/fibonacci-service/
最後也是最重要的部分,Marathon。如以前所提到,咱們能夠利用Marathon UI實現部署任務。不過這並非最具「技巧性」的辦法。Marathon也擁有本身的REST API,咱們能夠經過簡單的「curl」客戶端對其加以使用:
如下爲SpringBoot mesos installation manifest中的代碼片斷:
讓我來簡單介紹一下該配置文件中的內容(各部分逐一說明):
應用程序 id (在Bamboo配置中使用);
資源限制(若是該集羣不具有必要容量,應用程序將不會啓動——這一點對於基於虛擬機的集羣尤其重要)與實例數量;
容器設置:
forcePullImage是在正確時間點對容器進行更新的唯一方式;
SpringBoot容許咱們經過各環境變量進行config文件覆蓋,所以這是一種良好的容器操做方式;
因爲$HOST變量負責提供DNS名稱(這一點甚至在Marathon官方說明文件中亦沒有體現),所以從Docker容器內獲取主機本地IP的唯一方式就是默認Docker網絡接口172.17.42.1;
backoff因數/設定避免集羣運行「異常」應用,即沒法正常啓動並將所以形成反覆嘗試的應用(具體方式爲延後每一次啓示嘗試);
運行狀態檢查容許Marathon瞭解應用實例處於正常運行抑或是必須執行回彈;
upgradeStrategy幫助你們在無需接入能力的前提下實現應用更新(首先延後新版本,然後中止當前版本)。
最後要提到的是Bamboo,其一樣能夠經過REST API進行配置。這項任務很是簡單:
到這裏,咱們就已經擁有了「deploy」角色……
如下爲Deployment安裝任務中的代碼片斷:
你們能夠經過運行「deploy」劇本的方式進行調用:
到這裏所有結束!
調用該服務 curl http://master1:5000/service/fibonacci/15 (或者直接調用curl http://node2:31135/15);
檢查結果(正確值爲610);
檢查日誌內容(http://log1:5601)。
最後一點很是有趣。你們能夠看到哪臺主機被調用或者響應耗費了多長時間:
好了,今天的文章到這裏就結束了。沒錯,其篇幅遠超通常的「Hello World」指南——不過平心而論,內容仍是很是有趣的,對吧?
英文原文連接:http://trustmeiamadeveloper.com/2015/12/17/mesos-as-a-docker-containers-farm/