Docker三種文件系統總結

概述

容器持久化,相比小夥伴都不陌生。通過Docker的volume,我們可以非常方便的實現容器數據的持久化存儲。但volume之下的文件系統,相比許多小夥伴並不是非常清楚。因而本文以Docker爲例,重點講述Docker底層所支持的三種文件系統。

首先在說清楚Docker文件系統的具體功能之前,我們需要先了解一下,什麼叫做聯合文件系統。

聯合文件系統(Union File System,Unionfs)是一種分層的輕量級文件系統,它可以把多個目錄內容聯合掛載到同一目錄下,從而形成一個單一的文件系統,這種特性可以讓使用者像是使用一個目錄一樣使用聯合文件系統。

對於Docker來說,聯合文件系統可以說是其鏡像和容器的基礎。聯文件系統可以使得Docker把鏡像做成分層結構,從而使得鏡像的每一層都可以被共享。從而節省大量的存儲空間。

聯合文件系統更多的是一種概念或者標準,真正實現聯合文件系統纔是關鍵,當前Docker中常見的聯合文件系統有三種:AUDFS、Devicemapper和OverlayFS。

AUFS

AUFS是如何存儲文件的?

AUFS 是聯合文件系統,意味着它在主機上使用多層目錄存儲,每一個目錄在 AUFS 中都叫作分支,而在 Docker 中則稱之爲層(layer),但最終呈現給用戶的則是一個普通單層的文件系統,我們把多層以單一層的方式呈現出來的過程叫作聯合掛載。

每一個鏡像層和容器層都是 /var/lib/docker 下的一個子目錄,鏡像層和容器層都在 aufs/diff 目錄下,每一層的目錄名稱是鏡像或容器的 ID 值,聯合掛載點在 aufs/mnt 目錄下,mnt 目錄是真正的容器工作目錄。

創建整個容器過程中,aufs文件夾的變化:

當一個鏡像未生成容器時:

  • diff文件夾:存儲鏡像內容,每一層都存儲在鏡像層ID命名的子文件夾中。
  • layers文件夾:存儲鏡像層關係的元數據,在diff文件夾下的每一個鏡像層在這裏都會有一個文件,文件的內容爲該層鏡像的父級鏡像的ID
  • mnt文件夾:聯合掛載點目錄,未生成容器時,該目錄爲空

當一個鏡像生成容器後,AUFS存儲結構會發生如下變化:

  • diff文件夾:當容器運行時會在difff文件夾下生成容器層
  • layers文件夾:增加容器相關的元數據
  • mnt文件夾:容器的聯合掛載點,這和容器中看到的文件內容一致

AUFS如何工作?

  1. 讀取文件:
    1. 文件在容器層中存在時:當文件存在於容器層時,直接從容器層讀取。
    2. 當文件在容器層中不存在時:當容器運行時需要讀取某個文件,如果容器層中不存在時,則從鏡像層查找該文件,然後讀取文件內容。
    3. 文件既存在於鏡像層,又存在於容器層:當我們讀取的文件既存在於鏡像層,又存在於容器層時,將會從容器層讀取該文件。
  2. 修改文件或者目錄
    1. 第一次修改文件:當我們第一次在容器中修改某個文件時,AUFS 會觸發寫時複製操作,AUFS 首先從鏡像層複製文件到容器層,然後再執行對應的修改操作。
    2. 刪除文件或目錄:當文件或目錄被刪除時,AUFS 並不會真正從鏡像中刪除它,因爲鏡像層是隻讀的,AUFS 會創建一個特殊的文件或文件夾,這種特殊的文件或文件夾會阻止容器的訪

Devicemapper

什麼是 Devicemapper ?

Devicemapper 是 Linux 內核提供的框架,從 Linux 內核 2.6.9 版本開始引入,Devicemapper 與 AUFS 不同,AUFS 是一種文件系統,而Devicemapper 是一種映射塊設備的技術框架。

