Docker存儲驅動之ZFS簡介

ZFS是下一代的文件系統,支持了很多存儲高級特性,如卷管理、快照、和校驗、壓縮和重複刪除技術、拷貝等。
  ZFS由Sun公司創建,現屬於Oracle,ZFS是開源的,並基於CDDL license。因爲CDDL和GPL不兼容,ZFS不能加入Linux kernel主線。然而,ZFS On Linux(ZoL)項目提供kernel模塊和用戶空間程序,這些都可以單獨的安裝。
  ZFS on Linux(ZoL)是一項成熟的技術,但是,現在卻不建議在產品中使用zfs存儲驅動,當然,除非你對ZoL有着豐富的經驗。
  注意:在Linux平臺上,有ZFS的FUSE實現,它可以和Docker結合起來使用,但是卻不推薦這樣使用。原生的ZFS驅動(ZoL)被測試得更多,更有效率,也更廣泛地被使用。下面的內容也指的是原生的ZFS驅動。

鏡像分層和共享

  Docker的zfs存儲驅動使用了ZFS驅動的三個組件:
   ●文件系統
   ●快照
   ●克隆
  ZFS系統提供超配特性,通過按需分配操作從ZFS池(zpool)分配空間。快照和克隆是ZFS系統某個時間點的拷貝,較節省空間。快照是隻讀的,而克隆是讀寫的,克隆只能通過快照來創建。下圖顯示了它們之間這種簡單地關係。
  image
  圖中的實線顯示了創建了克隆的過程。第一步創建了一個文件系統的快照,第二步通過快照創建了一份克隆。虛線顯示了克隆、文件系統和快照之間的關係。這三個ZFS組件都從同一個下層的zpool申請空間。
  在Docker host上使用zfs存儲驅動。鏡像的基礎層就是一個ZFS文件系統,每個子層都是底層ZFS快照的一個ZFS克隆,容器就是一個ZFS克隆,它基於其鏡像最頂層的ZFS快照。所有的ZFS組件都從同一個zpool分配空間。下圖顯示了一個基於兩層鏡像的容器是如何使用這些ZFS組件的。
  image
  結合上圖,下面的過程解釋了鏡像是如何分層的,容器是如何創建的。
   ▶在Docker host中,鏡像的基礎層是一個ZFS文件系統。
   文件系統從zpool中消耗空間。
   ▶附加的鏡像層是其下層鏡像的克隆。
   圖中,“Layer 1”是通過創建基礎鏡像的ZFS快照,然後再通過快照創建克隆來實現的。克隆是可讀寫的,並且從zpool按需分配空間;而快照是隻讀的。
   ▶當容器啓動時,就會在鏡像層上附加一個可讀寫層。
   上圖中,製造了一個鏡像頂層的快照,然後再基於快照創建了一份克隆,而這份克隆就是容器的可讀寫層。
   如果需要改變容器,那麼久會從zpool按需分配空間給容器,ZFS默認會分配128K大小的塊。
  這種從只讀快照創建子層和容器的方法,使得鏡像作爲不可變對象來維護。

容器使用ZFS讀寫

  容器從zfs存儲驅動讀數據的過程非常簡單。新啓動的容器基於ZFS克隆,這份克隆從初始化開始就共享它底層的所有數據。這意味着使用zfs的讀操作非常快,即使正在讀的數據並沒有拷貝到容器。下圖顯示了數據塊的共享情況。
  image
  寫新數據是通過按需分配操作來完成的。每次要向容器的一個新區域寫數據時,就會從zpool中分配一個新塊,也就是說寫新數據時容器就會消耗額外的空間。分配給容器的新空間從底層的zpool分配。
  想更新容器的新數據,就得分配新空間給容器,並將這些改變的信息保存在新的塊中。原來的塊沒有改變,下面的鏡像依然是不可變的。

Docker中配置ZFS存儲驅動

  只有在/var/lib/docker被映射在一個ZFS文件系統上時,才能在docker host上使用zfs存儲驅動。本節將介紹如何在Ubuntu上安裝原生的ZFS on Linux(ZoL)。

準備

  如果你已經在Docker host上使用過Docker daemon,並且有一些想保存的鏡像,那麼在執行下面的步驟之前,你需要將這些鏡像保存到Docker Hub或者你的私有Docker鏡像倉庫中。
  停止Docker daemon。另外,確保你在/dev/xvdb(這個設備名可能根據你的OS環境而不同,你需要換成適合你自己的設備名)上有一個空閒塊設備。

在Ubuntu16.04 LTS上安裝ZFS

  1) 停止Docker daemon。

$ sudo systemctl stop docker.service

  2) 安裝zfs包。

 $ sudo apt-get install -y zfs

 Reading package lists... Done
 Building dependency tree
 <output truncated>

  3) 確認你的zfs模塊成功安裝並加載。

$ lsmod | grep zfs

 zfs                  2813952  3
 zunicode              331776  1 zfs
 zcommon                57344  1 zfs
 znvpair                90112  2 zfs,zcommon
 spl                   102400  3 zfs,zcommon,znvpair
 zavl                   16384  1 zfs

在Ubuntu 14.04 LTS上安裝ZFS

  1) 停止Docker daemon。

