酷播亮新聞
最棒的知識補給站

​容器​與虛擬化技術實現原理對比

文章摘要: 虛擬化技術是指在同一臺計算機上通過hypervisor虛擬出多個包括完整虛擬機器系統映象,每個虛擬機器擁有獨立的作業系統和硬體資源。以KVM為例,下面初探一下虛擬化技術的實現原理。

寫在前面:

在網際網路技術日益革新、產品快速迭代的今天,如何在提高資源使用率、提升效率的同時又兼顧互不干涉、安全隔離的原則,促使了虛擬化技術和容器技術的相繼誕生。

虛擬化技術有KVM、VMWare等並駕齊驅,容器技術為docker獨領風騷。

傳統虛擬化技術與容器虛擬化技術的簡要技術架構對比如下:


Part.1 虛擬化技術

虛擬化技術是指在同一臺計算機上通過hypervisor虛擬出多個包括完整虛擬機器系統映象,每個虛擬機器擁有獨立的作業系統和硬體資源。

以KVM為例,下面初探一下虛擬化技術的實現原理。


1.1 KVM虛擬化技術

KVM虛擬化的實現,主要是通過嵌入linux核心的kvm模組與QEMU相互配合實現全虛擬化,而兩者的通訊主要通過一系列針對特殊裝置檔案/dev/kvm的IOCTL呼叫實現。

Kvm模組的主要功能為cpu虛擬化+記憶體虛擬化,在提供虛擬化功能時,它會暴露一個/dev/kvm的介面,這個介面主要是用來建立和執行vCPU(虛擬CPU)以及分配虛擬記憶體空間、vCPU暫存器的讀寫。

而QEMU則是以動態二進制轉換來建立和管理各種裝置,通過IOCTL呼叫kvm的介面將部分CPU指令交給vCPU執行,kvm也依賴qemu模擬IO裝置(磁碟,網絡卡,顯示卡等),從而實現完整意義上的全虛擬化。

從下圖QEMU簡化的核心程式碼可以管中窺豹領略兩者的聯絡。

Qemu啟動程式碼:


可以看到,kvm提供了一個裝置/dev/kvm,對kvm的控制要通過這個裝置提供的io_ctl介面實現。

Kvm核心在主機上虛擬出vCPU,虛擬記憶體,再通過QEMU建立和管理各個虛擬I/O裝置包括虛擬網絡卡,磁碟等,安裝上OS(作業系統),實現虛擬機器建立的每個虛擬機器相當於獨立出來的計算機。

1.2 舉個例子

從技術上無法理解的童鞋可以不看上面的原理,我用通俗的語言說明一下,好比我們有一個冷藏室,我有很多種類的食物需要冷藏,但是爲了空間利用,快速分類和互不串味,虛擬化技術的實現就是將冷藏室隔成各個小庫房,並且把冷凍機拆開組裝成多個小製冷機每個房間放一個,這樣小房間溫度也可控,而且味道也不會串。


Part.2 容器技術

容器技術是後於虛擬化技術出現的,如果說虛擬化技術的出現主要是爲了解決資源調配和隔離的問題,那麼容器技術解決的是應用開發、測試和部署等提升效率的問題。而Docker在眾多容器解決方案中脫穎而出,儼然成爲了容器技術的代表,現在就以Docker為例,介紹一下容器技術的實現原理。

2.1 Docker

Docker的理念為「Build,Ship and Run Any App,Anywhere」,非常美好的願景。爲了實現這個目標,Docker通過Namespace分離程序,隔離網路介面、掛載點和程序間通訊,使用Croups將CPU和記憶體等物理資源隔離開,這樣就將一個完全對宿主機「一無所知」而且擁有「獨立」資源的容器構造出來了,相比虛擬化技術,實際上容器還是容器之間共享同一個系統核心。

2.1.1 Namespace

Namespace的目的為通過抽象方法使得namespace 中的程序看起來擁有它們自己的隔離的全域性系統資源例項,linux核心實現了六種namespace:Mount namespaces,UTS namespaces,IPC namespaces,PID namespaces,Network namespaces,User namespaces,分別的功能為:隔離檔案系統、定義hostname和domainame、特定的程序間通訊資源、獨立程序ID結構、獨立網路裝置、使用者和組ID空間。

Docker在建立一個容器的時候,會建立以上六種Namespace例項,然後將隔離的系統資源放入到相應的Namespace中,使得每個容器只能看到自己獨立的系統資源。

以PID namespaces為例,Docker是怎麼使容器擁有獨立的PID空間的:

Linux核心中通過pid_namespace隔離PID,首先來看下pid_namespace的簡要數據結構:

