ZFS 儲存驅動程式

ZFS 是下一代檔案系統,支援許多高階儲存技術,如卷管理、快照、校驗和、壓縮和去重、複製等。

它由 Sun Microsystems(現為 Oracle Corporation)建立,並在 CDDL 許可下開源。由於 CDDL 和 GPL 之間的許可不相容,ZFS 不能作為 Linux 核心主線的一部分發布。但是,ZFS On Linux (ZoL) 專案提供了一個樹外核心模組和使用者空間工具,可以單獨安裝。

ZFS on Linux (ZoL) 移植版是健康且成熟的。但是,目前不建議在生產環境中使用 zfs Docker 儲存驅動程式,除非您在 Linux 上有豐富的 ZFS 經驗。

注意

Linux 平臺上還有一個 ZFS 的 FUSE 實現。不建議使用這個。原生的 ZFS 驅動程式 (ZoL) 經過更多測試,效能更好,使用更廣泛。本文件的其餘部分指的是原生的 ZoL 移植版。

先決條件

  • ZFS 需要一個或多個專用的塊裝置,最好是固態硬碟 (SSD)。
  • /var/lib/docker/ 目錄必須掛載在 ZFS 格式的檔案系統上。
  • 更改儲存驅動程式會使您已建立的任何容器在本地系統上無法訪問。使用 docker save 儲存容器,並將現有映象推送到 Docker Hub 或私有倉庫,這樣您就不需要稍後重新建立它們。
注意

無需使用 MountFlags=slave,因為 dockerdcontainerd 在不同的掛載名稱空間中。