$ sudo systemctl stop docker.service

  2) 安裝software-properties-common包。

$ sudo apt-get install -y software-properties-common

Reading package lists... Done
Building dependency tree
<output truncated>

  3) 添加zfs-native包。

$ sudo add-apt-repository ppa:zfs-native/stable

The native ZFS filesystem for Linux. Install the ubuntu-zfs package.
<output truncated>
gpg: key F6B0FC61: public key "Launchpad PPA for Native ZFS for Linux" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
OK

  4) 獲取最新包的列表。

 $ sudo apt-get update

 Ign http://us-west-2.ec2.archive.ubuntu.com trusty InRelease
 Get:1 http://us-west-2.ec2.archive.ubuntu.com trusty-updates InRelease [64.4 kB]
 <output truncated>
 Fetched 10.3 MB in 4s (2,370 kB/s)
 Reading package lists... Done

  5) 安裝ubuntu-zfs包。

$ sudo apt-get install -y ubuntu-zfs

Reading package lists... Done
Building dependency tree
<output truncated>

  6) 加載zfs模塊。

$ sudo modprobe zfs

  7) 確認模塊是否正確加載。

$ lsmod | grep zfs

zfs                  2768247  0
zunicode              331170  1 zfs
zcommon                55411  1 zfs
znvpair                89086  2 zfs,zcommon
spl                    96378  3 zfs,zcommon,znvpair
zavl                   15236  1 zfs

在Docker中配置ZFS

  一旦安裝和加載了ZFS,就可以在Docker中配置ZFS了。
   1) 創建一個新的zpool。

$ sudo zpool create -f zpool-docker /dev/xvdb

   上面命令創建了一個名爲“zpool-docker”的zpool。這個名稱是隨意的。
   2) 檢查zpool是否存在。

$ sudo zfs list

NAME            USED  AVAIL    REFER  MOUNTPOINT
zpool-docker    55K   3.84G    19K    /zpool-docker

   3) 在/var/lib/docker上創建和映射一個新的ZFS文件系統。

$ sudo zfs create -o mountpoint=/var/lib/docker zpool-docker/docker

   4) 檢查前面的步驟是否正常工作。

$ sudo zfs list -t all

NAME                 USED  AVAIL  REFER  MOUNTPOINT
zpool-docker         93.5K  3.84G    19K  /zpool-docker
zpool-docker/docker  19K    3.84G    19K  /var/lib/docker

   可以看到,在/var/lib/docker上映射了一個ZFS文件系統,daemon啓動後會自動加載zfs存儲驅動。
   5) 啓動Docker daemon。

$ sudo service docker start

docker start/running, process 2315

   6) 確認daemon正在使用zfs存儲驅動。

$ sudo docker info

Containers: 0
Images: 0
Storage Driver: zfs
    Zpool: zpool-docker
    Zpool Health: ONLINE
    Parent Dataset: zpool-docker/docker
    Space Used By Parent: 27648
    Space Available: 4128139776
    Parent Quota: no
    Compression: off
    Execution Driver: native-0.2
[...]

Docker中的ZFS性能

  有以下一些因素會影響zfs存儲驅動在Docker中的性能。
   ●內存。內存對ZFS性能影響很大,因爲ZFS最初被設計成在擁有大量內存的Sun Solaris服務器上使用的。
   ●ZFS特性。使用ZFS特性,如重複刪除技術,會增加ZFS的內存使用。就內存使用和效率原因而言,建議關閉FS的重複刪除特性。
   ●ZFS緩存。ZFS將磁盤塊緩存在被稱作adaptive replacement cache(ARC)內存結構體中。ZFS的ARC單拷貝特性使得塊的單個緩存拷貝可以被多個文件系統的克隆共享,也就是說多個運行着的容器可以共享緩存塊的單個拷貝。這意味着對於PaaS或其他高密度用例來說,ZFS是一個不錯的選擇。
   ●存儲碎片。碎片是諸如ZFS這種copy-on-write文件系統的副產品。不過,ZFS寫128K的塊時,會分配slab(多個128K的塊)來進行CoW操作,從而嘗試減少存儲碎片。ZFS intent log(ZIL)和 coalescing of writes(delayed writes)也可以幫忙減少碎片。
   ●使用原生的Linux ZFS驅動。雖然Docker zfs存儲驅動支持ZFS FUSE實現,但在高性能場景下不建議使用ZFS FUSE。原生的ZFS Linux驅動有着更好的性能。
   ●使用SSD。爲了更好的性能,可以使用更快的存儲介質(如SSD)。不過,如果你的SSD存儲很有限,那麼建議你關閉SSD上的ZIL特性。

限制容器寫的存儲配額

  如果你像實現對每個鏡像的存儲配額,那麼你可以使用–storage-opt選項。

--storage-opt size=256M

  它會限制容器可以寫/修改的空間大小(需要ZFS使能特性available)。也就是說,如果你有一個256MB大小的鏡像,並且使用了前面的參數選項,那麼你對應的容器就有512MB的大小,其中有256MB是可用的。

發佈了122 篇原創文章 · 獲贊 55 · 訪問量 54萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章