深入理解虛擬機器、容器和Hyper技術
本文首先介紹了作業系統,然後引出容器技術以及虛擬機器技術,最後介紹了Docker和Hyper技術。通過本文可以清楚地對三者有感性認識。
作業系統概述
我們可以把作業系統簡化為:
作業系統 = 核心 + apps
其中核心負責管理底層硬體資源,包括CPU、記憶體、IO裝置等,並向上為apps提供系統呼叫介面,上層apps應用必須通過系統呼叫方式使用硬體資源,通常並不能直接訪問資源。這裡的apps指的是使用者介面,比如shell、gui、services、包管理工具等(linux的圖形介面也是作為可選應用之一,而不像Windows是整合到核心中的),注意與我們手動安裝的應用區別開來。同一個核心加上不同的apps,就構成了不同的作業系統發行版,比如Ubuntu、Red Hat、Android等。因此我們可以認為,不同的Linux發行版本其實就是由應用apps構成的環境的差別,比如預設安裝的軟體、連結庫、軟體包管理以及圖形介面等。我們把所有這些apps環境打成一個包,就可以稱之為映象。
問題來了,假如我們同時有多個apps環境,能否在同一個核心上執行呢?因為作業系統只負責提供服務,而並不管為誰服務,因此同一個核心之上可以同時執行多個apps環境是沒有問題的。比如假設我們現在有ubuntu和fedora的apps環境,即兩個發行版映象,分別位於/home/int32bit/ubuntu和/home/int32bit/fedora,我們最簡單的方式,採用chroot工具即可快速切換到指定的應用環境中,相當於同時有多個apps環境在執行。
容器技術
我們以上通過chroot方式,感覺上就已經接近了容器的功能,但其實容器並沒有那麼簡單,工作其實還差得遠。首先要作為雲資源管理還必須滿足:
資源隔離
因為雲端計算本質就是集中資源再分配(社會主義),再分配過程就是資源的邏輯劃分,提供資源抽象的實現方式,我們暫且定義為虛擬實體,虛擬實體可以是虛擬機器、容器等。虛擬實體必須滿足隔離性,包括使用者隔離(或者說許可權隔離)、程式隔離、網路隔離、檔案系統隔離等,即虛擬實體只能感知其內部的資源,並且自以為是獨佔整個資源空間,它既不能感知其所在宿主機的真實資源,也不能感知其他虛擬實體的資源。
資源控制
資源控制指為虛擬實體分配一定量的資源,虛擬實體得到所分配的資源,不能超出資源最大使用量。
以上是虛擬實體的兩個最基本要求,當然還包括其他很多條件,比如安全、效能等。本文主要基於以上兩個基本條件進行研究。
虛擬機器技術
顯然滿足以上兩個條件,虛擬機器是一種實現方式,這是因為:
- 隔離毋容置疑,因為不同的虛擬機器執行在不同的核心,虛擬機器內部是一個獨立的隔離環境。
- 資源控制也是毋容置疑的,Hypervisor能夠對虛擬機器分配指定的資源。
目前OpenStack Nova和AWS EC2都是基於虛擬機器提供計算服務,實現CPU、RAM、Disk等資源分配。其他比如Vagrant也是基於虛擬機器快速構建應用環境。
但是虛擬機器也帶來很多問題,比如:
- 映象臃腫龐大,不僅包括apps,還包括一個龐大的核心。
- 建立和啟動時間開銷大,不利於應用快速構建重組。
- 額外資源開銷大,部署密度小。
- 效能損耗。
- ...
容器技術
除了虛擬機器,有沒有其他實現方式能符合以上兩個基本條件呢?容器技術便是另一種實現方式。表面上和我們使用chroot方式相似,所有的容器例項直接執行在宿主機中,所有例項共享宿主機的核心,而虛擬機器例項內部的程式是執行在GuestOS中。由以上原理可知,容器相對於虛擬機器有以上好處:
- 映象體積更小,只包括apps以及所依賴的環境,沒有核心。
- 建立和啟動快,不需要啟動GuestOS,應用啟動開銷基本就是應用本身啟動的時間開銷。
- 無GuestOS,無hypervisor,無額外資源開銷,資源控制粒度更小,部署密度大。
- 使用的是真實物理資源,因此不存在效能損耗。
- 輕量級。
- ...
目前比較流行的容器實現比如LXC、LXD以及rkt等,我們需要驗證容器是否能夠實現資源隔離和控制。
隔離性
主要通過核心提供namespace技術實現隔離性,以下參考酷殼:
Linux Namespace是Linux提供的一種核心級別環境隔離的方法。不知道你是否還記得很早以前的Unix有一個叫chroot的系統呼叫(通過修改根目錄把使用者jail到一個特定目錄下),chroot提供了一種簡單的隔離模式:chroot內部的檔案系統無法訪問外部的內容。Linux Namespace在此基礎上,提供了對UTS、IPC、mount、PID、network、User等的隔離機制。
Linux Namespace有如下種類:
- Mount Namespaces
- UTS Namespaces
- IPC Namespaces
- PID Namespaces
- Network Namespaces
- User Namespaces
官方文件在這裡《Namespace in Operation》。
由上表可知,容器利用核心的Namespaces技術可以實現隔離性。比如網路隔離,我們可以通過sudo ip netns ls檢視Namespaces,通過ip netns add NAME增加Namespaces,不同的Namespaces可以有不同的網路卡、Router、iptables等。
資源控制
核心實現了對程式組的資源控制,即Linux Control Group,簡稱CGroup,它能為系統中執行程式組根據使用者自定義組分配資源。簡單來說,可以實現把多個程式合成一個組,然後對這個組的資源進行控制,比如CPU,記憶體大小、網路頻寬、磁碟iops等,Linux把CGroup抽象成一個虛擬檔案系統,可以掛載到指定的目錄下,Ubuntu 14.04預設自動掛載在/sys/fs/cgroup下,使用者也可以手動掛載,比如掛載Memory子系統(子系統可以實現某類資源的控制,比如CPU、Memory、blkio等)到/mnt下:
sudo mount -t cgroup -o memory memory /mnt
掛載後就能像檢視本地檔案一樣瀏覽程式組以及資源控制情況,控制組並不是孤立的,而是組織成樹狀結構構成程式組樹,控制組的子節點會繼承父節點。下面以Memory子系統為例,
ls /sys/fs/cgroup/memory/
輸出:
cgroup.clone_children memory.kmem.failcnt memory.kmem.tcp.usage_in_bytes memory.memsw.usage_in_bytes memory.swappiness cgroup.event_control memory.kmem.limit_in_bytes memory.kmem.usage_in_bytes memory.move_charge_at_immigrate memory.usage_in_bytes cgroup.procs memory.kmem.max_usage_in_bytes memory.limit_in_bytes memory.numa_stat memory.use_hierarchy cgroup.sane_behavior memory.kmem.slabinfo memory.max_usage_in_bytes memory.oom_control notify_on_release docker memory.kmem.tcp.failcnt memory.memsw.failcnt memory.pressure_level release_agent memory.failcnt memory.kmem.tcp.limit_in_bytes memory.memsw.limit_in_bytes memory.soft_limit_in_bytes tasks memory.force_empty memory.kmem.tcp.max_usage_in_bytes memory.memsw.max_usage_in_bytes memory.stat user
以上是根控制組的資源限制情況,我們以建立控制記憶體為4MB的Docker容器為例:
docker run -m 4MB -d busybox ping localhost
返回ID為0532d4f4af67,自動會建立以Docker例項DI為名的控制組,位於/sys/fs/cgroup/memory/docker/0532d4f4af67...,我們檢視該目錄下的memory.limit_in_bytes檔案內容為:
cat memory.limit_in_bytes 4194304
即最大的可使用的記憶體為4MB,正好是我們啟動Docker所設定的。
由以上可知,容器可以通過CGroup實現資源控制。
Docker技術
在Docker之前其實容器技術早就有了,Google的Borg以及Omega都利用了容器技術。但是之前容器一直沒有形成一個標準,也沒有一個很好的管理工具。LXC是Linux原生支援的容器,很多工具依賴於具體的發行版,可能會出現移植性差的問題,並且也缺乏一組完善的管理工具集。而Docker基於底層的核心特性的基礎上,在上層構建了一個更高層次的具備多個強大功能的工具集,它是PaaS提供商dotCloud開源的一個基於LXC的高階容器引擎,簡單說Docker提供了一個能夠方便管理容器的工具並形成標準。Docker相當於把應用以及應用所依賴的環境完完整整地打成了一個包,這個包拿到哪裡都能原生執行。
其特性包括:
- 快速構建基於容器的分散式應用
- 具有容器的所有優點
- 提供原生的資源監控
- 自動構建和版本控制
- 快速構建和重組
- ...
Docker與虛擬機器原理對比:
容器技術在很早就有了,因此不能說Docker發明了容器技術,而僅僅是發明了一套完整的管理容器的工具集。但其實Docker核心的創新在於它的映象管理,因此有人說:
Docker = LXC + Docker Image
Docker映象的創新之處在於使用了類似層次的檔案系統AUFS,簡單說就是一個映象是由多個映象層層疊加的,從一個Base映象中通過加入一些軟體構成一個新層的映象,依次構成最後的映象,如圖:
Image的分層,可以想象成Photoshop中不同的layer。每一層中包含特定的檔案,當Container執行時,這些疊加在一起的層就構成了Container的執行環境(包括相應的檔案、執行庫等,不包括核心)。Image通過依賴的關係,來確定整個映象內到底包含那些檔案。之後的版本的Docker,會推出Squash的功能,把不同的層壓縮成為一個,和Photoshop中合併層的感覺差不多。
作者:Honglin Feng
連結:https://www.zhihu.com/question ... 71258
來源:知乎
這裡利用了COW(copy on write)技術,即從一個映象啟動一個容器例項,這個映象是以只讀形式掛載的,即不允許任何修改操作。當在容器例項中修改一個檔案時,會首先從映象裡把這個檔案拷貝到可寫層,然後執行更新操作。當讀一個檔案時,會首先從可寫層裡找這個檔案,若這個檔案存在,直接返回檔案內容,如果不存在這個檔案,則會從最頂層的映象開始查詢,直到最底層的Base映象。這裡存在的一個問題是,當映象層很多時,查詢一個檔案可能需要一層一層查詢,影響效能。基於Ceph構建OpenStack建立虛擬機器也一樣的原理,我們上傳一個映象到Glance時,首先對這個映象建立一個快照並保護起來不允許寫操作,當基於這個映象建立虛擬機器時,直接從映象快照克隆一個新的rbd image作為虛擬機器的根磁碟,最開始這個根磁碟除了指向其parent快照的指標,沒有任何內容,不佔任何磁碟空間,當虛擬機器需要修改一個物件時,首先從parent中拷貝這個物件到它所在的空間,再執行更新操作。當讀一個檔案時,如果存在這個檔案,直接讀取,否則需要去parent所在的image中查詢。
這樣的好處是:
- 節省儲存空間——多個映象共享Base Image儲存;
- 節省網路頻寬——拉取映象時,只需要拉取本地沒有的映象層,本地已經存在的可以共享,避免多次傳輸拷貝;
- 節省記憶體空間——多個例項可共享Base Image,多個例項的程式命中快取內容的機率大大增加。如果基於某個映象啟動一個虛擬機器需要資源k,則啟動n個同一個映象的虛擬機器需要佔用資源kn,但如果基於某個映象啟動一個Docker容器需要資源k,無論啟動多少個例項,資源都是k;
- 維護升級方便——相比於copy-on-write型別的FS,Base Image也是可以掛載為可Writeable的,可以通過更新Base Image而一次性更新其之上的Container;
- 允許在不更改Base Image的同時修改其目錄中的檔案——所有寫操作都發生在最上層的writeable層中,這樣可以大大增加Base Image能共享的檔案內容。
使用容器技術,帶來了很多優點,但同時也存在一些問題:
- 隔離性相對虛擬機器弱-由於和宿主機共享核心,帶來很大的安全隱患,容易發生逃逸。
- 如果某些應用需要特定的核心特性,使用容器不得不更換宿主機核心。
- ...
更多關於AUFS參考酷殼:Docker基礎技術-AUFS。
Hyper技術
上文提到容器存在的問題,並且Docker的核心創新在於映象管理,即:
Docker = LXC + Docker Image
於是就有人提出把容器替換成最初的Hypervisor,而又利用Docker Image的優勢,接下來介紹的Hyper技術以及VMware最新的vic技術大體如此,Hyper官方定義:
Hyper - a Hypervisor-based Containerization solution
即:
Hyper = Hypervisor + Docker Image
簡而言之Hyper是一種基於虛擬化技術(Hypervisor)的Docker引擎。官方認為:
雖然Hyper同樣通過VM來執行Docker應用,但HyperVM裡並沒有GuestOS,相反的,一個HyperVM內部只有一個極簡的HyperKernel,以及要執行的Docker映象。這種Kernel Image的"固態"組合使得HyperVM和Docker容器一樣,實現了Immutable Infrastructure的效果。藉助VM天然的隔離性,Hyper能夠完全避免LXC共享核心的安全隱患.
建立一個基於Hyper的Ubuntu:
sudo hyper run -t ubuntu:latest bash
建立時間小於1秒,確實達到啟動容器的效率。
檢視核心版本:
root@ubuntu-latest-7939453236:/# uname -a Linux ubuntu-latest-7939453236 4.4.0-hyper #0 SMP Mon Jan 25 01:10:46 CST 2016 x86_64 x86_64 x86_64 GNU/Linux
宿主機核心版本:
$ uname -a Linux lenovo 3.13.0-77-generic #121-Ubuntu SMP Wed Jan 20 10:50:42 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
啟動基於Docker的Ubuntu並檢視核心版本:
$ docker run -t -i ubuntu:14.04 uname -a Linux 73a88ca16d94 3.13.0-77-generic #121-Ubuntu SMP Wed Jan 20 10:50:42 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
我們發現Docker和宿主機的核心版本是一樣的,即3.13.0-77-generic,而Hyper核心不一樣,版本為4.4.0-hyper。
以下為官方資料:
因此Hyper是容器和虛擬機器的一種很好的折衷技術,未來可能前景廣大,但需要進一步觀察,我個人主要存在以下疑問:
- 使用極簡的核心,會不會導致某些功能丟失?
- 是不是需要為每一個應用維護一個微核心?
- 有些應用需要特定核心,這些應用實際多麼?可以通過其他方式避免麼?
- Hyper引擎能否提供和Docker引擎一樣的api,能否在生態圈中相互替代?
- 隔離性加強的同時也犧牲了部分效能,如何權衡?
總結
近年來容器技術以及微服務架構非常火熱,CaaS有取代傳統IaaS的勢頭,未來雲端計算市場誰成為主流值得期待。
相關文章
- 容器技術和虛擬機器技術的對比虛擬機
- 深入理解java虛擬機器Java虛擬機
- 技術界中的虛擬機器、容器和沙箱的關係虛擬機
- 深入理解虛擬機器之虛擬機器類載入機制虛擬機
- 深入理解Java虛擬機器(一)Java虛擬機
- 深入理解Java虛擬機器(二)Java虛擬機
- Hyper-V和其他虛擬機器共存 【轉】虛擬機
- 深入理解虛擬機器之虛擬機器效能監控和故障處理工具虛擬機
- 深入理解Java虛擬機器 --- 垃圾回收器Java虛擬機
- Docker技術( 容器虛擬化技術 )Docker
- 【深入理解Java虛擬機器】垃圾回收Java虛擬機
- 深入理解虛擬機器之垃圾回收虛擬機
- PowerShell管理Hyper-V虛擬機器虛擬機
- Hyper-V批次建立虛擬機器虛擬機
- 深入理解虛擬機器之虛擬機器位元組碼執行引擎虛擬機
- VM和Container 虛擬機器和容器AI虛擬機
- 深入理解多執行緒(五)—— Java虛擬機器的鎖優化技術執行緒Java虛擬機優化
- Docker容器和虛擬機器區別Docker虛擬機
- 深入理解Java虛擬機器8 虛擬機器位元組碼執行引擎Java虛擬機
- 《深入理解 Java 虛擬機器》筆記整理Java虛擬機筆記
- [深入理解Java虛擬機器]執行緒Java虛擬機執行緒
- 《深入理解Java虛擬機器》個人筆記Java虛擬機筆記
- 虛擬機器、容器與沙盒技術有什麼區別?虛擬機
- Win10系統Hyper-V虛擬機器在哪開啟 Hyper-V虛擬機器怎麼關Win10虛擬機
- 深入理解JVM虛擬機器6:深入理解JVM類載入機制JVM虛擬機
- Docker,容器,虛擬機器和紅燒肉Docker虛擬機
- 深入理解JVM,虛擬機器類載入機制JVM虛擬機
- 深入理解Java虛擬機器(類載入機制)Java虛擬機
- 深入理解Java虛擬機器 - 類載入機制Java虛擬機
- 深入理解Java虛擬機器 --- 類載入機制Java虛擬機
- 深入理解java虛擬機器之垃圾收集器Java虛擬機
- 反虛擬機器技術總結虛擬機
- 虛擬機器檢測技術攻防虛擬機
- 《深入理解java虛擬機器》學習筆記4——Java虛擬機器垃圾收集器Java虛擬機筆記
- 《深入理解Java虛擬機器》個人讀書總結——JAVA虛擬機器記憶體Java虛擬機記憶體
- 深入理解Java虛擬機器之實戰OutOfMemoryErrorJava虛擬機Error
- 深入理解Java虛擬機器之垃圾回收篇Java虛擬機
- 《深入理解Java虛擬機器》讀書筆記Java虛擬機筆記