1. 程式人生 > Docker入門教學 >UnionFS 與 Docker

UnionFS 與 Docker

我們自己在上一節留下了不少問題,在自制 rootfs 有很多不完善的地方,在 Docker 產品的方面,就對這些部分進行了補足, 解決的方案,基本都是圍繞 UnionFS (聯合檔案系統)展開的,本節我們會講講 UnionFS 和它在 Docker中 的應用。

1. 什麼是檔案系統

計算機的檔案系統是一種儲存和組織計算機資料的方法,它使得對其訪問和查詢變得容易,檔案系統使用檔案和樹形目錄的抽象邏輯概念代替了硬碟和光碟等物理裝置使用資料塊的概念,使用者使用檔案系統來儲存資料不必關心資料實際儲存在硬碟(或者光碟)的地址為多少的資料塊上,只需要記住這個檔案的所屬目錄和檔名。在寫入新資料之前,使用者不必關心硬碟上的那個塊地址沒有被使用,硬碟上的儲存空間管理(分配和釋放)功能由檔案系統自動完成,使用者只需要記住資料被寫入到了哪個檔案中。

一句話總結,檔案系統是一套實現了資料的儲存、分級組織、訪問和獲取等操作的抽象資料型別。

2. 什麼是 UnionFS

聯合檔案系統(Union File System):2004 年由紐約州立大學開發,它可以把多個目錄內容聯合掛載到同一個目錄下,而目錄的物理位置是分開的。UnionFS可以把只讀和可讀寫檔案系統合併在一起,具有寫時複製功能,允許只讀檔案系統的修改可以儲存到可寫檔案系統當中。

目前有多種檔案系統可以被當作聯合檔案系統,CentOS8 使用的是 overlay2,下面,我們嘗試著掛載一個 overlay2 檔案系統。

/root/test 目錄下,建立一個unionfs 目錄,它的目錄結構如下(a,b,c是檔案,其他都是目錄):

unionfs
├── lower1
│   ├── a
│   └── b
├── lower2
│   └── a
├── merged
├── upper
│   └── c
└── work

進入 unionfs 目錄,使用 mount 命令掛載:

cd unionfs
mount -t overlay overlay -o lowerdir=lower1:lower2,upperdir=upper,workdir=work merged

如上,掛載了一個名為 overlay 的 overlay2 型別的檔案系統,掛載點為 merged 目錄。

檢視 merged 目錄的層次:

[
root@centos8 unionfs]# tree merged merged ├── a ├── b └── c

檢視這些檔案的內容:

[root@centos8 unionfs]# for i in `ls merged`;do echo $i: `cat merged/$i`;done
a: in lower1
b: in lower1
c: in upper

可以看到,從 merged 視角,位於 lower2 的 a 檔案被 lower1 的 a 檔案覆蓋;b 檔案位於 lower1,c 檔案位於 upper,符合從高到低 upper->lower1->lower2 的層次結構。

我們按照如下操作來驗證 unionfs 的分層特性:

[root@centos8 unionfs]# touch merged/d
[root@centos8 unionfs]# ls merged/
a  b  c  d
[root@centos8 unionfs]# ls upper/
c  d
[root@centos8 unionfs]# ls lower1
a  b
[root@centos8 unionfs]# ls lower2
a

可以看到對 merged 目錄的改動同步至 upper 目錄中,並不會影響到 lower 目錄。

3. Docker 如何使用 UnionFS?

Docker 的官方文件中有一張圖片,很好地展示了 Docker 使用 UnionFS 搭建的分層結構的狀態。
圖片描述

使用 UnionFS 搭建的分層結構

圖中的容器是執行在 debian 容器環境中的 apache 網頁應用,這個環境還提供了 emacs 編輯器功能。

將之前我們自己構建的 rootfs 與上面這張圖片對比,會發現我們將所有系統檔案、執行庫檔案和上層應用,都放到了一個 rootfs 裡面,這樣做缺乏靈活性,增大了維護的複雜度。而 Docker 引入了層(layer)的概念,將 rootfs 的內容進行了分層管理,有系統層,執行庫依賴層等等,可以一層接一層進行增量式掛載疊加。啟動容器的時候通過 UnionFS 把相關的層掛載到一個目錄,作為容器的根 rootfs。

藉助於 UnionFS,容器內部的更改都被儲存到了最上面的讀寫層,而其他層都是隻讀的,這樣中間的只讀 rootfs 是可以被多個容器複用的。UnionFS 將檔案的更新掛載到老的檔案之上,而不去修改那些不更新的內容,這就意味著即使虛擬的檔案系統被反覆修改,也能保證宿主機空間佔用保持一個較低水平。

4. 衍生出的 Docker 概念

4.1 Docker 映象

我們將中間只讀的 rootfs 的集合稱為 Docker 映象,我們在後面的部分會講到,Docker 映象構建時,會一層層構建,前一層是後一層的基礎。每一層構建完就不會再發生改變,後一層上的任何改變只發生在自己這一層。UnionFS 使得映象的複用、定製變得更為容易。甚至可以用之前構建好的映象作為基礎層,然後進一步新增新的層,以定製自己所需的內容,構建新的映象。

4.2 Docker 容器

Docker 容器與我們之前的容器在本質上沒有區別,我們之前的容器更偏向抽象的技術概念,而受到在 Docker 管理約束的容器就是 Docker 容器,它會帶有 Docker 產品的一些特徵和功能。

Docker映象 和 Docker容器 的關係,就像是面向物件程式設計中的 類 和 例項 一樣,映象是靜態的定義,容器是映象執行時的實體。
從檔案系統來看,Docker容器比Docker映象多一層可讀寫的檔案系統掛載層,從生命週期來看,Docker容器可以被建立、啟動、停止、刪除、暫停等。

5. 小結

在 rootfs 的基礎上,Docker 公司創新性地提出了使用 UnionFS,多個增量 rootfs 聯合掛載一個完整 rootfs 的方案,通過“分層映象”的設計,圍繞 Docker 映象,大家甚至可以協同工作,再加上 Docker 官方提供的映象倉庫,進一步減少了共享映象的成本,這大大提高了開發部署的效率。