懂了!VMware/KVM/Docker原來是這麼回事兒

軒轅之風 發表於 2020-06-30

雲端計算時代,計算資源如同小馬哥當年所言,已經成為了網際網路上的水和電。

懂了!VMware/KVM/Docker原來是這麼回事兒

虛擬主機、web伺服器、資料庫、物件儲存等等各種服務我們都可以通過各種各樣的雲平臺來完成。

而在雲端計算欣欣向榮的背後,有一個重要的功臣,那就是虛擬化技術。可以毫不客氣的說,沒有了虛擬化技術,雲端計算無從談起。

說起虛擬化你會想到什麼?從我們常用的虛擬機器三件套VMware、VirtualPC、VirutalBox到如今大火的KVM和容器技術Docker?

懂了!VMware/KVM/Docker原來是這麼回事兒

這些技術是什麼關係,背後的技術原理是怎樣的,又有什麼樣的區別,各自應用的場景又是什麼樣的?

看完這篇文章,相信大家都能回答上面問題。

歷史背景

什麼是虛擬化技術?

維基百科中的解釋是這樣的:

虛擬化(技術)是一種資源管理技術,是將計算機的各種實體資源(CPU、記憶體、磁碟空間、網路介面卡等),予以抽象、轉換後呈現出來並可供分割、組合為一個或多個電腦配置環境。

對於一臺計算機,我們可以簡單的劃分為三層:從下到上依次是物理硬體層,作業系統層、應用程式層

懂了!VMware/KVM/Docker原來是這麼回事兒

1974年,兩位電腦科學家Gerald Popek 和 Robert Goldberg發表了一篇重要的論文 《虛擬化第三代體系結構的正式要求》,在這篇論文中提出了虛擬化的三個基本條件:

  • 等價性:程式在本地計算機執行和在虛擬機器中執行應該表現出一樣的結果(不包括執行時間的差異)
  • 安全性:虛擬機器彼此隔離,與宿主計算機隔離
  • 效能:絕大多數情況下虛擬機器中的程式碼指令應該直接在物理CPU中執行,少部分特殊指令可由VMM參與。

那如何實現對計算機底層的物理資源的虛擬化分割呢?在計算機技術的發展歷史上,出現了兩種著名的方案,分別是I型虛擬化和II型虛擬化

I型虛擬化

II型虛擬化

圖中的VMM意為Virtual Machine Monitor,虛擬機器監控程式,或者用另一個更專業的名詞:HyperVisor

從圖中可以清楚的看到兩種虛擬化方案的區別:

Type I: 直接凌駕於硬體之上,構建出多個隔離的作業系統環境

Type II: 依賴於宿主作業系統,在其上構建出多個隔離的作業系統環境

我們熟知的VMware事實上有兩個產品線,一個是VMware ESXi,直接安裝在裸金屬之上,不需要額外的作業系統,屬於第一類虛擬化。另一個是我們普通使用者更加熟知的VMware WorkStation,屬於第二類虛擬化。

如何實現上述的虛擬化方案呢?

一個典型的做法是——陷阱 & 模擬技術

什麼意思?簡單來說就是正常情況下直接把虛擬機器中的程式碼指令放到物理的CPU上去執行,一旦執行到一些敏感指令,就觸發異常,控制流程交給VMM,由VMM來進行對應的處理,以此來營造出一個虛擬的計算機環境。

不過這一經典的虛擬化方案在Intel x86架構上卻遇到了問題。

全虛擬化:VMware 二進位制翻譯技術

不同於8086時代16位實地址工作模式,x86架構進入32位時代後,引入了保護模式、虛擬記憶體等一系列新的技術。同時為了安全性隔離了應用程式程式碼和作業系統程式碼,其實現方式依賴於x86處理器的工作狀態。

這就是眾所周知的x86處理器的Ring0-Ring3四個“環”。

懂了!VMware/KVM/Docker原來是這麼回事兒

作業系統核心程式碼執行在最高許可權的Ring0狀態,應用程式工作於最外圍許可權最低的Ring3狀態,剩下的Ring1和Ring2主流的作業系統都基本上沒有使用。

這裡所說的許可權,有兩個層面的約束:

  • 能訪問的記憶體空間
  • 能執行的特權指令

來關注一下第二點,特權指令。

CPU指令集中有一些特殊的指令,用於進行硬體I/O通訊、記憶體管理、中斷管理等等功能,這一些指令只能在Ring0狀態下執行,被稱為特權指令。這些操作顯然是不能讓應用程式隨便執行的。處於Ring3工作狀態的應用程式如果嘗試執行這些指令,CPU將自動檢測到並丟擲異常。

回到我們的主題虛擬化技術上面來,如同前面的定義所言,虛擬化是將計算資源進行邏輯或物理層面的切割劃分,構建出一個個獨立的執行環境。

