[牛思杰 潘碧瑩 龐濤]
容器技術是一種輕量級、可移植、自包含的軟件打包技術,使應用程序可以在幾乎任何地方以相同的方式運行,現(xiàn)階段已經發(fā)展成為應用分發(fā)和交付的標準技術。
隨著移動通信技術發(fā)展到5G 時代,容器技術助力云邊計算一體化,實現(xiàn)了云端和邊緣端的業(yè)務靈活編排,任務靈活調度,資源按需分配,但終端的發(fā)展還是垂直煙囪式、碎片化的現(xiàn)狀,終端和邊云不能按需進行任務的動態(tài)分配和資源的靈活共享,并且很難實現(xiàn)不同終端之間的資源共享。受限于終端相對緊缺的硬件資源以及各種終端之間硬件架構的差異,目前云端以及邊緣端上廣泛應用的容器技術棧無法很好地運行在各種類型的終端上。因此,終端側亟需一次技術革新,借鑒云端容器技術,研發(fā)可通用在各種異構終端上的輕量化容器技術,推動終端的虛擬化改造,以滿足云網融合的戰(zhàn)略機遇下端邊云網一體化的發(fā)展需求。
本文將通過研究對比目前業(yè)界的主流容器技術,結合終端容器的特點和需求,總結終端輕量化容器技術的發(fā)展方向。文中第2 節(jié)將介紹本次研究評測的背景,包括容器技術的發(fā)展現(xiàn)狀、目前業(yè)界4 種主流容器引擎即Docker、Containerd、iSulad 和balenaEngine 的技術特點,以及相關文獻中工作的梳理與借鑒。第3 節(jié)中將介紹本次測試的測試指標、工具和測試環(huán)境。第4 節(jié)中將展示本次測試的測試結果,并針對結果數據進行研究評測。第5 節(jié)中將給出本次測試的測試結論。第6 節(jié)中進行總結并展望未來終端輕量化容器技術的發(fā)展方向。
容器技術的概念可以追溯到1979 年的Unix Chroot,Chroot 為每個進程提供一套隔離化磁盤空間,進而虛擬化進程文件目錄,不能夠防止進程惡意訪問系統(tǒng)。2000 年提出Freebsd Jail技術,包含有進程沙箱機制以對文件系統(tǒng)、用戶及網絡等資源進行隔離,實現(xiàn)了操作系統(tǒng)級別的虛擬化,然而這種簡單性的隔離影響Jails 中應用訪問系統(tǒng)資源的靈活性[1]。2004 年出現(xiàn)了專為X86 和SPARC 系統(tǒng)設計的虛擬化技術Solaris Zone,該技術真正的引入了容器資源管理的概念。Solaris 容器是系統(tǒng)資源控制和通過 "區(qū)域" 提供邊界隔離的組合,Solaris Zone 技術讓應用在隔離的Zone 中運行,并實現(xiàn)有效的資源管理,每一個Zone 擁有自己的文件系統(tǒng),進程空間,防火墻,網絡配置等[2]。2008 年提出的LXC(Linux Containers)通過Namespaces和Cgroups 實現(xiàn)容器的隔離和資源控制,將容器支持集成到主流Linux 內核,允許使用單個Linux 內核在宿主機上運行多個獨立的系統(tǒng)[3]。隨著容器技術的發(fā)展,在原版Linux 內核上運行容器已經成為行業(yè)共識,容器技術因其特有的優(yōu)勢也在不同領域和設備中廣泛應用,如云平臺的Docker 和Containerd、嵌入式設備的Belena、資源受限端側設備的isulad,也在虛擬化技術中發(fā)揮著關鍵作用。
容器位于物理服務器及其主機操作系統(tǒng)之上,將應用所需的軟件和依賴項目打包成標準化單元,以用于開發(fā)、交付和部署。容器具有如下特點:
隔離性:容器底層運用Namespaces 和Cgroups 技術實現(xiàn)容器進程對外界的隔離,即在單一主機上安全的運行多個應用,其中的每個應用都有自己的隔離環(huán)境。
高效性:容器對操作系統(tǒng)進行抽象,每個容器只包括應用程序與必要的依賴資源,共享操作系統(tǒng)內核,因此占用空間小,能夠快速啟動和遷移。
可移植:容器消除了開發(fā)、測試、生產環(huán)境的不一致性,容器應用可以被移植到其它宿主機器中,為開發(fā)和運維提供標準化的解決方案。
2.1.1 Docker
Docker 是一個開源的應用容器引擎,基于Go 語言開發(fā)并遵循了Apache2.0 協(xié)議開源。Docker 可以讓開發(fā)者將應用和依賴包打包到一個輕量級、可移植的容器中,發(fā)布到任何流行的Linux 服務器[4]。
Docker 首次發(fā)布時由兩個核心組件構成:Docker daemon 和LXC(Linux Container)。Docker daemon 是單一的二進制文件,包含諸如Docker 客戶端、Docker API、容器運行時、鏡像構建等;LXC 提供了對諸如命名空間(Namespaces)和控制組(Cgroups)等基礎工具的操作能力[5,6]。Docker daemon、LXC 和操作系統(tǒng)之間的交互關系如圖1 所示。
圖1 Docker 調用鏈示意圖
隨著時間的推移,Docker 公司也在不斷完善Docker 的功能。Docker 公司開發(fā)了與平臺無關的工具Libcontainer,將容器引擎的底層實現(xiàn)抽象化到Libcontainer 接口,只要實現(xiàn)了Libcontainer 定義的一組接口,Docker 就可以運行,進而實現(xiàn)基于不同內核為Docker 上層提供必要的容器交互的功能。在Docker 0.9 版本中,Libcontainer 取代LXC成為Docker 默認的執(zhí)行驅動。2015 年,Docker 公司將Libcontainer 捐給一個完全中立的基金會管理,并改名為runC。功能完備的Docker daemon 使得Docker 難于變更、運行越來越慢,不利于Docker 生態(tài)的發(fā)展,因此Docker公司開始著手模塊化Docker daemon 進程,拆解出其中的功能特性,重構為小而專的工具來實現(xiàn)這些功能。
2.1.2 Containerd
2016 年,Docker 把負責容器生命周期的模塊拆分出來捐贈給CNCF 社區(qū),這便是Containerd 的前身,后社區(qū)為其添加了鏡像管理模塊和CRI 模塊,使得Containerd具備支持kubelet 創(chuàng)建Pod 所需的全部功能。2019 年2 月Containerd 從CNCF 社區(qū)畢業(yè),進入生產環(huán)境作為容器運行時使用。Containerd 項目源自Docker,在集成Docker 特性的基礎上,也進行了功能優(yōu)化,通過將image、filesystem、runtime 解耦合,實現(xiàn)插件式的拓展和重用。Containerd 支持OCI 和CRI 規(guī)范,可以與低級運行時(runC)和容器編排工具(如Kubernetes)交互,不需Docker-shim 的參與,簡化了管理容器生命周期的調用鏈,便于Kubernetes 項目的維護工作[7]。
目前,Containerd 已經成為了一個工業(yè)級容器技術了,采用標準的C/S 架構,服務端通過GRPC 協(xié)議提供穩(wěn)定的 API,客戶端通過調用服務端的API 進行高級的操作。開發(fā)人員或者終端用戶可以在宿主機中管理完整的容器生命周期,包括容器鏡像的傳輸和存儲、容器的執(zhí)行和管理、存儲和網絡等。在容器技術逐步標準化后,Containerd 在相關的技術棧中將占據非常重要的地位,Containerd 提供的核心服務將成為底層管理容器的標準。屆時,更上層的容器化應用平臺將直接使用Containerd 提供的基礎服務。在開源社區(qū)方面,Containerd 一直保持很活躍的狀態(tài),這個項目的成熟離不開社區(qū)廣大contributors 的貢獻。
2.1.3 iSulad
iSula是華為開源的一種云原生輕量級容器解決方案,可通過統(tǒng)一、靈活的架構滿足ICT 領域端、邊、云場景的多種需求[8]。iSulad 是iSula 技術鏈中的通用容器引擎,它提供統(tǒng)一的架構設計來滿足CT 和IT 領域的不同需求。相比Golang 編寫的Docker,iSulad 基于C/C++編寫,具有輕、靈、巧、快的特點,不受硬件規(guī)格和架構的限制,底噪開銷更小,可應用領域更為廣泛。iSulad 作為輕量化的容器底座,可以為多種場景提供靈活、穩(wěn)定、安全的底層支撐。
架構設計上,除了啟動容器部分需要通過fork/exec的方式,其他部分均使用調用函數庫的方式加快執(zhí)行速度;通過將鏡像和rootfs 部分獨立為服務,以及優(yōu)化鏡像模塊元數據的隔離性,實現(xiàn)了不同鏡像和rootfs 之間的操作完全隔離。
由于iSulad 資源占用較低,對容器引擎占用資源限制要求比較高的場景,如CT、嵌入式、邊緣側等,可以使用iSulad 容器引擎。iSulad 支持北向CRI 標準接口,可應用于對接Kubernetes 實現(xiàn)容器的編排管理。此外,iSulad 除了支持運行普通容器,還支持運行系統(tǒng)容器、安全容器滿足用戶不同應用場景下的需求。
2.1.4 balenaEngine
balenaEngine 是Balena.io 公司推出的一款與Docker兼容的用于嵌入式設備上的容器引擎,專門針對嵌入式和IoT 用例而構建,并且與Docker 容器兼容[9]。balenaEngine 基于Docker 的Moby Project,支持容器增量,二進制文件更小,更保守地使用RAM 和存儲,并專注于容器抽取的原子性和持久性。
與Docker 相比,balenaEngine 具備以下特點:①支持容器鏡像的增量拉取,節(jié)省10x~70x 的下載帶寬。②容器鏡像可以中斷后重新拉取。這意味著,當嵌入式設備掉電再重新上電時,容器鏡像可以繼續(xù)拉取。③容器執(zhí)行文件體積是Docker 執(zhí)行文件體積的2/7 左右。④改進了鏡像拉取使用頁面緩存的機制,避免在低內存的嵌入式設備下出現(xiàn)頁面緩存抖動。⑤去除了Docker 幾個不適用于嵌入式場景下的功能,例如Docker Swarm,插件支持,云端日志系統(tǒng),overlay 網絡驅動等。⑥只支持Linux 系統(tǒng)。
關于終端容器技術研究與評測的文獻很少,大多數相關的研究只對容器在基于X86 架構的服務器上運行時的各項性能指標進行了部分的研究對比。
通過前期的調查研究,文獻[10]中對比了Containerd和crio 在,runC 和gvisor 的底層runtime 下,10/20*run 命令下,CPU、MEM、Disk I/O 的性能對比。文獻[11]中測試了不同容器引擎在串行和并行情況下創(chuàng)建、啟動、停止、刪除等容器生命周期操作下的耗時。[12]中使用cAdvisor和mpstat 測試容器運行產生的CPU 負載,使用docker stats 測試容器中運行線程請求的CPU 資源,使用iostat 工具監(jiān)測系統(tǒng)磁盤I/O。[13]中介紹了在docker 與KVM 中運行程序的性能對比,對比的主要性能指標為系統(tǒng)boot 時間和其中進行CPU 運算的速度,在兩項指標中docker 均明顯優(yōu)于KVM。[14]中針對CPU、內存、磁盤I/O、請求負載、處理速度等方面對docker 和虛擬機進行了性能對比,測試中使用了Sysbench,Phoronix,和apache benchmarking 等測試工具。[15]對資源相對受限的移動邊緣計算環(huán)境下進行了研究,發(fā)現(xiàn)無論容器化進程的CPU 周期消耗如何,Docker 進程的CPU 使用是恒定的。文獻[16]中提出針對CPU 和I/O 密集型任務負載對Docker 進行了基準測試,結果顯示了當容器生命周期結束時,Docker 引擎的資源開銷從10%減少至5%。[17]中的試驗將Docker 與Flockport容器(基于LXC 的一款開源容器)進行了比較,結果顯示,對于這兩種容器實現(xiàn),I/O 和系統(tǒng)調用是造成性能開銷的主要原因,Docker 的內存性能略優(yōu)于Flockport。[18][19]中多個測試維度對比了虛擬化技術和容器技術的系統(tǒng)資源開銷。
綜合考慮相關文獻中的測試方案以及終端設備的相關硬件指標,本次測試的測試指標項包括。
磁盤空間占用:對于很多的終端設備來說,磁盤空間都是很緊缺的資源,不同于云端以及邊緣端服務器動輒數以TB 的磁盤陣列,有些終端(例如攝像頭)上的磁盤空間只有數十MB,這意味著體積過大的容器引擎在終端上是行不通的。本次測試中使用ls 查看容器引擎二進制文件的尺寸大小。
內存占用:內存占用指的是此進程所開銷的內存,內存占用過大,會影響機器的整體性能。終端設備通常內存配置較低,所以要求容器引擎的內存占用要盡量減少。本次測試中使用free 命令查看容器引擎服務的系統(tǒng)內存占用情況。
容器生命周期操作耗時:容器的生命周期操作是指容器的創(chuàng)建、啟動、運行、停止和刪除等操作,其中運行操作可視為創(chuàng)建和啟動兩個操作順序執(zhí)行。容器生命周期各項操作的耗時是衡量容器引擎性能的重要指標,尤其在容器的批量操作時,細微的差距會被倍數的放大。本項測試的前置條件是使用docker 官方的busybox 鏡像且鏡像已提前拉取到本地,測試中使用shall 編寫腳本進行容器各項操作耗時的測試,并對單獨執(zhí)行一次操作以及并行執(zhí)行十次操作兩種情況進行分別測試。
CPU 使用率:CPU 使用率是系統(tǒng)性能監(jiān)測中最重要的性能指標之一。它是確定應用程序處理速度的主要分析值,而處理速度是網絡和服務器運行狀況的關鍵性能指標。終端設備通常CPU 算力配置較低,對容器引擎的CPU 使用有一定限制。本項測試的前置條件是使用docker 官方的busybox 鏡像且鏡像已提前拉取到本地,測試中使用sar工具查看容器生命周期操作中CPU 的實時使用率,并對單獨執(zhí)行一次操作以及并行執(zhí)行十次操作兩種情況進行分別測試。sar 是 sysstat 工具包的組成部分,可以收集并報告操作系統(tǒng)中廣泛的系統(tǒng)活動,包括CPU 使用率、上下文切換和中斷速率、頁換入和頁換出速率、共享內存使用情況、緩沖區(qū)使用情況以及網絡使用情況。
磁盤I/O 占用磁盤的輸入輸出。輸入指的是對磁盤寫入數據,輸出指的是從磁盤讀出數據。磁盤I/O 負載過高會造成數據阻塞,導致系統(tǒng)響應速度變慢。本項測試的前置條件是使用docker 官方的busybox 鏡像且鏡像已提前拉取到本地,測試中使用sar 工具查看容器生命周期操作中磁盤I/O 占用情況,并對單獨執(zhí)行一次操作以及并行執(zhí)行十次操作兩種情況進行分別測試。
本次測試的硬件環(huán)境基于樹莓派4B0,如圖2 所示。
圖2 樹莓派4B 嵌入式開發(fā)板樣式圖
主要配置情況如下。
處理器:Broadcom BCM2711 ARM V8 Cortex-A72 64 位1.5 GHZ 4 核處理器
內存:4G DDR4 內存
硬盤:16G 硬盤
本次測試的軟件環(huán)境如下:
操作系統(tǒng):CentOS 7.3.10
容器軟件版本:Docker 20.10.6,Containerd 1.4.4,iSulad 2.0.0,Balena-engine v17.12.0
4 種容器引擎的體積占用磁盤空間情況如圖3 所示,其中灰色的柱體表示各容器引擎軟件包總體大小,由于四種容器引擎均采用CS 架構設計,所以軟件包均包括服務器端和客戶端兩個二進制文件,除此之外,軟件包中還包含一些功能組件。
圖3 磁盤空間占用對比圖
從對比可以看出,使用C 語言編寫的iSulad 在服務器端以及客戶端體積上優(yōu)勢明顯,而Docker 作為目前在云端和邊緣端最廣泛運用的容器引擎,體積遠高于其他3種容器引擎。值得一提的是,balenaEngine 的服務器端和客戶端以及其他組件集成到了同一個二進制文件中,故其軟件包的體積即為服務器端的體積。Containerd 的軟件包總體大小為100 M 左右,對于目前的手機終端來說尚可接受,但是對于諸如攝像頭等一些資源受限的終端來說還是過于龐大。
4 種容器引擎啟動后進程的內存占用情況如圖4 所示,Docker 進程的內存占用超過120 M,對于很多中低配置的終端設備來說是沉重的負擔,這意味著無法保留足夠多的內存來保證容器內業(yè)務應用的運行。Containerd、iSulad 和balenaEngine 進程的內存占用情況相對較低,相對Docker 都減少了一半以上,分布在40~60 M 之間,其中Containerd 內存占用最少,為43.07 MB。以一個普通智能攝像頭的的配置為例,內存的配置為128 M,上述3種容器引擎的內存占用情況是在相對可以接受的范圍之內的。
圖4 進程內存占用對比圖
4 種容器引擎生命周期各項操作耗時情況如圖5、6所示,結果顯示,不管是在單次還是并行10 次執(zhí)行生命周期操作情況下,4 種容器引擎的性能優(yōu)劣順序是基本一致的。Docker 作為4 種容器引擎中體積最大、占用內存最多的一種,它的各項生命周期操作耗時也是最多的,單次運行容器耗時達到了1 201 ms,而該項最優(yōu)的Containerd耗時僅為303 ms。從測試結果中可以看出,Containerd和iSulad 的整體表現(xiàn)明顯優(yōu)于Docker 和balenaEngine,Containerd 在運行容器操作上最具優(yōu)勢,而iSulad 停止、刪除容器操作上略勝一籌。從整體而言,并行10 次的執(zhí)行耗時會比單次耗時的10 倍少30%~50%。
圖5 單次生命周期操作耗時對比圖
圖6 并發(fā)10 次生命周期操作耗時對比圖
4 種容器引擎生命周期各項操作的CPU 使用情況如圖7、圖8 所示。在單次執(zhí)行情況下,4 種容器引擎在容器的創(chuàng)建和運行兩種操作的耗時差距很大,Containerd 和iSulad 的表現(xiàn)明顯優(yōu)于Docker 和balenaEngine。而在容器的停止和停止方面,iSulad 和balenaEngine 具有一定優(yōu)勢。而在并發(fā)10 次執(zhí)行情況下,Docker 和balenaEngine 基本CPU 滿載,在測試的硬件環(huán)境下達到性能瓶頸,相比之下iSulad 的表現(xiàn)最好。
圖7 單次生命周期操作CPU 使用對比圖
圖8 并發(fā)10 次生命周期操作CPU 使用對比圖
4 種容器引擎生命周期各項操作的磁盤I/O 占用情況如圖9、圖10 所示。從執(zhí)行情況來看,在單次執(zhí)行情況下,除Docker 外,其他3 種容器引擎均低于20%,在并發(fā)10 次執(zhí)行的情況下,balenaEngine 各項操作的磁盤I/O占用飆升,成為了4 種容器引擎中最占用資源的一種,而Containerd 和iSulad 的表現(xiàn)基本和單次執(zhí)行的結果呈現(xiàn)倍數關系。值得注意的是,4 種容器引擎在容器的停止操作時的磁盤I/O 占用均趨近于[20],說明該過程中不涉及磁盤數據的讀寫。
圖9 單次生命周期操作磁盤I/O 占用對比圖
圖10 并發(fā)10 次生命周期操作磁盤I/O 占用對比圖
對于終端上的容器引擎來說,磁盤空間占用以及進程的內存占用首先需要考慮的,這決定了容器引擎是否可以成功運行。從磁盤空間占用比較來看,基于C 語言編寫的isulad 最為輕量,其他依次為balena-engine、Containerd和Docker,前三者相對較為輕量,在尺寸上基本滿足在終端設備上運行的需求。從運行占用內存方面比較,Containerd 整體來說占用內存最少,40 MB 左右的內存占用可以保留足夠多的內存來保證容器內業(yè)務應用的運行,對于終端設備來說是在可以接受的范圍之內的。從容器生命周期耗時比較來看,Containerd 和isulad 整體優(yōu)于其他兩種種容器引擎,但在容器啟動時間上Containerd 更具優(yōu)勢;從容器生命周期的CPU 使用率和磁盤I/O 占用方面比較,isulad 和Containerd 相對來說更符合容器輕量化的要求。整體來說除了Docker 外,其他3 種容器引擎方案均在一定程度上滿足了終端對于容器引擎輕量化的需求。
隨著容器技術的發(fā)展,Docker 容器引擎的地位受到眾多后起之秀的挑戰(zhàn),不久前,Kubernetes 官方發(fā)布公告宣布自v1.20 起放棄對Docker 的支持,屆時用戶將收到Docker 棄用警告,并需要改用其他容器運行時。而得到CNCF 官方推薦并作為內置模塊集成進Kubernetes 的Containerd 將在容器引擎領域得到良好的發(fā)展。在特定的應用場景下,Docker 等主流容器引擎顯得力不從心,因此一些針對某種用例進行過專門優(yōu)化的容器引擎技術紛紛入場。本文以終端作為容器的硬件載體,以可用于終端的輕量化容器引擎為出發(fā)點,對目前業(yè)界的4 種主流容器引擎進行研究評測。
Docker 作為廣泛應用于云端的成熟容器解決方案來說,對于終端并不適用。業(yè)界有通過嘗試裁剪Docker 以實現(xiàn)容器的輕量化方案,對Docker 進行輕量化改造,對其裁剪和精簡化、去除不需要的功能、優(yōu)化組件結構等,甚至還對Go 語言環(huán)境的編譯進行了優(yōu)化。但是,由于Docker 本身體積比較大,且由于要運行在端側的嵌入式設備上,這種裁剪和壓榨資源的做法所能取得的效果很有限。
iSulad 作為華為OpenEuler 開源系統(tǒng)上的全量的容器軟件棧其中的輕量化容器引擎,目前還處于項目的起步階段,雖然在對比測試中的各項性能指標相對其他容器引擎有一定優(yōu)勢,但目前和業(yè)界的相關合作并不是很多,還沒有得到充分的應用和驗證。
balenaEngine 雖然比Docker 輕量很多,但在實際架構設計上依然延續(xù)Docker 的思路,從本次測試的結果也可以看出,在很多測試指標上都與Docker 較為接近,目前看來其在容器引擎這條賽道上很難脫穎而出。
Containerd 在容器引擎的測試對比中表現(xiàn)比較優(yōu)秀,并且作為CNCF 官方推薦,在開源社區(qū)獲得了廣泛的關注,其在整個容器生態(tài)鏈中的影響力也在不斷提高。另外,Containerd 系統(tǒng)架構的插件機制決定了它可以很靈活地裁剪體積和拓展功能,對于其在各式各樣終端設備上的應用增添了可行性。
5G 的全面普及,推進了“萬物互聯(lián)”時代的到來,在這個智能終端之間保持隨時隨地的連接互通的泛連接時代,終端形態(tài)也逐漸的擴展和變化,泛智能終端設備必將從單設備、多設備逐漸走向跨平臺、分布式。在這樣的趨勢下,終端容器技術將向著,輕量化、異構化、模塊化的方向發(fā)展,助力端邊云網一體化合力構建的全場景生態(tài)和服務。