1. 程式人生 > >深入理解overlayfs(一):初識

深入理解overlayfs(一):初識

Overlayfs是一種類似aufs的一種堆疊檔案系統,於2014年正式合入Linux-3.18主線核心,目前其功能已經基本穩定(雖然還存在一些特性尚未實現)且被逐漸推廣,特別在容器技術中更是勢頭難擋。本系列博文將首先介紹overlayfs的基本概念和應用場景,然後通過若干例項描述它的使用方式,最後從原始碼角度結合Linux VFS Layer和Ext4fs連通分析overlayfs的實現。本文先來大致認識一下什麼是Overlayfs,它有什麼應用場景和使用限制。

核心版本:Linux-4.13.y

 

Overlayfs概述

基本概念

Overlayfs是一種堆疊檔案系統,它依賴並建立在其它的檔案系統之上(例如ext4fs和xfs等等),並不直接參與磁碟空間結構的劃分,僅僅將原來底層檔案系統中不同的目錄進行“合併”,然後向用戶呈現。因此對於使用者來說,它所見到的overlay檔案系統根目錄下的內容就來自掛載時所指定的不同目錄的“合集”。見圖1。

圖1 Overlayfs基本結構

其中lower dirA / lower dirB目錄和upper dir目錄為來自底層檔案系統的不同目錄,使用者可以自行指定,內部包含了使用者想要合併的檔案和目錄,merge dir目錄為掛載點。當檔案系統掛載後,在merge目錄下將會同時看到來自各lower和upper目錄下的內容,並且使用者也無法(無需)感知這些檔案分別哪些來自lower dir,哪些來自upper dir,使用者看見的只是一個普通的檔案系統根目錄而已(lower dir可以有多個也可以只有一個)。

雖然overlayfs將不同的各層目錄進行合併,但是upper dir和各lower dir這幾個不同的目錄並不完全等價,存在層次關係。首先當upper dir和lower dir兩個目錄存在同名檔案時,lower dir的檔案將會被隱藏,使用者只能看見來自upper dir的檔案,然後各個lower dir也存在相同的層次關係,較上層遮蔽叫下層的同名檔案。除此之外,如果存在同名的目錄,那就繼續合併(lower dir和upper dir合併到掛載點目錄其實就是合併一個典型的例子)。

各層目錄中的upper dir是可讀寫的目錄,當用戶通過merge dir向其中一個來自upper dir的檔案寫入資料時,那資料將直接寫入upper dir下原來的檔案中,刪除檔案也是同理;而各lower dir則是隻讀的,在overlayfs掛載後無論如何操作merge目錄中對應來自lower dir的檔案或目錄,lower dir中的內容均不會發生任何的改變(理論設計如此,但實際在一些極端場景存在偏差,後面我會詳細介紹)。既然lower dir是隻讀的,那當用戶想要往來自lower層的檔案新增或修改內容時,overlayfs首先會的拷貝一份lower dir中的檔案副本到upper dir中,後續的寫入和修改操作將會在upper dir下的copy-up的副本檔案中進行,lower dir原檔案被隱藏。

以上就是overlayfs最基本的特性,簡單的總結為以下3點:(1)上下層同名目錄合併;(2)上下層同名檔案覆蓋;(3)lower dir檔案寫時拷貝。這三點對使用者都是不感知的。

 

應用

基本瞭解overlayfs的基本特性以後,來了解overlayfs特性所帶來的好處和應用場景。在實際的使用中,我們可能會存在以下的多使用者複用共享檔案和目錄的場景。見圖2。

圖2 複用共享目錄檔案

在同一個裝置上,使用者A和使用者B有一些共同使用的共享檔案(例如執行程式所依賴的動態連結庫等),一般是隻讀的;同時也有自己的私有檔案(例如系統配置檔案等),往往是需要能夠寫入修改的;最後即使使用者A修改了被共享的檔案也不會影響到使用者B。