按照我們前面所說的陷阱 & 模擬手段,可以讓虛擬機器中包含作業系統在內的程式統一執行在低許可權的Ring3狀態下,一旦虛擬機器中的作業系統進行記憶體管理、I/O通訊、中斷等操作時,執行特權指令,從而觸發異常,物理機將異常派遣給VMM,由VMM進行對應的模擬執行。

這本來是一個實現虛擬化很理想的模式,不過x86架構的CPU在這裡遇到了一個跨不過去的坎。

到底是什麼問題呢?

回顧一下前面描繪的理想模式,要這種模式能夠實現的前提是執行敏感指令的時候能夠觸發異常,讓VMM有機會介入,去模擬一個虛擬的環境出來。

但現實是,x86架構的CPU指令集中有那麼一部分指令,它不是特權指令,Ring3狀態下也能夠執行,但這些指令對於虛擬機器來說卻是敏感的,不能讓它們直接執行。一旦執行,沒法觸發異常,VMM也就無法介入,虛擬機器就露餡兒了!

這結果將導致虛擬機器中的程式碼指令出現無法預知的錯誤,更嚴重的是影響到真實物理計算機的執行,虛擬化所謂的安全隔離、等價性也就無從談起。

怎麼解決這個問題,讓x86架構CPU也能支援虛擬化呢?

VMware和QEMU走出了兩條不同的路。

VMware創造性的提出了一個二進位制翻譯技術。VMM在虛擬機器作業系統和宿主計算機之間扮演一個橋樑的角色,將虛擬機器中的要執行的指令“翻譯”成恰當的指令在宿主物理計算機上執行,以此來模擬執行虛擬機器中的程式。你可以簡單理解成Java虛擬機器執行Java位元組碼的過程,不同的是Java虛擬機器執行的是位元組碼,而VMM模擬執行的就是CPU指令。

懂了!VMware/KVM/Docker原來是這麼回事兒

另外值得一提的是,為了提高效能,也並非所有的指令都是模擬執行的,VMware在這裡做了不少的優化,對一些“安全”的指令,就讓它直接執行也未嘗不可。所以VMware的二進位制翻譯技術也融合了部分的直接執行。

對於虛擬機器中的作業系統,VMM需要完整模擬底層的硬體裝置,包括處理器、記憶體、時鐘、I/O裝置、中斷等等,換句話說,VMM用純軟體的形式“模擬”出一臺計算機供虛擬機器中的作業系統使用。

這種完全模擬一臺計算機的技術也稱為全虛擬化,這樣做的好處顯而易見,虛擬機器中的作業系統感知不到自己是在虛擬機器中,程式碼無需任何改動,直接可以安裝。而缺點也是可以想象:完全用軟體模擬,轉換翻譯執行,效能堪憂!

而QEMU則是完全軟體層面的“模擬”,乍一看和VMware好像差不多,不過實際本質是完全不同的。VMware是將原始CPU指令序列翻譯成經過處理後的CPU指令序列來執行。而QEMU則是完全模擬執行整個CPU指令集,更像是“解釋執行”,兩者的效能不可同日而語。

懂了!VMware/KVM/Docker原來是這麼回事兒

半虛擬化:Xen 核心定製修改

既然有全虛擬化,那與之相對的也就有半虛擬化,前面說了,由於敏感指令的關係,全虛擬化的VMM需要捕獲到這些指令並完整模擬執行這個過程,實現既滿足虛擬機器作業系統的需要,又不至於影響到物理計算機。

但說來簡單,這個模擬過程實際上相當的複雜,涉及到大量底層技術,並且如此模擬費時費力。

而試想一下,如果把作業系統中所有執行敏感指令的地方都改掉,改成一個介面呼叫(HyperCall),介面的提供方VMM實現對應處理,省去了捕獲和模擬硬體流程等一大段工作,效能將獲得大幅度提升。

這就是半虛擬化,這項技術的代表就是Xen,一個誕生於2003年的開源專案。

懂了!VMware/KVM/Docker原來是這麼回事兒

這項技術一個最大的問題是:需要修改作業系統原始碼,做相應的適配工作。這對於像Linux這樣的開源軟體還能接受,充其量多了些工作量罷了。但對於Windows這樣閉源的商業作業系統,修改它的程式碼,無異於痴人說夢。

硬體輔助虛擬化 VT / AMD-v

折騰來折騰去,全都是因為x86架構的CPU天然不支援經典虛擬化模式,軟體廠商不得不想出其他各種辦法來在x86上實現虛擬化。

如果進一步講,CPU本身增加對虛擬化的支援,那又會是一番怎樣的情況呢?

