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 並將其命名為 zpool-docker。名稱僅用於顯示目的,您可以使用不同的名稱。使用 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"]
}

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

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

zfs 儲存驅動程式的運作方式

ZFS 使用以下物件

  • **檔案系統**:精簡佈建,空間按需從 zpool 分配。
  • **快照**:檔案系統的唯讀空間高效能時間點副本。
  • **複製**:快照的讀寫副本。用於儲存與上一層的差異。

建立複製的過程

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) 提供比旋轉式硬碟更快的讀取和寫入速度。

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