對於以上的需求場景,我們並不希望每個使用者都有一份完全一樣的檔案副本,因為這樣不僅帶來空間的浪費也會影響效能,因此overlayfs是一個較為完美的解決方案。我們將這些共享的檔案和目錄所在的目錄設定為lower dir (1~n),將使用者私有的檔案和目錄所在的目錄設定為upper dir,然後掛載到使用者指定的掛載點,這樣即能夠保證前面列出的3點需求,同時也能夠保證使用者A和B獨有的目錄樹結構。最後最為關鍵的是使用者A和使用者B在各自掛載目錄下看見的共享檔案其實是同一個檔案,這樣磁碟空間的節省自是不必說了,還有就是共享同一份cache而減少記憶體的使用和提高訪問效能,因為只要cache不被回收,只需某個使用者首次訪問時建立cache,後續其他所有使用者都可以通過訪問cache來提高IO效能。

上面說的這種使用場景在容器技術中應用最為廣泛,下面以docker容器為例來介紹overlay的兩種應用方式:Overlay和Overlay2.

Docker容器將映象層(image layer)作為lower dir,將容器層(container layer)作為upper dir,最後掛載到容器merge掛載點,即容器的根目錄下。遺憾的是,早期核心中的overlayfs並不支援多lower layer,在Linux-4.0以後的核心版本中才陸續支援完善。而容器中可能存在多層映象,所以出現了兩種overlayfs的掛載方式,早期的overlay不使用多lower layer的方式掛載而overlay2則使用該方式掛載。

1. Overlay Driver

Overlay掛載方式如下。見圖3(該圖引用自Miklos Szeredi的《overlayfs and containers》2017 linux核心大會演講材料)。

圖3 Overlay Driver

本圖黃色框中的部分是映象層和容器層的組織方式,各個映象層中,每下一層中的檔案以硬連結的方式出現在它的上一層中,以此類推,最終掛載overlayfs的lower dir為最上層映象層目錄imager layer N。與此同時,容器的writable dir作為upper dir,掛載成為容器的rootfs。本圖中雖然只描述了一個容器的掛載方式,但是其他容器也類似,映象層lower dir N共享,只是各個容器的upper dir不同而已。

2. Overlay2 Driver

Overlay2掛載方式如下。見圖4(該圖引用自Miklos Szeredi的《overlayfs and containers》2017 linux核心大會演講材料)。

圖4 Overlay2 Driver

Overlay2的掛載方式比Overlay的要簡單許多,它基於核心overlayfs的Multiple lower layers特性實現,不在需要硬連結,直接將映象層的各個目錄設定為overlayfs的各個lower layer即可(Overlayfs最多支援500層lower dir),對比Overlay Driver將減少inode的使用。

 

注意事項

儘管Overlayfs看起來是這麼的優秀,但是當前它還並不是那麼的完美,依然存在一些缺點和使用限制(還沒有完全支援POSIX標準),這裡簡單列出一些,先認識一下,以後遇到也能心中有數:

0. Mount Overlayfs之後就不允許在對原lower dir和upper dir進行操作

當我們掛載完成overlayfs以後,對檔案系統的任何操作都只能在merge dir中進行,使用者不允許再直接或間接的到底層檔案系統的原始lower dir或upper dir目錄下修改檔案或目錄,否則可能會出現一些無法預料的後果(kernel crash除外)。

1. Copy-up

Overlayfs的lower layer檔案寫時複製機制讓某一個使用者在修改來自lower層的檔案不會影響到其他使用者(容器),但是這個檔案的複製動作會顯得比較慢,後面我們會看到為了保證檔案系統的一致性,這個copy-up實現包含了很多步驟,其中最為耗時的就是檔案資料塊的複製和fsync同步。使用者在修改檔案時,如果檔案較小那可能不一定能夠感受出來,但是當檔案比較大或一次對大量的小檔案進行修改,那耗時將非常可觀。雖然自Linux-4.11起核心引入了“concurrent copy up”特性來提高copy-up的並行性,但是對於大檔案也還是沒有明顯的效果。不過幸運的是,如果底層的檔案系統支援reflink這樣的延時拷貝技術(例如xfs)那就不存在這個問題了。