Devicemapper 的工作機制主要圍繞三個核心概念。

  • 映射設備(mapped device):即對外提供的邏輯設備,它是由 Devicemapper 模擬的一個虛擬設備,並不是真正存在於宿主機上的物理設備。

  • 目標設備(target device):目標設備是映射設備對應的物理設備或者物理設備的某一個邏輯分段,是真正存在於物理機上的設備。

  • 映射表(map table):映射表記錄了映射設備到目標設備的映射關係,它記錄了映射設備在目標設備的起始地址、範圍和目標設備的類型等變量。

映射設備通過映射表關聯到具體的物理目標設備。事實上,映射設備不僅可以通過映射表關聯到物理目標設備,也可以關聯到虛擬目標設備,然後虛擬目標設備再通過映射表關聯到物理目標設備。

Devicemapper 如何實現鏡像分層與共享?

Devicemapper 使用專用的塊設備實現鏡像的存儲,並且像 AUFS 一樣使用了寫時複製的技術來保障最大程度節省存儲空間,所以 Devicemapper 的鏡像分層也是依賴快照來是實現的。

Devicemapper 的每一鏡像層都是其下一層的快照,最底層的鏡像層是我們的瘦供給池,通過這種方式實現鏡像分層有以下優點:

  • 相同的鏡像層,僅在磁盤上存儲一次。例如,我有 10 個運行中的 busybox 容器,底層都使用了 busybox 鏡像,那麼 busybox 鏡像只需要在磁盤上存儲一次即可。
  • 快照是寫時複製策略的實現,也就是說,當我們需要對文件進行修改時,文件纔會被複制到讀寫層。
  • 相比對文件系統加鎖的機制,Devicemapper 工作在塊級別,因此可以實現同時修改和讀寫層中的多個塊設備,比文件系統效率更高。

當我們需要讀取數據時,如果數據存在底層快照中,則向底層快照查詢數據並讀取。當我們需要寫數據時,則向瘦供給池動態申請存儲空間生成讀寫層,然後把數據複製到讀寫層進行修改。Devicemapper 默認每次申請的大小是 64K 或者 64K 的倍數,因此每次新生成的讀寫層的大小都是 64K 或者 64K 的倍數。

OverlayFS

OverlayFS 的發展分爲兩個階段。2014 年,OverlayFS 第一個版本被合併到 Linux 內核 3.18 版本中,此時的 OverlayFS 在 Docker 中被稱爲overlay文件驅動。由於第一版的overlay文件系統存在很多弊端(例如運行一段時間後Docker 會報 "too many links problem" 的錯誤), Linux 內核在 4.0 版本對overlay做了很多必要的改進,此時的 OverlayFS 被稱之爲overlay2。

overlay2 工作原理

overlay2 和 AUFS 類似,它將所有目錄稱之爲層(layer),overlay2 的目錄是鏡像和容器分層的基礎,而把這些層統一展現到同一的目錄下的過程稱爲聯合掛載(union mount)。overlay2 把目錄的下一層叫作lowerdir,上一層叫作upperdir,聯合掛載後的結果叫作merged。

overlay2 如何讀取、修改文件?

讀取文件:

容器內進程讀取文件分爲以下三種情況。

  • 文件在容器層中存在:當文件存在於容器層並且不存在於鏡像層時,直接從容器層讀取文件;
  • 當文件在容器層中不存在:當容器中的進程需要讀取某個文件時,如果容器層中不存在該文件,則從鏡像層查找該文件,然後讀取文件內容;
  • 文件既存在於鏡像層,又存在於容器層:當我們讀取的文件既存在於鏡像層,又存在於容器層時,將會從容器層讀取該文件。

修改文件或目錄

overlay2 對文件的修改採用的是寫時複製的工作機制,這種工作機制可以最大程度節省存儲空間。具體的文件操作機制如下。

  • 第一次修改文件:當我們第一次在容器中修改某個文件時,overlay2 會觸發寫時複製操作,overlay2 首先從鏡像層複製文件到容器層,然後在容器層執行對應的文件修改操作。
  • 刪除文件或目錄:當文件或目錄被刪除時,overlay2 並不會真正從鏡像中刪除它,因爲鏡像層是隻讀的,overlay2 會創建一個特殊的文件或目錄,這種特殊的文件或目錄會阻止容器的訪問。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章