陳莉君, 張義飛
(西安郵電大學 計算機學院, 西安710121)
基于LKM的Docker資源信息隔離方法①
陳莉君, 張義飛
(西安郵電大學 計算機學院, 西安710121)
針對Docker容器目前存在的內存資源信息尚未隔離的問題, 設計了一種基于LKM技術的資源信息隔離方法. 該方法通過LKM的形式利用系統調用劫持來修改讀取到的procfs文件內容, 從而實現了Docker中的容器資源信息隔離的功能, 使得在其上運行的容器可以不用作任何修改就能達到資源信息隔離的目的. 最后通過實驗證明資源信息隔離的功能是可用的.
LKM; Docker; procfs; 容器; 隔離
隨著云計算的普及, 人們對應用的多樣化需求促使PaaS[1]技術的快速發展, 其中云應用的隔離性和資源控制顯得尤為重要. 傳統云應用的隔離性和資源控制是通過使用虛擬機來實現的, 但是部署在虛擬機中的應用會因為需要經過傳統虛擬化技術提供的一個抽象層從而導致應用性能的下降, 在云環境下, 這將會導致基礎設施層有效率損失[2-4]. 基于容器的虛擬化技術可以簡化應用的部署, 并通過Linux內核提供的特性來實現隔離和資源控制, 不需要經過額外的抽象層,所以在效率上要高于傳統的虛擬化技術[2]. 通過隔離可以在單一操作系統上運行多個實例, 實例之間彼此互不影響, 通過資源控制則可以將實例限制在一個資源集合中運行. Docker充分利用了Linux內核提供的Namespace和Cgroups特性. 但是目前Linux內核提供的Namespace特性還不夠完善[5], 對于procfs[6,7]文件系統的隔離還沒有完全實現, 這導致系統資源信息沒有隔離. 容器中的進程通過查看procfs文件系統內容或者使用free等基于procfs文件系統的命令查看系統資源信息的時候獲取到的信息都是宿主機的資源信息,并不是容器本身的資源信息. 一方面對于容器的使用者來說會得到不正確的結果給用戶造成困擾, 另一方面對于一些需要獲取系統資源信息的軟件來說會導致其獲取不到正確的資源信息, 例如監控軟件的agent端.
目前對于Docker的資源信息尚未隔離的問題, 業界也有一些解決方案, 但是都必須通過修改程序獲取資源信息的接口來解決. 例如lxcfs[8], Docker API. 對于一些依賴于procfs文件系統來獲取資源信息的軟件來說, 必須修改其資源信息獲取接口才能在容器中正常運行以獲得正確的資源信息. 沒有辦法在不修改原有代碼的前提下將其移植到容器中了, 此外這些解決方案都是用戶態實現, 每次信息請求都會導致多次上下文的切換和系統調用開銷效率低下. 因此本文提出了一種基于LKM技術的Docker資源信息隔離方法.
1.1 LKM技術
LKM[9]是動態擴充內核功能的一項技術. 它使得Linux 操作系統內核可以在運行狀態就能對功能進行擴充. 當編寫完一個LKM 程序, 用編譯器將其編譯為目標文件,然后就可以根據需要動態的進行加載, 在不需要其所提供的功能時卸載它. 在LKM 程序編寫和編譯的過程中無須對內核進行重新編譯.
使用LKM技術的另一個優點在于對于所有的Docker容器都是同效的, 不需要單獨為每一個容器進行設置, 因為Docker本身就是一種輕量級的虛擬化技術, 所有的容器共用同一個內核, 因此一個內核模塊會對所有的容器產生作用.
1.2 cgroups資源控制機制
Cgroups(Control groups)是Linux內核提供的一種可以限制, 記錄, 隔離進程組所使用的物理資源的機制, 是由google工程師提出, 其初衷是為了管理和控制系統資源. Cgroups也是LXC[8]為實現虛擬化所使用的資源管理手段[10]. Docker也是利用了Cgroups這一機制實現了容器的資源管理, Cgroups包含了九個子系統, 每一個子系統負責管理一種資源.
Linux內核為了表示子系統, 給每一個子系統都設計一個結構體, 例如內存子系統, 在內核中就有一個對應的結構體叫做mem_cgroup, 這個結構體負責管理這個子系統對應的cgroup的內存資源使用信息. 因此如果要獲取一個進程所使用的內存資源信息必須要獲得該進程對應的mem_cgroup. 內核中提供了大量的接口, 可以很方便的通過進程的task_struct結構體得到這個進程所對應的mem_cgroup結構體.
2.1 設計概述
本文提出的資源信息隔離方法主要由系統調用截獲層、資源信息獲取層、procfs內容覆寫層, 三層組成,其架構模型如圖1所示.