2. Rename directory(POSIX標準支援問題)

如果Overlayfs的某一個目錄是單純來自lower layer或是lower layer和upper layer合併的,那預設情況下,使用者無法對該目錄執行rename系統呼叫,否則會返回-EXDEV錯誤。不過你會發現通過mv命令重新命名該目錄依然可以成功,那是因為mv命令的實現對rename系統呼叫的-EXDEV錯誤進行規避(這當然是有缺點的,先暫不展開)。在Linux-4.10起核心引入了“redirect dir”特性來修復這個問題,為此引入了一個核心選項:CONFIG_OVERLAY_FS_REDIRECT_DIR,使用者想要支援該特性可以在核心中開啟這個選項,否則就應避免對這兩類目錄使用rename系統呼叫。

3. Hard link break(POSIX標準支援問題)

該問題源自copy-up機制,當lower dir目錄中某個檔案擁有多個硬連結時,若使用者在merge layer對其中一個寫入了一些資料,那將觸發copy-up,由此該檔案將拷貝到upper dir,那麼和原始檔案的hard link也就斷開了,變成了一個單獨的檔案,使用者在merge layer通過stat和ls命令能夠直接看到這個變化。在Linux-4.13起核心引入了“index feature”來修復這個問題,同樣引入了一個核心選項:CONFIG_OVERLAY_FS_INDEX,使用者想要修復該問題可以開啟這個選項,不過該選項不具有向前相容性,請謹慎使用。

4. Unconstant st_dev&st_ino(POSIX標準支援問題)

該問題同樣源自copy-up機制,當原來在lower dir中的檔案觸發了copy-up以後,那使用者在merge layer見到了將是來自upper dir的新檔案,那也就意味著它倆的inode是不同的,雖然inode中很多的attr和xattr是可以copy的,但是st_dev和st_ino這兩個欄位卻具有唯一性,是不可以複製的,所以使用者可以通過ls和stat命令看到的該欄位將發生變化。在Linux-4.12和Linux-4.13分別進行了部分的修復,目前在lower dir和upper dir都在同一個檔案系統掛載點的場景下,問題已經修復,但lower dir和upper dir若來自不同的檔案系統,問題依然存在。

5. File descriptor change(POSIX標準支援問題)

該問題也同樣源自copy-up機制,使用者在檔案發生copy-up之前以只讀方式open檔案(這操作不會觸發copy-up)得到的檔案描述符fd1和copy-up之後open檔案得到的檔案描述符fd2指向不同的檔案,使用者通過fd2寫入的新資料,將無法從fd1中獲取到,只能重新open一個新的fd。該問題目前社群主線核心依然存在,暫未修復。

以上這6點列出了目前Overlayfs的主要問題和限制,將在後文中陸續展開。社群為了讓Overlayfs能夠更加向支援Posix標準的檔案系統靠攏,做出了很多的努力,後續將進一步修復上面提到且未修復的問題,還會增加對NFS Export、freeze snapshots、overlayfs snapshots等的支援,進一步完善overlayfs。

 

小結

Overlayfs在以它特有的機制已經使用的越來越廣泛,在Docker容器技術中以它優異的效能將會漸漸成為首選。不過overlayfs也尚存諸多限制,到目前為止,它還不是一個完全符合Posix規範的檔案系統,但社群的開發人員們一直在努力完善,相信不久的將來我們會看到一個非常易用且成熟的Overlayfs。

 

參考文獻

1. <overlayfs and containers> by Miklos Szeredi.

2. Documentation/filesystems/overlayfs.txt

轉自:

https://blog.csdn.net/luckyapple1028/article/details/77916194