struct pid_namespace {
struct kref kref;

//引用計數
struct pidmap pidmap[PIDMAP_ENTRIES];

//pid分配的bitmap,如果位為1,表示這個pid已經分配了

int last_pid;

//記錄上次分配的pid,理論上,當前分配的pid=last_pid+1

struct task_struct *child_reaper;

//表示程序結束後,需要這個child_reaper程序對這個程序進行託管

struct kmem_cache *pid_cachep;
unsigned int level;

//記錄這個pid namespace的深度
struct pid_namespace *parent;

//記錄父pid namespace
struct fs_pin *bacct;
#endif
};

其中陣列pidmap記錄了PID的分配情況,每一位代表了對應偏移量的PID是否分配,保證了PID不重複。
每一個程序都會生成一個task_struct,task_struct的簡單數據結構如下:

struct task_struct
{
………….
pid_t pid;
struct pid_link pids[PIDTYPE_MAX];
………….
}

其中pid的簡單數據結構如下:

struct pid
{
unsigned int level;

//這個pid所在的層級
struct hlist_head tasks[PIDTYPE_MAX];

//一個hash表,又三個表頭,分別是pid表頭,程序組id表頭,會話id表頭,用於和task_struct進行關聯

struct upid numbers[1];

//這個pid對應的名稱空間,一個pid不僅要包含當前的pid,還有包含父名稱空間,預設大小為1,所以就處於根名稱空間中

};

可以看出來,PID namespace主要通過以上三種數據結構的關聯,將容器內部也就是獨立的namespace中的uPID與宿主機上的PID建立起查詢關係。

具體的做法為,task_struct結構體中的pid_link成員的node欄位就被鄰接到pid中的upid。upid通過pid_hash和pid數值關聯了起來,這樣就可以通過pid數值快速的找到所有名稱空間的upid結構,numbers是一個struct pid的最後一個成員,利用可變陣列來表示這個pid結構當前有多少個名稱空間.這樣Docker就實現了容器程序間PID的隔離。
其它系統資源的實現方式雖然與PID隔離有所差異,但是總體來說大同小異,都是通過linux核心的namespace實現資源隔離。

2.1.2Cgroups

前面介紹了Docker如何將系統資源進行隔離,下面簡單介紹一下Docker如何利用Croups控制各個容器使用繫系統資源。

Croups也是linux核心中提供一種機制,它的功能主要是限制、記錄、隔離程序所使用的物理資源,比如:CPU、mermory、IO、network等,下面我們就看看它是如何做到的吧。

簡單來說,Cgroups在接收到呼叫時,會給指定的程序掛上鉤子,這個鉤子會在資源被使用的時候觸發,觸發時會根據資源的類別(CPU,mermory,io等)使用對應的方法進行限制。

Croups中有一個術語叫做subsystem(子系統),也就是一個資源排程控制器,CPU subsystem負責CPU的時間分配,mermory subsystem負責mermory的使用量等。Cgroups的資源控制單位為組稱之為cgroup,每個cgroup都包含一個或者多個subsystem。當一個任務加入了某個cgroup,cgroup對應的subsystem就開始工作,像上文提到的鉤子就會觸發subsystem進行資源的限制。

Docker 啟動一個容器後,會在/sys/fs/cgroup目錄下生成帶有此容器ID的資料夾,裏面就是呼叫Croups的配置檔案,從而實現通過cgroups限制容器的資源使用率。

2.2 舉個例子

結合最開始虛擬化的例子,我們有一個冷藏室,容器化技術就好比將冷藏室隔成各個小房間(namespace),然後用導管和閥門(cgroups)將冷氣輸送到各個房間。相比與之前提到的「虛擬化冷藏」,這種方式佔用更少的資源和擴充套件啟動速度更快的優點。


Part.3 總結

綜上,虛擬化技術為使用者提供了一個完整的虛擬機器:包括核心在內的一個完整的系統映象。容器化技術為應用程式提供了隔離的執行空間:每個容器內都包含一個獨享的完整使用者環境空間,容器之間共享同一個系統核心。

兩種技術都有各自的優點,比如虛擬化有更佳的隔離性和安全性,容器化快速擴充套件、靈活性和易用性。也有各自的缺點,比如虛擬化技術實施難度高、更新和升級困難、相比容器過於笨重。容器化技術也存在較差的隔離性、安全性不高(宿主機被感染,所有容器受到影響)等缺點。

雖然兩者的出現希望解決相同的問題,但是目前看來,並無孰優孰劣的定論。反而將兩種技術結合起來,一個容器中執行一個虛擬機器或者一個虛擬機器中執行多個容器。這樣,既保證了強隔離性和安全性的同時,也有了快速擴充套件、靈活性和易用性。所以說,除了世界上最好的語言PHP,技術都是不完美的,但是不能阻擋我們追求完美的步伐,就醬。


如有侵權請來信告知:酷播亮新聞 » ​容器​與虛擬化技術實現原理對比