陳莉君, 張義飛
(西安郵電大學(xué) 計算機學(xué)院, 西安710121)
基于LKM的Docker資源信息隔離方法①
陳莉君, 張義飛
(西安郵電大學(xué) 計算機學(xué)院, 西安710121)
針對Docker容器目前存在的內(nèi)存資源信息尚未隔離的問題, 設(shè)計了一種基于LKM技術(shù)的資源信息隔離方法. 該方法通過LKM的形式利用系統(tǒng)調(diào)用劫持來修改讀取到的procfs文件內(nèi)容, 從而實現(xiàn)了Docker中的容器資源信息隔離的功能, 使得在其上運行的容器可以不用作任何修改就能達(dá)到資源信息隔離的目的. 最后通過實驗證明資源信息隔離的功能是可用的.
LKM; Docker; procfs; 容器; 隔離
隨著云計算的普及, 人們對應(yīng)用的多樣化需求促使PaaS[1]技術(shù)的快速發(fā)展, 其中云應(yīng)用的隔離性和資源控制顯得尤為重要. 傳統(tǒng)云應(yīng)用的隔離性和資源控制是通過使用虛擬機來實現(xiàn)的, 但是部署在虛擬機中的應(yīng)用會因為需要經(jīng)過傳統(tǒng)虛擬化技術(shù)提供的一個抽象層從而導(dǎo)致應(yīng)用性能的下降, 在云環(huán)境下, 這將會導(dǎo)致基礎(chǔ)設(shè)施層有效率損失[2-4]. 基于容器的虛擬化技術(shù)可以簡化應(yīng)用的部署, 并通過Linux內(nèi)核提供的特性來實現(xiàn)隔離和資源控制, 不需要經(jīng)過額外的抽象層,所以在效率上要高于傳統(tǒng)的虛擬化技術(shù)[2]. 通過隔離可以在單一操作系統(tǒng)上運行多個實例, 實例之間彼此互不影響, 通過資源控制則可以將實例限制在一個資源集合中運行. Docker充分利用了Linux內(nèi)核提供的Namespace和Cgroups特性. 但是目前Linux內(nèi)核提供的Namespace特性還不夠完善[5], 對于procfs[6,7]文件系統(tǒng)的隔離還沒有完全實現(xiàn), 這導(dǎo)致系統(tǒng)資源信息沒有隔離. 容器中的進(jìn)程通過查看procfs文件系統(tǒng)內(nèi)容或者使用free等基于procfs文件系統(tǒng)的命令查看系統(tǒng)資源信息的時候獲取到的信息都是宿主機的資源信息,并不是容器本身的資源信息. 一方面對于容器的使用者來說會得到不正確的結(jié)果給用戶造成困擾, 另一方面對于一些需要獲取系統(tǒng)資源信息的軟件來說會導(dǎo)致其獲取不到正確的資源信息, 例如監(jiān)控軟件的agent端.
目前對于Docker的資源信息尚未隔離的問題, 業(yè)界也有一些解決方案, 但是都必須通過修改程序獲取資源信息的接口來解決. 例如lxcfs[8], Docker API. 對于一些依賴于procfs文件系統(tǒng)來獲取資源信息的軟件來說, 必須修改其資源信息獲取接口才能在容器中正常運行以獲得正確的資源信息. 沒有辦法在不修改原有代碼的前提下將其移植到容器中了, 此外這些解決方案都是用戶態(tài)實現(xiàn), 每次信息請求都會導(dǎo)致多次上下文的切換和系統(tǒng)調(diào)用開銷效率低下. 因此本文提出了一種基于LKM技術(shù)的Docker資源信息隔離方法.
1.1 LKM技術(shù)
LKM[9]是動態(tài)擴充內(nèi)核功能的一項技術(shù). 它使得Linux 操作系統(tǒng)內(nèi)核可以在運行狀態(tài)就能對功能進(jìn)行擴充. 當(dāng)編寫完一個LKM 程序, 用編譯器將其編譯為目標(biāo)文件,然后就可以根據(jù)需要動態(tài)的進(jìn)行加載, 在不需要其所提供的功能時卸載它. 在LKM 程序編寫和編譯的過程中無須對內(nèi)核進(jìn)行重新編譯.
使用LKM技術(shù)的另一個優(yōu)點在于對于所有的Docker容器都是同效的, 不需要單獨為每一個容器進(jìn)行設(shè)置, 因為Docker本身就是一種輕量級的虛擬化技術(shù), 所有的容器共用同一個內(nèi)核, 因此一個內(nèi)核模塊會對所有的容器產(chǎn)生作用.
1.2 cgroups資源控制機制
Cgroups(Control groups)是Linux內(nèi)核提供的一種可以限制, 記錄, 隔離進(jìn)程組所使用的物理資源的機制, 是由google工程師提出, 其初衷是為了管理和控制系統(tǒng)資源. Cgroups也是LXC[8]為實現(xiàn)虛擬化所使用的資源管理手段[10]. Docker也是利用了Cgroups這一機制實現(xiàn)了容器的資源管理, Cgroups包含了九個子系統(tǒng), 每一個子系統(tǒng)負(fù)責(zé)管理一種資源.
Linux內(nèi)核為了表示子系統(tǒng), 給每一個子系統(tǒng)都設(shè)計一個結(jié)構(gòu)體, 例如內(nèi)存子系統(tǒng), 在內(nèi)核中就有一個對應(yīng)的結(jié)構(gòu)體叫做mem_cgroup, 這個結(jié)構(gòu)體負(fù)責(zé)管理這個子系統(tǒng)對應(yīng)的cgroup的內(nèi)存資源使用信息. 因此如果要獲取一個進(jìn)程所使用的內(nèi)存資源信息必須要獲得該進(jìn)程對應(yīng)的mem_cgroup. 內(nèi)核中提供了大量的接口, 可以很方便的通過進(jìn)程的task_struct結(jié)構(gòu)體得到這個進(jìn)程所對應(yīng)的mem_cgroup結(jié)構(gòu)體.
2.1 設(shè)計概述
本文提出的資源信息隔離方法主要由系統(tǒng)調(diào)用截獲層、資源信息獲取層、procfs內(nèi)容覆寫層, 三層組成,其架構(gòu)模型如圖1所示.
圖1 資源信息隔離架構(gòu)模型圖
該設(shè)計框圖中, 系統(tǒng)調(diào)用截獲層屏蔽了上層的多種資源信息 獲取方式所帶來的差異, 資源信息獲取層通過Linux Kernel提供的資源信息接口, 得到發(fā)起資源信息請求的進(jìn)程所對應(yīng)的控制組的資源信息. procfs內(nèi)容覆寫層通過修改procfs內(nèi)容輸出的接口從而將正確的資源信息輸出.
2.2 分層設(shè)計
系統(tǒng)調(diào)用截獲層: 該層分為兩個部分, 第一個部分是判斷發(fā)起的請求是否是一個資源獲取的請求, 用戶可能只是訪問一個普通的文件或者一個設(shè)備而已,因此需要根據(jù)請求的路徑是否是/proc/meminfo來判定是否是資源獲取請求, 第二個部分是通過修改系統(tǒng)調(diào)用表sys_call_table將sys_read替換為本文的docker_read, 無論上層應(yīng)用是通過系統(tǒng)命令還是函數(shù)接口的方式來獲取資源信息, 其最終都會去調(diào)用內(nèi)核中的sys_read來獲取資源數(shù)據(jù). 系統(tǒng)調(diào)用截獲層通過LKM技術(shù)將sys_read進(jìn)行了截獲, 并替換為本文實現(xiàn)的docker_read, 從而成功將資源信息獲取的邏輯陷入到本文提出的資源信息隔離邏輯中.
資源信息獲取層: 該層主要包含兩個部分的功能,第一個部分是判斷發(fā)起資源請求的進(jìn)程是否使用了Cgroups限制其資源, 第二個部分則是通過Cgroups在內(nèi)核中提供的資源信息獲取接口, 得到發(fā)起資源請求的進(jìn)程所在控制組的資源信息結(jié)構(gòu)體, 該結(jié)構(gòu)體中包含了該進(jìn)程所在控制組中的資源信息.
procfs內(nèi)容覆寫層: procfs本身是一種內(nèi)存文件系統(tǒng), Linux內(nèi)核通過seq_file機制[11]給procfs中的文件設(shè)置了callback函數(shù), 當(dāng)開始讀取procfs文件中的內(nèi)容時會自動觸發(fā)callback函數(shù)填充文件內(nèi)容. procfs內(nèi)容覆寫層通過資源信息獲取層得到的控制組資源信息重新實現(xiàn)了callback函數(shù), 并進(jìn)行了注冊.
3.1 資源信息隔離實現(xiàn)
為了驗證本文提出的資源信息隔離方法的正確性,根據(jù)給出的架構(gòu)模型設(shè)計并實現(xiàn)了一個詳細(xì)的資源信息隔離系統(tǒng), 如圖2所示.
圖2 資源信息隔離系統(tǒng)架構(gòu)圖
該系統(tǒng)架構(gòu)圖中, 系統(tǒng)調(diào)用截獲層通過對上層應(yīng)用最終調(diào)用的sys_read進(jìn)行劫持, 進(jìn)而可以通過請求類型分析模塊, 根據(jù)請求的文件路徑是否是/proc/meminfo來判定此次請求是否是一個資源信息請求, 在判定是一個資源信息請求后就交由資源信息獲取層來處理, 在這層中通過資源限制分析模塊判定當(dāng)前發(fā)起資源信息請求的進(jìn)程是否使用了Cgroups限制其資源信息, 對于沒有使用Cgroups進(jìn)程是不做處理的, 接著會使用資源信息獲取模塊來獲取當(dāng)前進(jìn)程所在控制組的資源信息. 最后將這個進(jìn)程的資源信息交給procfs內(nèi)容覆寫層, 在這層中會通過內(nèi)容覆寫模塊將進(jìn)程的資源信息輸出到/proc/meminfo文件中.
3.2 處理流程
本文所實現(xiàn)的資源信息隔離方法的請求處理流程如圖3所示.
圖3所示的資源信息隔離方法的執(zhí)行流程描述如下:
(1) 應(yīng)用程序發(fā)起資源信息獲取的請求, 通過glibc庫最終陷入內(nèi)核, 調(diào)用sys_read.
圖3 系統(tǒng)處理流程
(2) 系統(tǒng)調(diào)用截獲層接受并處理資源信息請求.
a) 請求未到達(dá)前修改內(nèi)核系統(tǒng)調(diào)用表sys_call_table, 替換sys_read.
b) 判定資源請求是否是對/proc/meninfo的訪問.
(3) 資源信息獲取層接收合法的資源信息請求.
a) 獲取當(dāng)前進(jìn)程的cgroup信息, 判斷是否存在cgroups資源限制.
b) 獲取當(dāng)前進(jìn)程的資源信息.
(4) procfs內(nèi)容覆寫層接收當(dāng)前進(jìn)程所在控制組的資源信息.
a) 根據(jù)資源信息生成meminfo文件內(nèi)容.
b) 輸出到/proc/meminfo文件.
4.1 實驗環(huán)境
為了驗證本文所提的基于LKM的Docker資源信息隔離方法, 設(shè)置了如下的實驗環(huán)境.
表1 實驗環(huán)境和工具
4.2 試驗方法
為了測試該方法的正確性和可用性, 筆者首先和業(yè)界現(xiàn)有解決方案在功能上和性能上做了對比, 在功能上主要對比以下三個功能點:
功能點1: 是否可以獲取容器的真實內(nèi)存信息.
功能點2: 是否改動軟件的資源信息獲取接口.
功能點3: 是否需要單獨對每個容器進(jìn)行設(shè)置.在性能上主要通過對比各個解決方案在1W, 10W, 100W次的資源信息請求下所耗費的時間.
最后通過下面的方案來測試本文所提出的方法的正確性. 啟動一個nginx容器, 并限制這個容器可以使用的最大內(nèi)存為512M. 通過以下兩種方案進(jìn)行測試.
方案1: 使用cat, free, vmstat, top等Linux標(biāo)準(zhǔn)命令查看容器內(nèi)存資源信息.
方案2: 使用筆者編寫的文件讀取工具查看容器內(nèi)存資源信息.
方案3: 不使用本文所采用的方法, 通過procfs文件系統(tǒng)來查看容器內(nèi)存資源信息.
最后通過對比查看到的內(nèi)存資源信息和通過cgroups限制的內(nèi)存資源信息是否相同.
4.3 實驗結(jié)果
分別對lxcfs, Docker API, 以及DRISO(Docker Resource Information Isolation )即本文所提出的方法進(jìn)行功能上的對比, 對比結(jié)果如表2所示.
表2 功能對比
通過上面的結(jié)果可知, 本文所提出的DRISO在功能上要比現(xiàn)有的解決方案更加完善.
為了證明本文所提出的方法在實際生產(chǎn)環(huán)境下可用, 對上述幾個解決方案做了性能上的對比, 測試結(jié)果如表3所示.
表3 性能測試
通過上面的結(jié)果可知, 在不是用任何方法的情況下性能是最好的, 本文所使用的DRISO方法性能次之, Docker API的方式性能最差, 因為該方式每次資源信息請求都是一次完整的HTTP請求和響應(yīng), 這其中涉及了大量的操作, 而本文的DRISO方法, 卻只有僅僅幾次系統(tǒng)調(diào)用和數(shù)據(jù)從內(nèi)核空間拷貝到用戶空間的開銷, lxcfs性能較好, 因為lxcfs是基于文件接口的形式來獲取資源信息, 和procfs一樣也是一個文件系統(tǒng),但是因為其是基于FUSE的用戶態(tài)文件系統(tǒng), 這導(dǎo)致大量的數(shù)據(jù)拷貝操作, 和上下文切換的開銷, 因此性能差于本文所提出的DRISO方法.
通過加載本文實現(xiàn)的LKM模塊使得容器可以通過Linux標(biāo)準(zhǔn)命令來獲取限制的內(nèi)存資源信息, 如圖4所示.
圖4 資源信息隔離前后對比圖
上圖中首先使用docker運行了一個nginx容器,并通過-m選項限制這個容器的最大可用內(nèi)存為512M,然后運行free命令查看這個容器的可用內(nèi)存信息, 通過結(jié)果可以得知查看到的內(nèi)存資源信息是宿主機的資源信息, 接著通過插入本文所編寫的資源隔離內(nèi)核模塊后, 再次運行相同的nginx容器并使用free命令查看容器內(nèi)存資源信息, 發(fā)現(xiàn)內(nèi)存資源信息有效的進(jìn)行了隔離.
為了驗證本文提出的基于LKM的Docker資源信息隔離方法在不同的資源獲取方式下都可以正確工作,分別通過Linux標(biāo)準(zhǔn)命令和筆者利用read系統(tǒng)調(diào)用編寫的文件讀取工具進(jìn)行了測試, 方案1和方案2, 3的測試結(jié)果如表4所示.
表4 測試結(jié)果
綜合上面所有的測試結(jié)果可知, 本文提出的DRISO方法是正確的, 并且是實際生產(chǎn)環(huán)境下可用的.
本文主要介紹了Linux中的Cgroups機制, 并在此基礎(chǔ)上基于LKM的技術(shù)實現(xiàn)了Docker的資源信息隔離. 通過實驗證明了其正確性. 隨著Docker容器技術(shù)的快速發(fā)展, 容器的安全性[12]和隔離性[13]越來越重要,這對如何在Linux操作系統(tǒng)層面加強對容器安全性和隔離性的支持提出了更高的要求.
1 Pahl C. Containerization and the PaaS cloud. IEEE Cloud Computing, 2015, (3): 24–31.
2 Felter W, Ferreira A, Rajamony R, et al. An updated performance comparison of virtual machines and linux containers. 2015 IEEE International Symposium on Performance Analysis of Systems and Software (ISPASS). IEEE. 2015. 171–172.
3 Joy AM. Performance comparison between Linux containers and virtual machines. 2015 International Conference on Advances in Computer Engineering and Applications (ICACEA). IEEE. 2015. 342–346.
4 Scheepers MJ. Virtualization and containerization of application infrastructure: A comparison. 21st Twente Student Conference on IT. 2014. 1–7.
5 Menage P. Linux Kernel Documentation/cgroups/cgroups.txt. 2011.
6 Bowden T, Bauer B, Nerin J, et al. The/proc filesystem. Linux Kernel Documentation, 2000.
7 趙付強,李允俊,宮彥磊. Proc文件系統(tǒng)的研究與應(yīng)用.計算機系統(tǒng)應(yīng)用,2013,22(1):87–90.
8 Graber S, Hallyn S. LXC Linux Containers. https:// linuxcontainers.org. [2013-05-15].
9 徐偉,賈春福.擴充Linux系統(tǒng)功能的LKM技術(shù).計算機應(yīng)用研究,2003,4:100–102.
10 汪愷,張功萱,周秀敏.基于容器虛擬化技術(shù)研究.計算機技術(shù)與發(fā)展,2015,8:138–141.
11 郭松,謝維波.Linux下Proc文件系統(tǒng)的編程剖析.華僑大學(xué)學(xué)報(自然科學(xué)版),2010,5:515–520.
12 Bui T. Analysis of docker security. arXiv preprint arXiv:1501.02967, 2015.
13 劉思堯,李強,李斌.基于Docker技術(shù)的容器隔離性研究.軟件,2015,4:110.
Docker Resource Information Isolation Method Based on LKM
CHEN Li-Jun, ZHANG Yi-Fei
(School of Computer Science, Xi’an University of Posts and Telecommunications, Xi’an 710121, China)
In view of the problem that the memory resource information in Docker container is not isolated, we design a resource information isolation method based on LKM technology. The method in the form of LKM uses system to call hijacking to modify the reading of the procfs file content, so as to realize the function of the Docker container resources information isolation, on which the containers run without any modification can achieve the purpose of resource information isolation. The experiments prove that the resource information isolation function is available.
LKM; Docker; procfs; container; isolation
2016-04-11;收到修改稿時間:2016-05-23
10.15888/j.cnki.csa.005536