使用 zfs 儲存驅動程式配置 Docker

  1. 停止 Docker。

  2. /var/lib/docker/ 的內容複製到 /var/lib/docker.bk,並刪除 /var/lib/docker/ 的內容。

    $ sudo cp -au /var/lib/docker /var/lib/docker.bk
    
    $ sudo rm -rf /var/lib/docker/*
    
  3. 在您的專用塊裝置上建立一個新的 zpool,並將其掛載到 /var/lib/docker/。請確保您指定了正確的裝置,因為這是一個破壞性操作。此示例將兩個裝置新增到池中。

    $ sudo zpool create -f zpool-docker -m /var/lib/docker /dev/xvdf /dev/xvdg
    

    該命令建立名為 zpool-dockerzpool。該名稱僅用於顯示,您可以使用不同的名稱。使用 zfs list 檢查池是否已正確建立和掛載。

    $ sudo zfs list
    
    NAME           USED  AVAIL  REFER  MOUNTPOINT
    zpool-docker    55K  96.4G    19K  /var/lib/docker
    
  4. 配置 Docker 以使用 zfs。編輯 /etc/docker/daemon.json 並將 storage-driver 設定為 zfs。如果檔案之前是空的,現在它應該如下所示:

    {
      "storage-driver": "zfs"
    }

    儲存並關閉檔案。

  5. 啟動 Docker。使用 docker info 驗證儲存驅動程式是否為 zfs

    $ sudo docker info
      Containers: 0
       Running: 0
       Paused: 0
       Stopped: 0
      Images: 0
      Server Version: 17.03.1-ce
      Storage Driver: zfs
       Zpool: zpool-docker
       Zpool Health: ONLINE
       Parent Dataset: zpool-docker
       Space Used By Parent: 249856
       Space Available: 103498395648
       Parent Quota: no
       Compression: off
    <...>
    

管理 zfs

增加正在執行的裝置的容量

要增加 zpool 的大小,您需要向 Docker 主機新增一個專用的塊裝置,然後使用 zpool add 命令將其新增到 zpool 中:

$ sudo zpool add zpool-docker /dev/xvdh

限制容器的可寫儲存配額

如果您想在每個映象/資料集的基礎上實施配額,可以設定 size 儲存選項來限制單個容器可用於其可寫層的空間量。

編輯 /etc/docker/daemon.json 並新增以下內容:

{
  "storage-driver": "zfs",
  "storage-opts": ["size=256M"]
}

請參閱 守護程序參考文件 中每個儲存驅動程式的所有儲存選項

儲存並關閉檔案,然後重新啟動 Docker。

zfs 儲存驅動程式的工作原理

ZFS 使用以下物件:

  • 檔案系統 (filesystems):精簡配置,按需從 zpool 分配空間。
  • 快照 (snapshots):檔案系統的只讀、空間高效的時間點副本。
  • 克隆 (clones):快照的讀寫副本。用於儲存與上一層的差異。

建立克隆的過程:

ZFS snapshots and clones
  1. 從檔案系統建立一個只讀快照。
  2. 從快照建立一個可寫克隆。這包含了與父層的所有差異。

檔案系統、快照和克隆都從底層的 zpool 中分配空間。

磁碟上的映象和容器層

每個正在執行的容器的統一檔案系統都掛載在 /var/lib/docker/zfs/graph/ 中的一個掛載點上。繼續閱讀以瞭解統一檔案系統是如何組成的。

映象分層和共享

映象的基礎層是一個 ZFS 檔案系統。每個子層都是基於其下一層 ZFS 快照的 ZFS 克隆。容器是基於其建立來源映象頂層 ZFS 快照的 ZFS 克隆。

下圖顯示瞭如何將一個基於兩層映象的執行中容器組合在一起。

ZFS pool for Docker container

當您啟動一個容器時,會按順序發生以下步驟:

  1. 映象的基礎層作為 ZFS 檔案系統存在於 Docker 主機上。

  2. 額外的映象層是託管其正下方映象層的資料集的克隆。

    在圖中,“層 1”是透過對基礎層進行 ZFS 快照,然後從該快照建立一個克隆來新增的。該克隆是可寫的,並根據需要從 zpool 中消耗空間。快照是隻讀的,將基礎層維護為一個不可變物件。

  3. 當容器啟動時,會在映象上方新增一個可寫層。

    在圖中,容器的讀寫層是透過對映象的頂層(層 1)進行快照並從該快照建立一個克隆來建立的。

  4. 當容器修改其可寫層的內容時,會為被更改的塊分配空間。預設情況下,這些塊的大小為 128k。

容器的讀寫如何與 zfs 協同工作

讀取檔案

每個容器的可寫層都是一個 ZFS 克隆,它與建立它的資料集(其父層的快照)共享所有資料。讀操作速度很快,即使讀取的資料來自很深的層。下圖說明了塊共享的工作原理:

ZFS block sharing

寫入檔案

寫入新檔案:從底層的 zpool 按需分配空間,並將塊直接寫入容器的可寫層。

修改現有檔案:僅為已更改的塊分配空間,並使用寫時複製 (CoW) 策略將這些塊寫入容器的可寫層。這最小化了層的大小並提高了寫入效能。

刪除檔案或目錄:

  • 當您刪除存在於較低層中的檔案或目錄時,ZFS 驅動程式會在容器的可寫層中遮蔽該檔案或目錄的存在,即使該檔案或目錄仍然存在於較低的只讀層中。
  • 如果您在容器的可寫層內建立然後刪除一個檔案或目錄,這些塊將被 zpool 回收。

ZFS 和 Docker 效能

有幾個因素會影響使用 zfs 儲存驅動程式的 Docker 效能。

  • 記憶體:記憶體對 ZFS 效能有重大影響。ZFS 最初是為擁有大量記憶體的大型企業級伺服器設計的。

  • ZFS 功能:ZFS 包括一個去重功能。使用此功能可能會節省磁碟空間,但會佔用大量記憶體。建議您對與 Docker 一起使用的 zpool 停用此功能,除非您正在使用 SAN、NAS 或其他硬體 RAID 技術。

  • ZFS 快取:ZFS 將磁碟塊快取在一個稱為自適應替換快取 (ARC) 的記憶體結構中。ZFS 的*單副本 ARC* 功能允許一個塊的單個快取副本被多個克隆共享。透過此功能,多個正在執行的容器可以共享一個快取塊的單個副本。此功能使 ZFS 成為 PaaS 和其他高密度用例的良好選擇。

  • 碎片化:碎片化是像 ZFS 這樣的寫時複製檔案系統的自然副產品。ZFS 透過使用 128k 的小塊大小來緩解這個問題。ZFS 意圖日誌 (ZIL) 和寫操作的合併(延遲寫入)也有助於減少碎片化。您可以使用 zpool status 來監控碎片化情況。但是,除了重新格式化和恢復檔案系統外,沒有辦法對 ZFS 進行碎片整理。

  • 使用 Linux 的原生 ZFS 驅動程式:由於效能較差,不建議使用 ZFS FUSE 實現。

效能最佳實踐

  • 使用快速儲存:固態硬碟 (SSD) 提供比旋轉磁碟更快的讀寫速度。

  • 對寫入密集型工作負載使用卷:卷為寫入密集型工作負載提供最佳且最可預測的效能。這是因為它們繞過了儲存驅動程式,並且不會產生由精簡配置和寫時複製引入的任何潛在開銷。卷還有其他好處,例如允許您在容器之間共享資料,並且即使沒有正在執行的容器使用它們,它們也會持久存在。