在軟體廠商使出渾身解數來實現x86平臺的虛擬化後的不久,各家處理器廠商也看到了虛擬化技術的廣闊市場,紛紛推出了硬體層面上的虛擬化支援,正式助推了虛擬化技術的迅猛發展。

這其中為代表的就是Intel的VT系列技術和AMD的AMD-v系列技術。

懂了!VMware/KVM/Docker原來是這麼回事兒

硬體輔助虛擬化細節較為複雜,簡單來說,新一代CPU在原先的Ring0-Ring3四種工作狀態之下,再引入了一個叫工作模式的概念,有VMX root operationVMX non-root operation 兩種模式,每種模式都具有完整的Ring0-Ring3四種工作狀態,前者是VMM執行的模式,後者是虛擬機器中的OS執行的模式。

VMM執行的層次,有些地方將其稱為Ring -1,VMM可以通過CPU提供的程式設計介面,配置對哪些指令的劫持和捕獲,從而實現對虛擬機器作業系統的掌控。

懂了!VMware/KVM/Docker原來是這麼回事兒

換句話說,原先的VMM為了能夠掌控虛擬機器中程式碼的執行,不得已採用“中間人”來進行翻譯執行,現在新的CPU告訴VMM:不用那麼麻煩了,你提前告訴我你對哪些指令哪些事件感興趣,我在執行這些指令和發生這些事件的時候就通知你,你就可以實現掌控了。完全由硬體層面提供支援,效能自然高了不少。

上面只是硬體輔助虛擬化技術的一個簡單理解,實際上還包含更多的要素,提供了更多的便利給VMM,包括記憶體的虛擬、I/O的虛擬等等,讓VMM的設計開發工作大大的簡化,VMM不再需要付出昂貴的模擬執行成本,整體虛擬化的效能也有了大幅度的提升。

VMware從5.5版本開始引入對硬體輔助虛擬化的支援,隨後在2011年的8.0版本中正式全面支援。於是乎,我們在建立虛擬機器的時候,可以選擇要使用哪一種虛擬化引擎技術,是用原先的二進位制翻譯執行,還是基於硬體輔助虛擬化的新型技術。

懂了!VMware/KVM/Docker原來是這麼回事兒

同一時期的XEN從3.0版本也加入對硬體輔助虛擬化的支援,從此基於XEN的虛擬機器中也能夠執行Windows系統了。

KVM-QEMU

有了硬體輔助虛擬化的加持,虛擬化技術開始呈現井噴之勢。VirtualBox、Hyper-V、KVM等技術如雨後春筍般接連面世。這其中在雲端計算領域聲名鵲起的當屬開源的KVM技術了。

KVM全稱for Kernel-based Virtual Machine,意為基於核心的虛擬機器。

在虛擬化底層技術上,KVM和VMware後續版本一樣,都是基於硬體輔助虛擬化實現。不同的是VMware作為獨立的第三方軟體可以安裝在Linux、Windows、MacOS等多種不同的作業系統之上,而KVM作為一項虛擬化技術已經整合到Linux核心之中,可以認為Linux核心本身就是一個HyperVisor,這也是KVM名字的含義,因此該技術只能在Linux伺服器上使用。

懂了!VMware/KVM/Docker原來是這麼回事兒

KVM技術常常搭配QEMU一起使用,稱為KVM-QEMU架構。前面提到,在x86架構CPU的硬體輔助虛擬化技術誕生之前,QEMU就已經採用全套軟體模擬的辦法來實現虛擬化,只不過這種方案下的執行效能非常低下。

KVM本身基於硬體輔助虛擬化,僅僅實現CPU和記憶體的虛擬化,但一臺計算機不僅僅有CPU和記憶體,還需要各種各樣的I/O裝置,不過KVM不負責這些。這個時候,QEMU就和KVM搭上了線,經過改造後的QEMU,負責外部裝置的虛擬,KVM負責底層執行引擎和記憶體的虛擬,兩者彼此互補,成為新一代雲端計算虛擬化方案的寵兒。

容器技術-LXC & Docker

前面談到的無論是基於翻譯和模擬的全虛擬化技術、半虛擬化技術,還是有了CPU硬體加持下的全虛擬化技術,其虛擬化的目標都是一臺完整的計算機,擁有底層的物理硬體、作業系統和應用程式執行的完整環境。

為了讓虛擬機器中的程式實現像在真實物理機器上執行“近似”的效果,背後的HyperVisor做了大量的工作,付出了“沉重”的代價。

雖然HyperVisor做了這麼多,但你有沒有問過虛擬機器中的程式,這是它想要的嗎?或許HyperVisor給的太多,而目標程式卻說了一句:你其實可以不用這樣辛苦。

確實存在這樣的情況,虛擬機器中的程式說:我只是想要一個單獨的執行執行環境,不需要你費那麼大勁去虛擬出一個完整的計算機來。