圖1 資源信息隔離架構模型圖
該設計框圖中, 系統調用截獲層屏蔽了上層的多種資源信息 獲取方式所帶來的差異, 資源信息獲取層通過Linux Kernel提供的資源信息接口, 得到發起資源信息請求的進程所對應的控制組的資源信息. procfs內容覆寫層通過修改procfs內容輸出的接口從而將正確的資源信息輸出.
2.2 分層設計
系統調用截獲層: 該層分為兩個部分, 第一個部分是判斷發起的請求是否是一個資源獲取的請求, 用戶可能只是訪問一個普通的文件或者一個設備而已,因此需要根據請求的路徑是否是/proc/meminfo來判定是否是資源獲取請求, 第二個部分是通過修改系統調用表sys_call_table將sys_read替換為本文的docker_read, 無論上層應用是通過系統命令還是函數接口的方式來獲取資源信息, 其最終都會去調用內核中的sys_read來獲取資源數據. 系統調用截獲層通過LKM技術將sys_read進行了截獲, 并替換為本文實現的docker_read, 從而成功將資源信息獲取的邏輯陷入到本文提出的資源信息隔離邏輯中.
資源信息獲取層: 該層主要包含兩個部分的功能,第一個部分是判斷發起資源請求的進程是否使用了Cgroups限制其資源, 第二個部分則是通過Cgroups在內核中提供的資源信息獲取接口, 得到發起資源請求的進程所在控制組的資源信息結構體, 該結構體中包含了該進程所在控制組中的資源信息.
procfs內容覆寫層: procfs本身是一種內存文件系統, Linux內核通過seq_file機制[11]給procfs中的文件設置了callback函數, 當開始讀取procfs文件中的內容時會自動觸發callback函數填充文件內容. procfs內容覆寫層通過資源信息獲取層得到的控制組資源信息重新實現了callback函數, 并進行了注冊.
3.1 資源信息隔離實現
為了驗證本文提出的資源信息隔離方法的正確性,根據給出的架構模型設計并實現了一個詳細的資源信息隔離系統, 如圖2所示.

圖2 資源信息隔離系統架構圖
該系統架構圖中, 系統調用截獲層通過對上層應用最終調用的sys_read進行劫持, 進而可以通過請求類型分析模塊, 根據請求的文件路徑是否是/proc/meminfo來判定此次請求是否是一個資源信息請求, 在判定是一個資源信息請求后就交由資源信息獲取層來處理, 在這層中通過資源限制分析模塊判定當前發起資源信息請求的進程是否使用了Cgroups限制其資源信息, 對于沒有使用Cgroups進程是不做處理的, 接著會使用資源信息獲取模塊來獲取當前進程所在控制組的資源信息. 最后將這個進程的資源信息交給procfs內容覆寫層, 在這層中會通過內容覆寫模塊將進程的資源信息輸出到/proc/meminfo文件中.
3.2 處理流程
本文所實現的資源信息隔離方法的請求處理流程如圖3所示.
圖3所示的資源信息隔離方法的執行流程描述如下:
(1) 應用程序發起資源信息獲取的請求, 通過glibc庫最終陷入內核, 調用sys_read.

圖3 系統處理流程
(2) 系統調用截獲層接受并處理資源信息請求.
a) 請求未到達前修改內核系統調用表sys_call_table, 替換sys_read.
b) 判定資源請求是否是對/proc/meninfo的訪問.
(3) 資源信息獲取層接收合法的資源信息請求.
a) 獲取當前進程的cgroup信息, 判斷是否存在cgroups資源限制.
b) 獲取當前進程的資源信息.
(4) procfs內容覆寫層接收當前進程所在控制組的資源信息.
a) 根據資源信息生成meminfo文件內容.
b) 輸出到/proc/meminfo文件.
4.1 實驗環境
為了驗證本文所提的基于LKM的Docker資源信息隔離方法, 設置了如下的實驗環境.

