于燁++李斌++劉思堯



摘要:Docker因為其輕量、便捷的特點,受了業界廣泛的關注和討論,目前已有多個相關項目,逐漸形成了圍繞Docker的生態體系。Docker的核心思想是利用擴展的LXC(Linux Container)方案實現一種輕量級的虛擬化解決方案。Docker主要利用AUFS機制來實現系統的移植性,節省了存儲和內存,也保證了容器的快速部署。本文從AUFS的實現原理入手,詳細分析了Docker的移動應用部署的原理和可行性。
關鍵詞:Docker;AUFS;文件系統;移植性
中圖分類號:TP311
文獻標識碼:A
DOI: 10.3969/j.issn.1003-6970.2015.07.012
0 引言
Docker是dotcloud公司于2013初年開始的一個開源項目,最早是該公司已有的云業務的一個自然擴展技術。Docker對容器的使用基本是建立在LXC基礎之上的,然而LXC存在的問題是難以移動,即難以通過標準化的模板制作、重建、復制和移動容器。在以VM為基礎的虛擬化手段中,有image和snapshot可以用于VM的復制、重建以及移動的功能。想要通過容器來實現快速的大規模部署和更新,這些功能不可或缺。針對這樣的問題,Docker利用AUFS來實現對容器的快速更新,Docker0.7中引入了Storage Driver,支持AUFS,VFS,Device Mapper,也為BTRFS以及ZFS的引入提供了可能。
1 Docker簡介
Docker是PaaS提供商dotCloud開源的一個基于LXC(Linux Container)的應用容器引擎,讓開發者可以將應用程序、依賴的運行庫文件打包并移植到一個新的容器中,然后發布到任何系統為Linux的機器上,也可以實現虛擬化解決方案。容器是完全沙箱機制的實現方式,任意容器之間不會有任何接口,具有安全訪問資源的特性,可以實現系統的隔離;而且容器的運行資源開銷小,可以很容易地在機器和數據中心中運行。最重要的是Docker容器不依賴于任何特定需求實現的編程語言、編程框架或已打包的系統。Docker目前在業界非常受歡迎,包括dotCloud, Google Compute Engine和百度應用引擎(BAE),都使用了Docker。
Docker容器主要解決“依賴地獄”的問題,即應用通常從已存在的組件組合而來,并且依賴其他服務和應用。例如,Python應用可能使用Postgre所為一個數據存儲,用Redis緩存以及使用Apache作web服務器。每個這些組件都附帶自身的一些依賴,這些依賴可能與其他組件產生沖突。通過打包每個組件及其依賴,Docker容器解決沖突依賴、缺少依賴、平臺依賴等問題。
2 Docker的移植性
2.1 AUFS簡介
AUFS (AnotherUnionFS)是一種Union FS,簡單來說就是支持將不同目錄掛載到同一個虛擬文件系統下(unite several directories into a single virtual filesystem)的文件系統,更進一步地,AUFS支持為每一個成員目錄(AKA branch)設定readonly,readwrite和whiteout-able權限,同時AUFS里有一個類似分層的概念,對readonly權限的branch可以邏輯上進行修改(增量地,不影響readonly部分的)。通常Union FS有兩個用途,一方面可以實現不借助LVM,RAID將多個disk和掛在到一個目錄下,另一個更常用的就是將一個readonly的branch和一個writeable的branch聯合在一起,Live CD正是基于此可以允許在OS image不變的基礎上允許用戶在其上進行一些寫操作。
2.2 Docker的移植性分析
Docker使用AuFS作為容器的文件系統。AuFS的層狀文件系統能夠透明覆蓋一個或多個現有文件系統。當一個進程需要修改一個文件時,AuFS創建該文件的一個副本。AuFS可以通過寫復制把多層合并成文件系統的單層表示。AuFS允許Docker把某些鏡像作為容器的基礎。例如,利用AuFS的機制,只需要一個CentOS鏡像的副本就可以作為很多不同容器的基礎,既節省了存儲和內存,也保證了容器的快速部署。
使用AuFS的另一個好處是提升了Docker的版本容器鏡像能力。每個新版本都是一個與之前版本的簡單差異改動,有效地保持鏡像文件最小化。但這也意味著需要一個記錄該容器從一個版本到另一個版本改動的審計跟蹤。
AUFS是一種Union FS,它是一種支持將不同目錄掛載到同一個虛擬文件系統下的文件系統,并且支持為每一個成員目錄(AKA branch)設定‘readonly,‘readwrite和 ‘whiteout-able權限,同時AUFS里有一個類似分層的概念,對readonly權限的branch可以邏輯上進行修改。通常Union FS有兩個用途,一方面可以實現不借助LVM, RAID將多個disk和掛在到一個目錄下,另一個更常用的就是將一個readonly的branch和一個writeable的branch聯合在一起,Live CD正是基于此可以允許在OS image不變的基礎上允許用戶在其上進行一些寫操作。Docker在AUFS上構建的container image也正是如此。
典型的Linux啟動到運行需要兩個FS:bootfs和rootfs(從功能角度而非文件系統角度),如圖1所示。
bootfs (boot file system)主要包含bootloader和kernel,bootloader主要用于引導加載kernel,當boot成功后,kernel被加載到內存中,bootfs就被umount了。endprint
rootfs (root file system)包含典型Linux系統中的/dev,/proc,/bin,/etc等標準目錄和文件。
由此可見對于不同的linux發行版,bootfs基本是一致的,rootfs會有差別,因此不同的發行版可以公用bootfs如圖2所示。
典型的Linux在啟動后,首先將rootfs置為readonly,進行一系列檢查,然后將其切換為readwrite供用戶使用。在docker中,最初也是將rootfs以readonly方式加載并檢查,接下來利用unionmount將一個readwrite文件系統掛載在readonly的rootfs之上,允許再次將下層的file system設定為readonly并向上疊加,這樣以來一組readonly和一個writeable的結構就構成一個container的運行目錄,每一個運行目錄被稱作一個Layer,如圖3所示。
得益于AUFS的特性,每一個對readonly層文件或文件目錄的修改都只會存在于上層的writeable層中。這樣就可以避免競爭,使多個container可以共享readonly的layer。
因此docker將readonly的層稱作“image”,對于容器而言整個rootfs都是read-write的,但事實上所有的修改都寫入最上層的writeable層中,image不保存用戶狀態,可以用于模板、重建和復制。
上層的image依賴下層的image,因此docker中把下層的image稱作父image,沒有父image的image稱作base image,如圖4所示。
因此想要從一個image啟動一個容器,docker會先加載其父image直到base image,用戶的進程運行在writeable的layer中。所有parent image中的數據信息以及ID、網絡和lxc管理的資源限制等具體container的配置,構成一個docker概念上的容器,如圖5所示。
由此可見,采用AUFS作為docker的容器文件系統,能夠提供如下好處:
(1)節省存儲空間:多個容器可以共享base image存儲;
(2)快速部署:如果要部署多個容器,base image可以避免多次拷貝;
(3)內存更省:因為多個容器共享base image,以及OS的disk緩存機制,多個容器中的進程命中緩存內容的幾率大大增加;
(4)升級更方便:相比于copy-on-write類型的FS,base-image也可以掛載為可writeable的,可以通過更新base image而一次性更新其之上的容器;
(5)允許在不更改base-image的同時修改其目錄中的文件:所有寫操作都發生在最上層的writeable層中,這樣可以大大增加base image能共享的文件內容。
以上5條中,1-3條可以通過copy-on-write的FS實現,4可以利用其他的union mount方式實現,5只有AUFS實現的很好。這也是為什么Docker一開始就建立在AUFS之上。
3 結論
Docker使用AuFS作為容器的文件系統。AUFS是一種Union FS,它是一種支持將不同目錄掛載到同一個虛擬文件系統下的文件系統,并且為每一個成員目錄(AKA branch)設定不同的權限,并基于一種分層的概念,對這些權限從邏輯上進行修改。節省了存儲和內存,保證了容器的快速部署和升級的便捷性。endprint