UnionFS 與 Docker
我們自己在上一節(jié)留下了不少問(wèn)題,在自制 rootfs 有很多不完善的地方,在 Docker 產(chǎn)品的方面,就對(duì)這些部分進(jìn)行了補(bǔ)足, 解決的方案,基本都是圍繞 UnionFS (聯(lián)合文件系統(tǒng))展開的,本節(jié)我們會(huì)講講 UnionFS 和它在 Docker中 的應(yīng)用。
1. 什么是文件系統(tǒng)
計(jì)算機(jī)的文件系統(tǒng)是一種存儲(chǔ)和組織計(jì)算機(jī)數(shù)據(jù)的方法,它使得對(duì)其訪問(wèn)和查找變得容易,文件系統(tǒng)使用文件和樹形目錄的抽象邏輯概念代替了硬盤和光盤等物理設(shè)備使用數(shù)據(jù)塊的概念,用戶使用文件系統(tǒng)來(lái)保存數(shù)據(jù)不必關(guān)心數(shù)據(jù)實(shí)際保存在硬盤(或者光盤)的地址為多少的數(shù)據(jù)塊上,只需要記住這個(gè)文件的所屬目錄和文件名。在寫入新數(shù)據(jù)之前,用戶不必關(guān)心硬盤上的那個(gè)塊地址沒有被使用,硬盤上的存儲(chǔ)空間管理(分配和釋放)功能由文件系統(tǒng)自動(dòng)完成,用戶只需要記住數(shù)據(jù)被寫入到了哪個(gè)文件中。
一句話總結(jié),文件系統(tǒng)是一套實(shí)現(xiàn)了數(shù)據(jù)的存儲(chǔ)、分級(jí)組織、訪問(wèn)和獲取等操作的抽象數(shù)據(jù)類型。
2. 什么是 UnionFS
聯(lián)合文件系統(tǒng)(Union File System):2004 年由紐約州立大學(xué)開發(fā),它可以把多個(gè)目錄內(nèi)容聯(lián)合掛載到同一個(gè)目錄下,而目錄的物理位置是分開的。UnionFS可以把只讀和可讀寫文件系統(tǒng)合并在一起,具有寫時(shí)復(fù)制功能,允許只讀文件系統(tǒng)的修改可以保存到可寫文件系統(tǒng)當(dāng)中。
目前有多種文件系統(tǒng)可以被當(dāng)作聯(lián)合文件系統(tǒng),CentOS8 使用的是 overlay2,下面,我們嘗試著掛載一個(gè) overlay2 文件系統(tǒng)。
在 /root/test
目錄下,建立一個(gè)unionfs 目錄,它的目錄結(jié)構(gòu)如下(a,b,c是文件,其他都是目錄):
unionfs
├── lower1
│ ├── a
│ └── b
├── lower2
│ └── a
├── merged
├── upper
│ └── c
└── work
進(jìn)入 unionfs 目錄,使用 mount 命令掛載:
cd unionfs
mount -t overlay overlay -o lowerdir=lower1:lower2,upperdir=upper,workdir=work merged
如上,掛載了一個(gè)名為 overlay 的 overlay2 類型的文件系統(tǒng),掛載點(diǎn)為 merged 目錄。
查看 merged 目錄的層次:
[root@centos8 unionfs]# tree merged
merged
├── a
├── b
└── c
查看這些文件的內(nèi)容:
[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
的層次結(jié)構(gòu)。
我們按照如下操作來(lái)驗(yàn)證 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
可以看到對(duì) merged 目錄的改動(dòng)同步至 upper 目錄中,并不會(huì)影響到 lower 目錄。
3. Docker 如何使用 UnionFS?
Docker 的官方文檔中有一張圖片,很好地展示了 Docker 使用 UnionFS 搭建的分層結(jié)構(gòu)的狀態(tài)。
圖中的容器是運(yùn)行在 debian 容器環(huán)境中的 apache 網(wǎng)頁(yè)應(yīng)用,這個(gè)環(huán)境還提供了 emacs 編輯器功能。
將之前我們自己構(gòu)建的 rootfs 與上面這張圖片對(duì)比,會(huì)發(fā)現(xiàn)我們將所有系統(tǒng)文件、運(yùn)行庫(kù)文件和上層應(yīng)用,都放到了一個(gè) rootfs 里面,這樣做缺乏靈活性,增大了維護(hù)的復(fù)雜度。而 Docker 引入了層(layer)的概念,將 rootfs 的內(nèi)容進(jìn)行了分層管理,有系統(tǒng)層,運(yùn)行庫(kù)依賴層等等,可以一層接一層進(jìn)行增量式掛載疊加。啟動(dòng)容器的時(shí)候通過(guò) UnionFS 把相關(guān)的層掛載到一個(gè)目錄,作為容器的根 rootfs。
借助于 UnionFS,容器內(nèi)部的更改都被保存到了最上面的讀寫層,而其他層都是只讀的,這樣中間的只讀 rootfs 是可以被多個(gè)容器復(fù)用的。UnionFS 將文件的更新掛載到老的文件之上,而不去修改那些不更新的內(nèi)容,這就意味著即使虛擬的文件系統(tǒng)被反復(fù)修改,也能保證宿主機(jī)空間占用保持一個(gè)較低水平。
4. 衍生出的 Docker 概念
4.1 Docker 鏡像
我們將中間只讀的 rootfs 的集合稱為 Docker 鏡像,我們?cè)诤竺娴牟糠謺?huì)講到,Docker 鏡像構(gòu)建時(shí),會(huì)一層層構(gòu)建,前一層是后一層的基礎(chǔ)。每一層構(gòu)建完就不會(huì)再發(fā)生改變,后一層上的任何改變只發(fā)生在自己這一層。UnionFS 使得鏡像的復(fù)用、定制變得更為容易。甚至可以用之前構(gòu)建好的鏡像作為基礎(chǔ)層,然后進(jìn)一步添加新的層,以定制自己所需的內(nèi)容,構(gòu)建新的鏡像。
4.2 Docker 容器
Docker 容器與我們之前的容器在本質(zhì)上沒有區(qū)別,我們之前的容器更偏向抽象的技術(shù)概念,而受到在 Docker 管理約束的容器就是 Docker 容器,它會(huì)帶有 Docker 產(chǎn)品的一些特征和功能。
Docker鏡像 和 Docker容器 的關(guān)系,就像是面向?qū)ο蟪绦蛟O(shè)計(jì)中的 類 和 實(shí)例 一樣,鏡像是靜態(tài)的定義,容器是鏡像運(yùn)行時(shí)的實(shí)體。
從文件系統(tǒng)來(lái)看,Docker容器比Docker鏡像多一層可讀寫的文件系統(tǒng)掛載層,從生命周期來(lái)看,Docker容器可以被創(chuàng)建、啟動(dòng)、停止、刪除、暫停等。
5. 小結(jié)
在 rootfs 的基礎(chǔ)上,Docker 公司創(chuàng)新性地提出了使用 UnionFS,多個(gè)增量 rootfs 聯(lián)合掛載一個(gè)完整 rootfs 的方案,通過(guò)“分層鏡像”的設(shè)計(jì),圍繞 Docker 鏡像,大家甚至可以協(xié)同工作,再加上 Docker 官方提供的鏡像倉(cāng)庫(kù),進(jìn)一步減少了共享鏡像的成本,這大大提高了開發(fā)部署的效率。