眾所周知,企業網盤在這兩年呈現爆發式增長,越來越多的企業選擇企業網盤,來解決企業在業務過程中面臨的數據集中存儲、共享、分發、協同辦公以及移動化等痛點需求。同時將企業網盤整合到各個業務系統中,大幅提高企業的數據流轉效率和安全!
而聯想企業網盤增長尤為迅速,僅聯想私有云網盤業務15年較14年增長300%。大家都知道歷史上所有的私有云的產品在迅猛發展的過程中,部署實施交付始終是一個巨大的挑戰。其中,解決分布式部署交付的問題是諸多挑戰中的核心。
我們的聯想企業網盤在業務發展之初就開始考慮如何高效的交付,經過團隊持續的提升和優化,功夫不負有心人,我們逐步實現了一套基于Docker的分布式部署和運維框架“DragonBall”。這也使得交付的環節成為我們用戶滿意度非常高的一個環節,也成為了聯想企業網盤的一個核心競爭力!
相信所有80后都對龍珠這個名字很有感情,沒錯,集齊龍珠就可以召喚神龍!在分布式系統的場景中,召喚神龍的意義就是充分發揮分布式架構的強大威力。DragonBall項目經過一段時間的發展和完善,部署10臺規模小微集群的時間從三五天縮減到10分鐘左右。
由于“分布式部署”這個話題牽扯細節眾多,下文將重點介紹聯想私有云網盤在這方面的經驗與實踐:
分布式系統部署的主要挑戰
分布式系統部署和交付的挑戰并不單純來自技術方面,很多時候我們還需要從項目管理的角度來思考,但基本上都逃不過這些最直接的挑戰:
l 對實施人員要求很高
以redhat系統舉例,配置yum源、安裝各種依賴包、配置調試網絡、設置selinux、改防火墻規則、配置ulimit、寫啟動腳本、下源碼make ……這個列表還可以接著寫很長。可能有人說合格的運維本來就應該會這些啊!沒錯,即使你已經滾瓜爛熟,但誰又能保證這么多操作沒有錯誤呢?這些重復勞動居然不能自動化?簡直喪心病狂!
l 軟件環境和依賴包的兼容性問題
Ok,假定你已經按照研發提供的list完成了所有依賴包的安裝,高高興興準備啟動服務了,那么恭喜你,你已經站在了另一個大坑邊上:版本兼容噩夢。
由于各種操作系統發行版之間的差異,基本上你無法遇到完全一致的軟件環境,各種依賴庫、依賴庫的依賴庫,版本、編譯參數、patch千差萬別。
l 各模塊之間啟動順序無法保證
當模塊間存在強依賴時,保證正確的啟動順序非常重要。
l 伴隨著節點數量的增加,工作量和操作錯誤概率呈指數增長。
很多配置項需要在每一個節點配置與其他所有節點相關的參數,這樣的話總配置項就變成了N*(N-1),當N大于10的時候,這種配置將變成災難。
而且只要是有人參與的操作一定有機會犯錯,節點數的增加將大大提高出錯概率。
l 客戶生產環境往往與前期溝通差距很大,經常需要部署人員現場隨時調整部署方案
其實大部分客戶非常配合,也最大努力的提供必要信息,但是很多情況下設計好的部署方案必須臨時調整。
聯想企業網盤如何解決這些問題
分層部署,隔離問題,分而治之
將整個部署過程分成三個層面:資源層、容器層、應用層
l 資源層
完成操作系統層面配置和部署,包括內核升級、docker服務部署、安全策略配置、ssh公鑰分發等。
資源層的安裝需要登錄每臺服務器并root身份運行DragonBall.bin,此時內置腳本將提示用戶完成本地設置,并選出一臺服務器充當“portal”,即DragonBall的web配置界面,同時portal管理了一個私有的docker-registry用于分發docker鏡像。
通過資源層的部署,DragonBall向上層交付了資源操作平面。
資源操作平面具備向任意服務器導入鏡像、起停容器的能力,同時DragonBall也能夠實時監控基本的資源使用情況,如內存、cpu、io、連接數等等。
l 容器層
在資源操作平面上,部署實施人員可以通過portal提供的web界面方便的編排容器和服務器之間的關系。通過“添加設備”功能還能夠很方便的加入新的服務器資源。
通過容器層的部署,DragonBall向上層交付了容器操作平面。
容器操作平面具備對任何一個實現了DragonBall服務規范的服務進行啟動、停止、狀態監控、參數配置、通知其他服務狀態變化的能力。
l 應用層
應用層向最終用戶交付系統能力。在容器操作平面上,通過編排各種服務之間的關系,發揮分布式系統架構的威力。
業界有句老話,簡單就是靈活!在DragonBall框架下只有兩種類型容器: Service和Backend。
Service容器負責對外提供服務訪問點。既可以自己處理請求,也可以將請求分發給Backend;Backend容器真正處理Service請求。在配置Service的Backend時,也可以將其他Service當成Backend。
兩種類型容器間一個顯著區別是Service容器內集成了負載均衡和故障剔除機制(通過內置nginx實現),而Backend容器則不具備這些機制。
(Docker社區建議一個Docker跑一個進程,這聽起來不錯,但是當系統內有成千上萬的進程時,這種策略似乎不便于配置管理。Kubernetes項目提出的pod概念很棒,2015年docker社區也發布了docker compose。但是很遺憾,我們啟動項目時還沒有接觸到這些出色的項目。經過大量測試后,我們沿用了一個容器跑幾個進程的土辦法)
通過Service、Backend模式,我們可以構造出Service依賴樹,樹的根節點對系統外提供服務。
Service依賴樹將在容器啟動階段發揮重要作用。當啟動某服務時,DragonBall框架將遞歸檢查此服務的Backend(或充當Backend的Service),先啟動依賴樹的葉子節點并保證狀態正常后再逐級回溯啟動上級服務。這種機制保證了各模塊的啟動順序。
最終,我們可以看到并監控各服務的運行狀況了。
通過三層結構,DragonBall將各種問題分開處理,降低了整體復雜度。
構建標準化鏡像,將差異封印在容器中
企業級分布式系統的正常運轉,僅僅依靠精巧的框架和機制是不夠的。真正的業務還要由勤奮的程序猿來添磚加瓦。
那么如何將不同廠商、不同語言、不同配置模式的模塊快速部署到正確的位置,又如何保證模塊配置正確并按照正確順序啟動呢?
為了解決這個問題,DragonBall定義了標準模塊鏡像。
l 首先一個標準模塊需要按如下結構規劃目錄。
其中log最容易理解,用于模塊記錄日志使用。
n storage目錄用于存儲持久化數據。
n module目錄用來放置模塊自身文件。
n action目錄提供了一種簡單粗暴的操作模式,模塊需要編寫對應腳本放到對應目錄下面。當目錄對應的事件發生時,DragonBall框架將按照ascii順序依次同步調用腳本(默認執行超時時間為1分鐘)。
action目錄下的status和info用于輸出容器的當前狀態和容器的描述性信息。
l 然后使用ADD命令把my_service加入鏡像中,Dockerfile大概是這個樣子:
然后我們的每日構建系統會自動將鏡像build出來,第二天的bin包中將包含此模塊鏡像。
l 最后,當DragonBall框架啟動模塊容器時會按照配置將storage、log目錄掛載到容器外,同時調用start目錄中的所有腳本,至此模塊啟動完成。
從網狀配置模式到星形配置模式
為了避免網狀配置,最初的DragonBall框架采用全局配置文件的模式。
即部署人員在web界面完成配置之后,DragonBall框架會生成一個巨大的配置文件,配置文件描述了整個系統的所有物理機情況、模塊情況、Service依賴樹、服務訪問點等等。
任何一個模塊看到這個配置文件后即可獲得所有需要的信息。而當任何配置發生變化后,框架只需要重新生成該配置文件并通知每個模塊即可。
通過這種模式確實簡化了整體配置復雜度,但是也引入了一些問題:
l 任何配置發生變化后,所有模塊都會收到更新通知,浪費了系統資源
l 連續改變配置后,不同網絡延遲的容器收到的配置可能短時間不一致
l 配置推送失敗后沒有可靠的補救措施
為了解決上述問題,DragonBall框架集成了Consul服務,通過watch機制,只有當前模塊相關的信息發生變化時才會收到通知。為了快速適配一些第三方模塊,我們還大量采用了consul template,有興趣的朋友可以深入了解一下。
(https://www.hashicorp.com/blog/introducing-consul-template.html)
與Kubernetes有何區別
很多人可能會問這不跟Kubernetes干的事情一樣嗎?很多功能還不如Kubernetes強大,為什么要重新造輪子?
Kubernetes是很棒的開源項目,擁有很多值得借鑒的理念,但其核心目的并不是解決分布式系統的快速部署問題,其自身的部署也是具有一定難度的,而DragonBall在項目啟動之初就把簡單、迅速、友好作為第一設計目標。
總結
本文首先介紹了企業級分布式系統部署所面臨的挑戰,并且結合聯想云存儲自有框架研發經驗分享了一些解決問題的思想和具體做法。最后還與Kubernetes項目進行了簡單對比。