張瑞林 吳學(xué)敏
摘要:龐雜而版本升級頻繁的互聯(lián)網(wǎng)后端服務(wù)系統(tǒng),需要一種內(nèi)部耦合性低的方法來實(shí)現(xiàn)靈活開發(fā)、便捷部署。該文分析了Docker容器的特點(diǎn)及其核心技術(shù),然后通過實(shí)例來說明把一個(gè)復(fù)雜的后端服務(wù)拆分為多個(gè)微服務(wù)子系統(tǒng),在Docker官方公布的OpenJDK、MySql等基礎(chǔ)鏡像之上構(gòu)建新鏡像,并運(yùn)行這些鏡像作為微服務(wù),以此來提供整體后端服務(wù)的基本方法,最后總結(jié)了本方法的優(yōu)缺點(diǎn)。
關(guān)鍵詞: Docker技術(shù);后端服務(wù);微服務(wù)
中圖分類號:TP3 ? ? ? ?文獻(xiàn)標(biāo)識碼:A
文章編號:1009-3044(2019)13-0281-02
隨著互聯(lián)網(wǎng)信息技術(shù)的發(fā)展,一些系統(tǒng)變得更加龐大復(fù)雜,后端系統(tǒng)給前端Web或應(yīng)用程序提供的服務(wù)越來越大,功能越來越多。因此,這些臃腫的后端系統(tǒng)帶來一系列問題:開發(fā)者難以掌握整個(gè)大系統(tǒng)全部細(xì)節(jié),修BUG或者增加新功能都不容易;無論修改多小的功能都要對整個(gè)系統(tǒng)進(jìn)行更新,帶來潛在未知風(fēng)險(xiǎn);每次版本更新時(shí),重新啟動也要耗費(fèi)較長時(shí)間等等。為了解決上述問題,把復(fù)雜的后端系統(tǒng)分割為多個(gè)微小系統(tǒng)是一個(gè)不錯的選擇,因此本文提出了一種在后端服務(wù)中應(yīng)用Docker容器作為載體來提供微服務(wù)的解決方法。
1 Docker容器及其核心技術(shù)
Docker技術(shù)是dotCloud 公司在2013年發(fā)布的基于Go語言實(shí)現(xiàn)的云開源項(xiàng)目,與已有的傳統(tǒng)虛擬化技術(shù)相比,Docker技術(shù)有著獨(dú)特的優(yōu)勢,比如輕量級、自由度更大、啟動快等特點(diǎn),并且Docker技術(shù)可以按照所需的服務(wù)和應(yīng)用打包起來建立執(zhí)行的環(huán)境。
Docker有3個(gè)核心概念,鏡像、容器以及倉庫。其中Docker鏡像是一個(gè)由一層層只讀層構(gòu)成的模板文件。Docker容器使用了Linux操作系統(tǒng)內(nèi)核的命名空間(Namespace)、控制組(Control Group)、聯(lián)合文件系統(tǒng)(Union File System)等三個(gè)關(guān)鍵技術(shù)。Docker容器使用Linux內(nèi)核的Namespace特性進(jìn)行各個(gè)容器之間的隔離,通過內(nèi)核的Control Groups進(jìn)行使用資源的限制和監(jiān)控,通過高性能分層文件系統(tǒng)Union File System使得鏡像可以通過分層實(shí)現(xiàn)和繼承。圖1是Docker容器技術(shù)的架構(gòu)圖。
1.1 命名空間Namespace技術(shù)
Namespace技術(shù)是容器的隔離性的基礎(chǔ),Namespace將容器的進(jìn)程、網(wǎng)絡(luò)、消息、文件系統(tǒng)、UTS等系統(tǒng)資源和用戶空間隔離開。使用了Namespace之后,進(jìn)程在Namespace之外展示為一個(gè)普通用戶,但是在Namespace內(nèi)則展現(xiàn)為root用戶(uid=0)。也就是進(jìn)程在這個(gè)Namespace里擁有root權(quán)限,在Namespace外面只有普通用戶的權(quán)限。通過Namespace特性,每個(gè)Docker容器都有自己的獨(dú)立的命名空間,運(yùn)行在該Docker中的應(yīng)用程序和運(yùn)行中獨(dú)立的操作系統(tǒng)中類似,這種隔離性保證了容器之間彼此互不影響。
1.2 控制組Control Groups技術(shù)
Control Groups技術(shù)對進(jìn)程起了限制資源的作用。這些資源包括CPU,內(nèi)存,存儲,網(wǎng)絡(luò)等。通過Control Groups還可以實(shí)時(shí)的監(jiān)控進(jìn)程的監(jiān)控和統(tǒng)計(jì)信息。比如在啟動Docker容器時(shí),可以指定允許使用的內(nèi)存大小,Docker 會自動為容器在目錄/sys/fs/cgroup/memory/Docker/<容器的完整長ID>中創(chuàng)建相應(yīng) Cgroup 配置文件。Control Groups技術(shù)為Docker容器限定使用資源提供了技術(shù)支持。
1.3 聯(lián)合文件系統(tǒng)Union File System技術(shù)
聯(lián)合文件系統(tǒng)Union File System是一種輕量級高性能的分層文件系統(tǒng),能把不同物理位置的目錄合并一起掛載到同一個(gè)虛擬目錄下。Docker容器使用了聯(lián)合文件系統(tǒng)技術(shù)實(shí)現(xiàn)了鏡像的分層。在該文件系統(tǒng)中,每次修改都可以看作創(chuàng)建了一個(gè)新的層Layer,Docker鏡像就是由一層或多層這樣的Layer所構(gòu)成。鏡像層都是只讀的,但是鏡像啟動成為容器,在容器層是可寫的。Docker鏡像之間有順序關(guān)系,最下面一層為基礎(chǔ)鏡像,其他層都會有一個(gè)指針指向下一層,上層鏡像依賴于下層鏡像。
2 使用Docker容器構(gòu)建后端微服務(wù)
2.1 后端服務(wù)整體架構(gòu)
下文以某公司的信息服務(wù)后端系統(tǒng)為例,介紹把該后端系統(tǒng)分割為多個(gè)微服務(wù)子系統(tǒng),再以Docker容器作為載體創(chuàng)建后端服務(wù)的方法。先按照業(yè)務(wù)邏輯進(jìn)行劃分后端微服務(wù),分為生產(chǎn)部后端應(yīng)用服務(wù)、生產(chǎn)部數(shù)據(jù)庫服務(wù)、MQTT消息發(fā)送服務(wù)、售后后端應(yīng)用服務(wù)、售后數(shù)據(jù)庫服務(wù)等5個(gè)微服務(wù),這些微服務(wù)都以Docker容器的方式獨(dú)立運(yùn)行于一個(gè)主機(jī)里,主機(jī)的操作系統(tǒng)是UBUNTU 16.04。圖2是以Docker為載體的后端服務(wù)系統(tǒng),Docker1~5分別承載了上面的五個(gè)微服務(wù),各個(gè)微服務(wù)的Docker以“IP:Port”的方式對外提供后端服務(wù),即要訪問某個(gè)服務(wù),需要知道該服務(wù)的IP和端口號。
2.2 Docker容器微服務(wù)組建步驟
該后臺系統(tǒng)分割為5個(gè)Docker微服務(wù)后,需要Docker1和Docker4提供JAVA環(huán)境來運(yùn)行JAR包,需要Docker3提供MQTT代理服務(wù)器broker(作用是接受發(fā)布者發(fā)布的所有消息再按訂閱規(guī)則發(fā)給不同的消息訂閱者),需要Docker2和Docker5提供MySql數(shù)據(jù)庫服務(wù)。下面是這5個(gè)Docker容器微服務(wù)的組建步驟:
(1)去Docker官方倉庫去獲取這3種鏡像(JAVA運(yùn)行環(huán)境、MQTT代理服務(wù)器、MySql數(shù)據(jù)庫環(huán)境)。具體地是,安裝好Docker后,使用“Docker pull openjdk”命令從倉庫里拉取openjdk這個(gè)Docker鏡像到本地,這鏡像提供了JAVA運(yùn)行環(huán)境;使用“Docker pull toke/mosquitto”命令拉mosquitto鏡像(MQTT服務(wù)鏡像);使用“Docker pull mysql”命令拉取MySql鏡像。
(2)把生產(chǎn)部后端服務(wù)的JAVA JAR包放到JDK鏡像后生成新的鏡像。具體地是,新建Dockerfile,使用Docker build命令按照Dockerfile里設(shè)定的規(guī)則來創(chuàng)建Docker鏡像。在這個(gè)基礎(chǔ)鏡像之上,把生產(chǎn)部后端服務(wù)的JAVA JAR包拷貝到新鏡像里,再設(shè)定該容器啟動時(shí)自動運(yùn)行該JAR包即可。
(3)使用Docker run命令運(yùn)行第2步生成的鏡像來創(chuàng)建Docker容器,以此提供生產(chǎn)部后端微服務(wù),運(yùn)行時(shí)需要指定容器端口和映射到宿主機(jī)的端口,因?yàn)樽罱K是需要通過“IP:端口”的形式來提供后端服務(wù),每個(gè)Docker容器都會自動獲取一個(gè)內(nèi)網(wǎng)IP。
(4)把售后后端服務(wù)的JAVA JAR包放到JDK鏡像后生成新的鏡像。這一步的和第2步類似,使用的JAR包換成售后后端的JAR包即可。
(5)運(yùn)行第4步生成的鏡像來創(chuàng)建Docker容器,以此提供售后后端微服務(wù),這一步和第3步類似,注意,指定的宿主機(jī)映射端口號要不同。
(6)運(yùn)行第1步獲得的MySql鏡像創(chuàng)建生產(chǎn)部數(shù)據(jù)庫容器。運(yùn)行時(shí)也指定容器端口和映射到宿主機(jī)的端口。采用數(shù)據(jù)卷(Volume)的方式把MySql容器內(nèi)部的數(shù)據(jù)庫目錄/var/lib/mysql掛載到宿主機(jī)的目錄(比如新建一個(gè)目錄/host/mysql_data/)下,這樣,容器內(nèi)的MySql數(shù)據(jù)文件就會持久化保存到宿主機(jī),即使容器本身被刪除,我們也可以在宿主機(jī)上的掛載目錄里找到數(shù)據(jù)庫文件。
(7)運(yùn)行第1步獲得的MQTT鏡像來提供MQTT代理服務(wù)器。運(yùn)行時(shí)要指定映射到宿主機(jī)的端口和MQTT的端口。
3 Docker容器作為后端服務(wù)載體的優(yōu)缺點(diǎn)分析
在采用Docker容器作為后端微服務(wù)的載體后,主要有下列優(yōu)點(diǎn):
(1)Docker容器可以打包了整個(gè)運(yùn)行環(huán)境,確保了開發(fā)環(huán)境、測試環(huán)境以及生產(chǎn)環(huán)境的一致性。這樣就不會出現(xiàn)開發(fā)環(huán)境運(yùn)行良好,到生產(chǎn)環(huán)境就發(fā)生異常等問題。生產(chǎn)環(huán)境出現(xiàn)問題,也可以方便地把生產(chǎn)環(huán)境的鏡像拿到開發(fā)環(huán)境進(jìn)行問題重現(xiàn)和調(diào)查。
(2)Docker鏡像占用硬盤空間比傳統(tǒng)虛擬機(jī)小,傳統(tǒng)虛擬機(jī)鏡像通常以G字節(jié)為單位,Docker鏡像通常只有幾M到幾百M(fèi)字節(jié)。尺寸的減小不僅僅降低了硬盤資源占用,在傳輸文件時(shí)也更加快捷。
(3)Docker容器在對硬件要求較傳統(tǒng)虛擬機(jī)低,因?yàn)镈ocker容器之間共用了宿主機(jī)的操作系統(tǒng)資源。一臺主機(jī)上可以運(yùn)行幾十、幾百甚至更多的Docker容器。
Docker容器作為后端微服務(wù)的載體也存在一些不足之處,主要有下面幾點(diǎn):
(1)Docker容器之間跟宿主機(jī)共用一些系統(tǒng)資源,隔離性不徹底,會存在安全上的未知風(fēng)險(xiǎn)。
(2)Docker基于64位Linux內(nèi)核特性,所以在其他操作系統(tǒng)比如windows或MAC上不能直接使用Docker。
(3)在Docker里的程序調(diào)用系統(tǒng)服務(wù)時(shí)會有一些不便,比如,使用系統(tǒng)定時(shí)任務(wù)crontab,用法和普通的主機(jī)里的crontab不一樣。
4 結(jié)語
Docker官方提供了很多流行應(yīng)用的鏡像文件,比如本文用到OpenJDK、MySql、MQTT等鏡像,我們可以在這些基礎(chǔ)鏡像之上創(chuàng)建自己的應(yīng)用鏡像。采用這些鏡像為載體,把復(fù)雜的后端系統(tǒng)劃分為多個(gè)小系統(tǒng),可以充分利用Docker隔離性、系統(tǒng)資源要求相對低、部署方便等特性,特別適合模塊多,版本更新頻繁的后端系統(tǒng),在實(shí)際工程應(yīng)用中已經(jīng)取得了良好效果。
參考文獻(xiàn):
[1] Sam Newman.微服務(wù)設(shè)計(jì)[M].北京:人民郵電出版社,2016:23-26.
[2] 楊保華.Docker技術(shù)入門與實(shí)踐[M].北京:機(jī)械工業(yè)出版社2016:165-171.
[3] 謝睿.Docker技術(shù)在Web服務(wù)中的應(yīng)用[J].電子技術(shù)與軟件工程,2018(16):173.
【通聯(lián)編輯:代影】