表1 實驗環境和工具
4.2 試驗方法
為了測試該方法的正確性和可用性, 筆者首先和業界現有解決方案在功能上和性能上做了對比, 在功能上主要對比以下三個功能點:
功能點1: 是否可以獲取容器的真實內存信息.
功能點2: 是否改動軟件的資源信息獲取接口.
功能點3: 是否需要單獨對每個容器進行設置.在性能上主要通過對比各個解決方案在1W, 10W, 100W次的資源信息請求下所耗費的時間.
最后通過下面的方案來測試本文所提出的方法的正確性. 啟動一個nginx容器, 并限制這個容器可以使用的最大內存為512M. 通過以下兩種方案進行測試.
方案1: 使用cat, free, vmstat, top等Linux標準命令查看容器內存資源信息.
方案2: 使用筆者編寫的文件讀取工具查看容器內存資源信息.
方案3: 不使用本文所采用的方法, 通過procfs文件系統來查看容器內存資源信息.
最后通過對比查看到的內存資源信息和通過cgroups限制的內存資源信息是否相同.
4.3 實驗結果
分別對lxcfs, Docker API, 以及DRISO(Docker Resource Information Isolation )即本文所提出的方法進行功能上的對比, 對比結果如表2所示.

表2 功能對比
通過上面的結果可知, 本文所提出的DRISO在功能上要比現有的解決方案更加完善.
為了證明本文所提出的方法在實際生產環境下可用, 對上述幾個解決方案做了性能上的對比, 測試結果如表3所示.

表3 性能測試
通過上面的結果可知, 在不是用任何方法的情況下性能是最好的, 本文所使用的DRISO方法性能次之, Docker API的方式性能最差, 因為該方式每次資源信息請求都是一次完整的HTTP請求和響應, 這其中涉及了大量的操作, 而本文的DRISO方法, 卻只有僅僅幾次系統調用和數據從內核空間拷貝到用戶空間的開銷, lxcfs性能較好, 因為lxcfs是基于文件接口的形式來獲取資源信息, 和procfs一樣也是一個文件系統,但是因為其是基于FUSE的用戶態文件系統, 這導致大量的數據拷貝操作, 和上下文切換的開銷, 因此性能差于本文所提出的DRISO方法.
通過加載本文實現的LKM模塊使得容器可以通過Linux標準命令來獲取限制的內存資源信息, 如圖4所示.

圖4 資源信息隔離前后對比圖
上圖中首先使用docker運行了一個nginx容器,并通過-m選項限制這個容器的最大可用內存為512M,然后運行free命令查看這個容器的可用內存信息, 通過結果可以得知查看到的內存資源信息是宿主機的資源信息, 接著通過插入本文所編寫的資源隔離內核模塊后, 再次運行相同的nginx容器并使用free命令查看容器內存資源信息, 發現內存資源信息有效的進行了隔離.
為了驗證本文提出的基于LKM的Docker資源信息隔離方法在不同的資源獲取方式下都可以正確工作,分別通過Linux標準命令和筆者利用read系統調用編寫的文件讀取工具進行了測試, 方案1和方案2, 3的測試結果如表4所示.

表4 測試結果
綜合上面所有的測試結果可知, 本文提出的DRISO方法是正確的, 并且是實際生產環境下可用的.
本文主要介紹了Linux中的Cgroups機制, 并在此基礎上基于LKM的技術實現了Docker的資源信息隔離. 通過實驗證明了其正確性. 隨著Docker容器技術的快速發展, 容器的安全性[12]和隔離性[13]越來越重要,這對如何在Linux操作系統層面加強對容器安全性和隔離性的支持提出了更高的要求.
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文件系統的研究與應用.計算機系統應用,2013,22(1):87–90.
8 Graber S, Hallyn S. LXC Linux Containers. https:// linuxcontainers.org. [2013-05-15].
9 徐偉,賈春福.擴充Linux系統功能的LKM技術.計算機應用研究,2003,4:100–102.
10 汪愷,張功萱,周秀敏.基于容器虛擬化技術研究.計算機技術與發展,2015,8:138–141.
11 郭松,謝維波.Linux下Proc文件系統的編程剖析.華僑大學學報(自然科學版),2010,5:515–520.
12 Bui T. Analysis of docker security. arXiv preprint arXiv:1501.02967, 2015.
13 劉思堯,李強,李斌.基于Docker技術的容器隔離性研究.軟件,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