這樣做的好處是什麼?

虛擬出一臺計算機的成本高還是隻虛擬出一個隔離的程式執行環境的成本高?答案很明顯是前者。一臺物理機可能同時虛擬出10臺虛擬機器就已經開始感到乏力了,但同時虛擬出100個虛擬的執行環境卻還是能夠從容應對,這對於資源的充分利用可是有巨大的好處。

近幾年大火的容器技術正是在這樣的指導思想下誕生的。

懂了!VMware/KVM/Docker原來是這麼回事兒

不同於虛擬化技術要完整虛擬化一臺計算機,容器技術更像是作業系統層面的虛擬化,它只需要虛擬出一個作業系統環境。

LXC技術就是這種方案的一個典型代表,全稱是LinuX Container,通過Linux核心的Cgroups技術和namespace技術的支撐,隔離作業系統檔案、網路等資源,在原生作業系統上隔離出一個單獨的空間,將應用程式置於其中執行,這個空間的形態上類似於一個容器將應用程式包含在其中,故取名容器技術。

舉個不是太恰當的比喻,一套原來是三居室的房子,被二房東拿來改造成三個一居室的套間,每個一居室套間裡面都配備了衛生間和廚房,對於住在裡面的人來說就是一套完整的住房。

如今各個大廠火爆的Docker技術底層原理與LXC並不本質區別,甚至在早期Docker就是直接基於LXC的高層次封裝。Docker在LXC的基礎上更進一步,將執行執行環境中的各個元件和依賴打包封裝成獨立的物件,更便於移植和部署。

懂了!VMware/KVM/Docker原來是這麼回事兒

容器技術的好處是輕量,所有隔離空間的程式程式碼指令不需要翻譯轉換,就可以直接在CPU上執行,大家底層都是同一個作業系統,通過軟體層面上的邏輯隔離形成一個個單獨的空間。

容器技術的缺點是安全性不如虛擬化技術高,畢竟軟體層面的隔離比起硬體層面的隔離要弱得多。隔離環境系統和外面的主機共用的是同一個作業系統核心,一旦利用核心漏洞發起攻擊,程式突破容器限制,實現逃逸,危及宿主計算機,安全也就不復存在。

超輕虛擬化 firecracker

虛擬完整的計算機隔離性好但太過笨重,簡單的容器技術又因為太過輕量純粹靠軟體隔離不夠安全,有沒有一個折中的方案同時兼具兩者的優點,實現既輕量又安全呢?

近年來,一種超輕虛擬化的思想開始流行開來,亞馬遜推出的firecracker就是一個典型的代表。

懂了!VMware/KVM/Docker原來是這麼回事兒

firecracker將虛擬化技術的強隔離性和容器技術的輕量性進行融合,提出了一個microVM的概念,底層通過KVM虛擬化技術實現各個microVM的強隔離,而隔離的虛擬機器中執行的是一個個精簡版的微型作業系統,砍掉了大量無用的功能,專為容器設計的微型OS。

超輕虛擬化如今成為一個新的浪潮,除了AWS的firecracker,谷歌的gVisor, Intel主導的NEMU也在向這個領域開始發力。

總結

本文簡單介紹了虛擬化技術的基本概念和基本要求。隨後引出由於早期的x86架構不支援經典的虛擬化方案,各家軟體廠商只能通過軟體模擬的形式來實現虛擬化,其代表是早期的VMware WorkStation和Xen。

不過純粹依靠軟體的方式畢竟有效能的瓶頸,好在Intel和AMD及時推出了CPU硬體層面的虛擬化支援,軟體廠商迅速跟進適配,極大的改善了虛擬化的效能體驗。這一時期的代表有新版本的VMware WorkStation、Hyper-V、KVM等。

懂了!VMware/KVM/Docker原來是這麼回事兒

近年來,隨著雲端計算和微服務的縱深發展,對虛擬化技術的虛擬粒度逐漸從粗到細。從最早的虛擬化完整的計算機,到後來只需虛擬出一個作業系統,再到後來虛擬出一個微服務需要的環境即可,以Docker為代表的容器技術在這個時期大放異彩。

技術的發展總是伴隨著市場的發展需要而不斷演進,虛擬化的未來是怎樣的,你有什麼樣的看法呢,歡迎評論區留言交流。

往期TOP5文章

真慘!連各大程式語言都擺起地攤了!

因為一個跨域請求,我差點丟了飯碗

完了!CPU一味求快出事兒了!

雜湊表哪家強?幾大程式語言吵起來了!

一個HTTP資料包的奇幻之旅

懂了!VMware/KVM/Docker原來是這麼回事兒

懂了!VMware/KVM/Docker原來是這麼回事兒