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
,因為dockerd
和containerd
在不同的掛載名稱空間中。
使用 zfs
儲存驅動程式配置 Docker
停止 Docker。
將
/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/*
在您的專用塊裝置上建立一個新的
zpool
,並將其掛載到/var/lib/docker/
。請確保您指定了正確的裝置,因為這是一個破壞性操作。此示例將兩個裝置新增到池中。$ sudo zpool create -f zpool-docker -m /var/lib/docker /dev/xvdf /dev/xvdg
該命令建立名為
zpool-docker
的zpool
。該名稱僅用於顯示,您可以使用不同的名稱。使用zfs list
檢查池是否已正確建立和掛載。$ sudo zfs list NAME USED AVAIL REFER MOUNTPOINT zpool-docker 55K 96.4G 19K /var/lib/docker
配置 Docker 以使用
zfs
。編輯/etc/docker/daemon.json
並將storage-driver
設定為zfs
。如果檔案之前是空的,現在它應該如下所示:{ "storage-driver": "zfs" }
儲存並關閉檔案。
啟動 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):快照的讀寫副本。用於儲存與上一層的差異。
建立克隆的過程:


- 從檔案系統建立一個只讀快照。
- 從快照建立一個可寫克隆。這包含了與父層的所有差異。
檔案系統、快照和克隆都從底層的 zpool
中分配空間。
磁碟上的映象和容器層
每個正在執行的容器的統一檔案系統都掛載在 /var/lib/docker/zfs/graph/
中的一個掛載點上。繼續閱讀以瞭解統一檔案系統是如何組成的。
映象分層和共享
映象的基礎層是一個 ZFS 檔案系統。每個子層都是基於其下一層 ZFS 快照的 ZFS 克隆。容器是基於其建立來源映象頂層 ZFS 快照的 ZFS 克隆。
下圖顯示瞭如何將一個基於兩層映象的執行中容器組合在一起。


當您啟動一個容器時,會按順序發生以下步驟:
映象的基礎層作為 ZFS 檔案系統存在於 Docker 主機上。
額外的映象層是託管其正下方映象層的資料集的克隆。
在圖中,“層 1”是透過對基礎層進行 ZFS 快照,然後從該快照建立一個克隆來新增的。該克隆是可寫的,並根據需要從 zpool 中消耗空間。快照是隻讀的,將基礎層維護為一個不可變物件。
當容器啟動時,會在映象上方新增一個可寫層。
在圖中,容器的讀寫層是透過對映象的頂層(層 1)進行快照並從該快照建立一個克隆來建立的。
當容器修改其可寫層的內容時,會為被更改的塊分配空間。預設情況下,這些塊的大小為 128k。
容器的讀寫如何與 zfs
協同工作
讀取檔案
每個容器的可寫層都是一個 ZFS 克隆,它與建立它的資料集(其父層的快照)共享所有資料。讀操作速度很快,即使讀取的資料來自很深的層。下圖說明了塊共享的工作原理:


寫入檔案
寫入新檔案:從底層的 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) 提供比旋轉磁碟更快的讀寫速度。
對寫入密集型工作負載使用卷:卷為寫入密集型工作負載提供最佳且最可預測的效能。這是因為它們繞過了儲存驅動程式,並且不會產生由精簡配置和寫時複製引入的任何潛在開銷。卷還有其他好處,例如允許您在容器之間共享資料,並且即使沒有正在執行的容器使用它們,它們也會持久存在。