利用Docker/Ansible实现轻量集群服务部署(视频演示+彩蛋)
周良偉
網易云信系統架構師
負責云信IM平臺的架構設計和服務器研發團隊
作者簡介今天和大家分享的主題是如何用Docker/Ansible來做輕量私有化的技術方案。首先,簡單介紹一下所謂輕量私有化到底是怎么回事。
我們這幾年在做公有云平臺,過程中也接觸到很多客戶。有許多客戶提出來說,你們的云平臺服務很好、線上也很穩定,但希望能把云平臺在自己的環境里部署起來,于是就有了今天要分享的題目。
今天分享的內容,大致分為三個部分:第一部分,做輕量私有化面臨什么樣的問題;第二部分,面對這些問題,我們如何去解決,即方案;最后是關于實踐的部分。因平臺沒有辦法做實時Coding的交互的過程,所以我簡單錄了一段視頻的教程,大家可以對照這個視頻看一下我們具體是怎么做的。
因為這個過程會涉及到代碼的部分,所以我把sample的代碼已經提交到GitHub,后面跟大家分享一下,大家可以對照著一起看。
●●●
問? 題
大概2011年左右,我剛開始參加工作的時候,其實很少聽到XX云的說法,大家講的更多的是分布式系統。那個時候分布式系統非常火,我第一個工作就是一個分布式的文件系統。
分布式系統的分類
有工作經驗的同學都知道,我們說的云其實就是一種規模化的分布式系統,這里我為分布式系統簡單做了一個分類,當然這里的分類不一定準確,只是我個人對分布式集群系統的理解。
1.面向特定場景的服務集群/云
這個場景是什么?比如面向存儲場景,我們知道有HDFS/HBase系統;面向計算型,MapReduce/Yarn/Spark/Storm這樣一種計算平臺;還有一些像Mesos這種資源調度型平臺。這些就是面向特定場景的云。
除了這些大家耳熟能詳的平臺,在網易內部,我們有DDB(分布式數據庫)以及RDS、NOS。NOS是一個分布式的對象存儲服務,也是屬于特定場景的服務集群,或者稱為特定場景的云。
2.面向通用場景的資源型云服務
比如現在非常熱門的OpenStack這樣一個IaaS層的云平臺,或者像Ceph這樣面向存儲的云平臺,其實它們都屬于通用型。
像Ceph就是把存儲資源云化,還有像Vita-Line這樣的網絡虛擬化的一種云服務,我們把這些稱為面向通用場景的資源型云服務。
3.獨辟蹊徑的容器型的服務
這和今天講解的內容有關系了,獨辟蹊徑的容器型的服務其實就是Docker容器+K8S,對于Docker這種容器進行一個資源調度的云平臺。
4.最近非常火的FaaS平臺,就是函數及計算的云平臺,這個和今天的內容不太相關,就不發散開了。
所以,有那么多不同類型的云服務,我們針對專門的場景提供PaaS層的平臺服務,但我們要把這樣一個平臺服務搬到一個企業內部或者一個獨立的環境里面。如果把整個云搬進去,可想象這個代價會非常大,而且從復制性上來說,這不具有非常高的可復制性。
在線上運營那么多年的云平臺后,我們也總結了一些經驗、積累了一些技術棧,開始思考能不能用更加簡單的方式實現輕量級私有化服務。
輕量私有化面臨的問題
所以我們要的模式是什么樣的?這是我們的服務面臨的問題:
1.單機不夠用。在任何一個環境里,沒有單體的程序或者單機軟件可以滿足一個應用場景,這種產品非常少。
2. 規模化不高。我們規模化還沒有公有云上做得那么高,在私有云環境里,我們的用戶大概是5萬或者10萬的量級。
其實對于現在的企業來說,5萬到10萬算是非常大的規模,但和互聯網相比,還是遠遠不夠的,所以企業私有化經常面臨的用戶規模就是幾萬這個量級,這個規模化程度要說高,也不是那么高。
3.技術棧太復雜。我們公有云平臺涉及到的模塊非常多,在這些模塊里,每個服務實現的技術棧是不一樣的,語言是不一樣的,依賴的軟件和網絡環境也是不一樣的。
面對這樣一個技術棧,我們如何把這個技術方案盡量簡化,做到可復制性,這就是我們面臨的挑戰。
剛剛說整個技術棧太復雜,我們的集群也太復雜,規模沒有那么大,但也不小。
這里以網易云信為例簡單看一下。下圖是我們現在涉及到的一些服務架構,當然這里面沒有列全,但是主要模塊都已經列出來了。
從這張圖可看到,我們的服務涉及到非常多的不同的服務模塊,比如說負責長連接的服務,負責做業務調度的服務,包括一些Web類的API的服務,還有對象存儲、文件上傳、文件下載以及媒體服務,還有一個分布式的文件系統,再往后還有處理消息漫游的服務、推送的服務等各種各樣的服務。
在這些服務里面,涉及到的技術棧不只是Java,有些其它的比如消息隊列,我們今天演示的就是RabbitMQ ,它的技術棧是在Erlang 層面,和我們之前熟悉的Java是完全不一樣的東西,像數據庫或者說緩存服務,那又是別的技術棧的東西。
所以,從這張圖里我們發現,想要解決集群的快速部署 ,我們面臨的問題就是:這么繁雜的一個集群,我們要怎么通過技術讓它變得簡單。
于是,進入今天的重點分享環節,輕量集群部署應該怎么做?
●●●
方? 案
輕量集群服務部署
如何部署輕量集群服務?我們總結了一下,有三句話。
1.標準OS提供計算資源。
因為是標準OS,所以能夠兼容物理機/云主機這樣不同的環境。
2.Docker實現程序包封裝和運行時資源隔離。
前面說到,我們整個集群的搭建過程中,服務模塊是基于不同技術棧上來做的,可能有的是Erlang,有的是C,有的可能對 Linux的內核有要求, 比如有的要求4.x的版本,有的要求2.x的版本。
這樣不同程序包的整個依賴環境會非常復雜,對此,我們可以用Docker的形式來將這些程序包全部封裝起來,同時還能在運行時實現資源隔離, 我們對CPU和對內存都去做限定。
3.用Ansible實現集群分布式部署。
為什么要在這里用Ansible?我在前面說Docker時,很多同學自然而然會想到,那你用Docker,是不是應該用容器云、K8S呢?非常對,本身容器服務或者微服務,其實非常適合K8S這樣的容器。
但在輕量私有化這樣一個限定的場景里,如果為了在幾臺機子上部署一套云平臺,專門去搭建一個K8S,代價是非常大的。因為本身K8S需要做鏡像庫、資源調度、做控制節點,對成本的要求本身就比較高。
那么既然要把這個東西脫離,我們就必須要有一個可以替代的東西,在這里就是Ansible。
Ansible本身是用來做協同的多機同步控制處理的框架,可能做運維的同學會比較了解,它是大家日常做集群化的操作中非常有用的東西,我們就把它引入進來,解決我們的問題。
常用的技術棧工具
1.Docker
Docker是什么?Docker現在被稱為Moby,2017年4月在DockerCon上,官方做了這樣一個動作,后面就被商業化了,這里說到的Docker是Docker CE或者叫Moby。
Docker是一個開源的應用容器引擎,讓開發者可以打包它們的應用以及依賴包到一個可移植的容器中,然后發布到任何流行的Linux機器上,也可以實現虛擬化,容器是完全使用沙箱機制,相互之間不會有任何接口。
那么在Docker里面有幾個術語,這里簡單說一下:
Docker鏡像。Docker鏡像非常像管理源代碼用的GitHub,了解GitHub的同學都知道GitHub上可以用來做版本控制,對我們代碼可以做提交、開分支,可以做commit, 各種各樣的操作,非常簡單、非常快速。
鏡像倉庫。Docker的鏡像倉庫類似于GitHub這樣一個的產品形態,可以幫助我們管理鏡像,那么Docker鏡像是把我們所有程序包和我們的應用以及程序包依賴的依賴包全部打包成一個鏡像的形式、一個Image用來管理,我們可以理解為,它也是一個代碼,它是一個可執行的、二進制的代碼。
Container實例。Container實例就是把一個Docker鏡像給跑起來,在運行過程中,我們稱它為一個容器實例。
數據卷Volume。我們可以把它理解為一個目錄,或者磁盤上的一個空間。
因為Docker本來用了沙箱機制,所以它在運行時所需要用到的這些磁盤、本地文件或者產生的一些數據,如果在不做任何配置的情況下,它是在這個沙箱里面的。
而通過數據卷的形式,我們可以把數據加載出來,加載到宿主機上,把宿主機上某個特定的目錄,或者是某個網絡上特定的目錄,加載到容器里。在容器里面這個數據卷就可以當作一個硬盤一樣,快速使用。
Docker網絡。Docker網絡是用來把實例和宿主機之間做一個相互的隔離或者做一個橋接。同時在Docker網絡里面,比如我們在容器內部,開一個TomCat服務是8080端口,但我們宿主機上面同時運行的有三個實例,大家知道3個8080端口不可能同時在一臺宿主機上開始,如果要去改容器鏡像,那有點復雜。
通過Docker網絡,我們就可以把這個端口直接映射出來,比如把3個容器的8080端口分別映射到宿主機上,分別為8080、8081、8082,它能夠做到快速的網絡映射轉換的過程。
Dockerfile。Dockerfile是用來描述Docker鏡像的整個構建過程,可以理解為Docker的一個代碼,通過這個代碼,可以構建出一個二進制的鏡像。
2.Kubernetes
講到Docker的話,必然要講到K8S,K8S全名是Kubernetes,它是Google開源的容器集群管理系統,用Go語言開發,提供應用部署、維護、擴展機制等功能,利用K8S能方便地管理跨機器運行容器化的應用。
其主要功能如下:
使用Docker對應用程序包裝(package)、實例化(instantiate)、運行(run)。
以集群的方式運行、管理跨機器的容器。
解決 Docker 跨機器容器之間的通訊問題。
Kubernetes 具有自我修復機制,比如Docker在這個宿主機上,這個容器死掉之后,可以在另外一個宿主機上將這個容器迅速地拉起來,保證服務的計算容量和高可用,這個非常重要,使得容器集群總是運行在用戶期望的狀態。
3.Ansible
然而K8S比較重,引入輕量方案中不合適,于是我們找了一種替代品——Ansible。
Ansible是一種自動化運維工具,基于Python開發出來,它集合了眾多運維工具的優點,可以實現批量系統配置、進行程序部署、運行命令等功能。
Ansible 是基于模塊工作的,我們知道Eclipse也是基于模塊,基于模塊代表它可以擴展,社區也貢獻了非常多的模塊來擴展Ansible的能力,所以Ansible現在是非常強大的。
它本身沒有批量部署的能力,但模塊可以實現非常多的功能,主要有:
Host inventory:用來制定需要操作的被控機的列表,它可以在配置文件中快速修改列表,來調整需要操作的環節,下面實踐的部分會講到這些。
連接插件Connection Plugins:負責和被監控端實現通信,被控機無 Agent,所以不存在初始化,或者Agent下線后導致被控機沒有辦法去執行命令這樣子的問題。
Host inventory:用來制定需要操作的被控機的列表,它可以在配置文件中快速修改列表,來調整需要操作的環節,下面實踐的部分會講到這些。
借助于各種模塊、核心模塊、Command 模塊、自定義模塊來實現最多的功能。
Playbook:劇本執行多個任務時,可以讓節點一次性運行多個任務,可以幫助我們快速集群化部署的效果。
方案呈現
簡單給大家科普了一下我們需要用到的三個技術棧上的工具,接下里看一下網易云信把這么多的模塊、這么復雜的架構全部打包起來,會變成什么樣子。
如圖所示,最底層就是一個OS層,在OS層上面運行的是一個一個Docker容器,這些Docker容器運行狀態需要被監控,所以我們在OS層的宿主機上部署了MetricBeat,它是 ELK中用來做監控的Agent,可以幫助我們監控各個容器是否正常。
那么在OS層中還需要解決的問題是什么?一是權限的管理,比如主機和主機之間需要互通;二是基礎性能管理,比如文件句柄數是否開夠了,還有文件目錄或者數據盤的權限是否開放出來,包括網絡層的一些參數需要進行一些性能調優;三是Docker環境的初始化,還有Supervisor的服務,因為我們任何一臺機器或任何一種服務都有當機、故障重啟的風險,一旦服務器重啟,你需要手動拉起服務,或者它掛掉以后沒有一個自動恢復的機制,這個在高可用上可能體驗不是那么好,所以我們引入一個Supervisor,通過Supervisor作為一個后臺,幫我們把這些服務保持一個健康的狀態。
最重要一點是,在OS層還需要做一個CPU和內存資源的隔離,這個也是借助于Docker本身基于Cgroup做資源隔離的能力實現的。
在OS層之上,就是Docker容器,我們在每個Docker容器里面寫的時候不是單個的進程,而是我們用的多個進程,因為我們理解任何一個服務其實都有可能不是一個單體程序,有可能是一個主程序加上N個輔助程序來完成,所以我們在這里面把N個輔助程序通過Supervisor關聯到一起。
像圖上這個示例里面有幾個程序,一個是我們的主進程,就是NIM Proc,還有處理日志用的Rsyslog 或者Filebeat, Filebeat也是ELK里面做日志采集用的,還有Metricbeat,這是用來做指標采集的,把這些主進程或輔助進程都通過Supervisor管理起來。
在Docker里還要解決的一個問題是對依賴環境的差異化,比如:當前需要執行的程序需要JDK 1.7的版本,那么我們可以把1.7的JDK封裝到這個鏡像里去,對于另外一個程序或者另外一個軟件如像ELK里面的ElasticSearch,它需要的JDK版本是1.8以上,如果我簡單地把進程跑在宿主機上,可能需要去安裝多個JDK的版本,然后在應用里面去單獨指定,這個過程可能會比較復雜。
如果沒有軟件沖突還好,一旦你依賴的是內核層或者底層庫,就會產生軟件沖突,代表你不能在同一個機器上運行。這種情況就可以用Docker去達到這樣一個目的。
再往上層就是一個個模塊被我們打包成一個個鏡像,這里一個個方塊代表著單個的鏡像,這些鏡像都是用Dockerfile來描述,通過Dockerfile我們可以把這些鏡像一個個程序化地構建起來,構建完了之后,我們要把鏡像跑起來,跑起來之后變成了容器實例,一個個實例之間相互組合之后變成了整體的服務。把這些鏡像拉起來變成容器服務,這就是Ansible要做的事情。
我們看到最上層有非常多的文件,這些文件代表一個個YAML文件,代表了一個個Playbook。我們看到這里一個個Playbook,比如DB_cluster,這個腳本是專門用來處理構建DB數據庫的集群。又如NOS.yml,NOS是我們網易對象存儲服務的簡稱,它通過這個腳本,可以在多機上部署起來一個對象存儲服務。
其它的也是類似這樣的服務,可以通過腳本化的形式管理起來。通過這張圖大家也可以看到我們整個技術方案,通過借助這樣一個工具,把它做到一個可復制的程度。
●●●
實? 例
下面就是實踐的部分:先簡單搭一個RabbitMQ的集群, 我們需要把單節點給布置起來,需要決定這個MQ的節點的角色,然后做不同的配置、cookie 的同步,做各種各樣的事情,最后還需要做一些用戶的初始化,整個部署的過程非常復雜。
對于一個經驗豐富的運維人員來說,部署一個集群也需要花費一段時間,過程中有可能踩到很多坑。我們希望部署一個MQ集群就像把大象關進冰箱一樣,只需要三步:打開冰箱門——放進大象——關上門。這個就是我們的目標。
我們今天實踐的部分——怎么快速搭建一個MQ集群,這里已經把相關代碼放到GitHub上:https://github.com/williamleung/lite-deploy-sample。
具體過程也已經錄屏,大家可以參考(iframe 代碼嵌入文章內):
https://v.qq.com/x/page/z05343zmcdj.html?__t=1&ptag=1.qzone&_out=101
參照這個代碼怎么用Docker和Ansible把整個過程自動化處理,這里還涉及到一個多機部署的問題,在示例代碼中,使用Vagrant來創建虛擬機模擬了一個多機部署的環境。
Vagrant今天在分享里沒有講太多內容,感興趣的同學可以自己了解一下,簡單來說,Vagrant可以幫助你用代碼的形式快速維護虛擬機的集群環境。
實踐過程中有一個開發部署的模型,這個模型分兩個部分角色,研發人員做的工作和部署人員做的工作,完成后幫助大家解讀示例的代碼部分。
研發人員主要負責開發打包鏡像、開發部署腳本以及鏡像和腳本的分發;現場實施人員主要負責創建服務器、目標環境初始化以及集群部署。
最后提供給大家幾個參考資料,以供大家學習:
Vagrant地址
https://app.vagrantup.com/boxes/search
網易云的容器服務地址
https://c.163.com/hub#/m/home/
Ansible資源庫
https://galaxy.ansible.com/
Daocloud容器加速鏡像地址:
https://download.daocloud.io/Docker_Mirror/Docker
●●●
問答環節
【問題】:Docker 是必然的趨勢嗎!
答:是不是“必然”的趨勢我覺得每個人都有自己的看法,其實對于任何一個技術或者工具,我覺得都有自己的應用場景,如果能結合自己的業務把Docker用好更加重要。
比如在今天分享的這個case里,我們更加關注的是Docker對應用程序及其依賴庫進行封裝的能力,通過dockerfile可以將其固化下來支持不斷迭代;其次就是容器支持在運行時資源隔離,幫助我們更好地利用宿主機上的資源;但借助K8S實現的容器服務調度的功能就沒有用到,這也是我們基于自己的業務場景做出的選擇。
?
想做“沖頂大會”?全球首套直播競答解決方案來了!
總結
以上是生活随笔為你收集整理的利用Docker/Ansible实现轻量集群服务部署(视频演示+彩蛋)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网页性能分析不完全指南
- 下一篇: 网易云信国际短信上线啦!