Docker用户指南(9) – ZFS存储驱动实践

ZFS是支持许多高级存储技术(如卷管理,快照,检验和,压缩,去重,复制等)的下一代文件系统。由Microsystems(现在是Oracle Corporation)创建,以CDDL许多可证开源。由于CDDL和GPL的许可证不兼容,ZFS无法作为Linux内核主线的一部分提供。不过,Linux的ZFS(ZoL)提供了在内核树之外的模块并且可以单独安装用户空间工具。
Linux的ZFS(ZoL)目前已经是稳定成熟了。不过,除非你在Linux上拥有丰富的ZFS使用经验,否则不建议目前在生产环境使用zfs Docker存储驱动。

镜像分层和ZFS共享

Docker zfs存储驱动大量使用三个ZFS数据集:

  • 文件系统
  • 快照
  • 克隆
  • ZFS文件系统是精简置备的(thinly provisioned)并通过按需分配操作从一个ZFS池(zpool)分配空间。快照和克隆是节省空间的某个时间点的ZFS文件系统副本。快照是只读的。克隆(clones)是可读写的。克隆只能从快照创建。它们简单的关系如下图.

    上图中的实线部分是创建一个克隆的过程。步骤1创建文件系统的一个快照,步骤2是从快照创建克隆。虚线表示克隆和文件系统之间的关系,通过快照,所有三个ZFS数据集从相同的底层zpool中申请空间。
    在使用zfs存储驱动的Docker主机上,一个镜像的base层是一个ZFS文件系统。每一个子层是基于该层下面层的快照的克隆。一个容器是基于从其创建的镜像顶层的快照的ZFS克隆。所有的ZFS数据集从同一个zpool申请空间。下图显示zpool,三个数据集,一个基于两层镜像的容器的关系。

    下面的过程解释了镜像是如何分层的和如何创建容器。该过程基于上图。
    1.镜像的base数据层作为ZFS文件系统存在于Docker主机上。
    此文件系统消耗用于在/var/lib/docker上创建Docker主机的本地存储区的zpool空间。
    2.其它的镜像数据层是在其下方的镜像层的数据集的克隆。
    在这个图中,”Layer 1″是通过创建base层的一个ZFS快照,然后从这个快照创建一个克隆增加。这个克隆是可写的并消耗从zpool按需分配的空间。快照是只读的,将base层保持为一个不可变的对象。
    3.当一个容器创建后,一个可读写的数据层增加在镜像的上面。在上图中,这个容器的可读写数据层是通过创建镜像顶层(Layer1)的快照,然后从这个快照创建一个克隆创建的。
    所有对容器的更改,将通过按需分配操作从zpool中分配空间。默认下,ZFS以128K大小的数据块分配空间。
    从只读快照创建子层和容器的此过程允许保持镜像为一个不可变对象。

    使用ZFS读写容器

    使用zfs存储驱动进行容器的读取是非常简单的。一个新创建的容器基于一个ZFS克隆。此克隆最初与从其创建的数据集共享其所有数据。这意味着使用zfs存储驱动的读操作是非常快的 – 即使要读取的数据还没有复制到容器中。下面显示这个数据块的分享。

    写入新数据到容器是通过按需分配操作完成。每次需要写数据到容器的新区域,一个新的数据块从zpool分配。这意味着写入新数据到容器的新区域将消耗额外的空间。从底层zpool分配新空间给容器(ZFS克隆)。
    更新容器存在的数据通过分配新数据块给容器克隆和存储更改的数据到这些新数据块完成。原始的数据块没有更改,允许底层镜像数据集保持不变。这与写入正常的ZFS文件系统相同,并且都执行了写时拷贝操作。

    配置Docker使用ZFS存储驱动

    zfs存储驱动只支持/var/lib/docker挂载为一个ZFS文件系统的Docker主机。本节介绍如何在Ubuntu 14.04系统上安装和配置原生Linux ZFS(ZoL)。

    先决条件

    如果你已经在你docker主机上使用docker daemon并且有你想保留的镜像,在执行下面的步骤之前先push它们到docker hub或你的私有docker registry。
    停止docker daemon。然后确保在/dev/xvdb有一个空闲的块设备。块设备的标识符可能与你的不同,请替换成你自己的。

    在Ubuntu 16.04 LTS安装ZFS

    1.先停止docker deamon。
    2.安装zfs软件包。

    1. $ sudo apt-get install -y zfs
    2.  
    3.  Reading package lists... Done
    4.  Building dependency tree
    5.  <output truncated>

    3.验证zfs模块是否已经正确加载。

    1. $ lsmod | grep zfs
    2.  
    3.  zfs                  2813952  3
    4.  zunicode              331776  1 zfs
    5.  zcommon                57344  1 zfs
    6.  znvpair                90112  2 zfs,zcommon
    7.  spl                   102400  3 zfs,zcommon,znvpair
    8.  zavl                   16384  1 zfs

    在Ubuntu 14.04安装ZFS

    1.先停止docker daemon。
    2.安装add-apt-repository命令依赖的software-properties-common软件。

    1. $ sudo apt-get install -y software-properties-common
    2.  
    3.  Reading package lists... Done
    4.  Building dependency tree
    5.  <output truncated>

    3.增加zfs-native软件包ppa源。

    1. $ sudo add-apt-repository ppa:zfs-native/stable
    2.  
    3.   The native ZFS filesystem for Linux. Install the ubuntu-zfs package.
    4.  <output truncated>
    5.  gpg: key F6B0FC61: public key "Launchpad PPA for Native ZFS for Linux" imported
    6.  gpg: Total number processed: 1
    7.  gpg:               imported: 1  (RSA: 1)
    8.  OK

    4.获取最新的软件包列表。

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

    5.安装ubuntu-zfs软件包

    1. $ sudo apt-get install -y ubuntu-zfs
    2.  
    3.  Reading package lists... Done
    4.  Building dependency tree
    5.  <output truncated>

    6.加载zfs模块。

    1. $ sudo modprobe zfs

    7.验证模块是否已正确加载。

    1. $ lsmod | grep zfs
    2.  
    3.  zfs                  2768247  0
    4.  zunicode              331170  1 zfs
    5.  zcommon                55411  1 zfs
    6.  znvpair                89086  2 zfs,zcommon
    7.  spl                    96378  3 zfs,zcommon,znvpair
    8.  zavl                   15236  1 zfs

    配置Docker ZFS

    一旦ZFS安装并加载完成,你可以继续配置docker ZFS。
    1.创建一个新的zpool。

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

    该命令创建名为”zpool-docker”的zpool。名称可以是任意的。
    2.检查zpool是否存在。

    1. $ sudo zfs list
    2.  
    3.  NAME            USED  AVAIL    REFER  MOUNTPOINT
    4.  zpool-docker    55K   3.84G    19K    /zpool-docker

    3.创建并挂载一个新的ZFS文件系统到/var/lib/docker。

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

    4.检查是否已经挂载成功。

    1. $ sudo zfs list -t all
    2.  
    3.  NAME                 USED  AVAIL  REFER  MOUNTPOINT
    4.  zpool-docker         93.5K  3.84G    19K  /zpool-docker
    5.  zpool-docker/docker  19K    3.84G    19K  /var/lib/docker

    现在你已经把一个ZFS文件系统挂载到/var/lib/docker,docker daemon应该可以自动加载zfs存储驱动了。
    5.启动docker daemon。

    1. $ sudo service docker start
    2.  
    3.  docker start/running, process 2315

    6.验证docker daemon是否已经在使用zfs存储驱动了。

    1. $ sudo docker info
    2.  
    3.  Containers: 0
    4.  Images: 0
    5.  Storage Driver: zfs
    6.   Zpool: zpool-docker
    7.   Zpool Health: ONLINE
    8.   Parent Dataset: zpool-docker/docker
    9.   Space Used By Parent: 27648
    10.   Space Available: 4128139776
    11.   Parent Quota: no
    12.   Compression: off
    13.  Execution Driver: native-0.2
    14.  [...]

    上面命令的输出显示docker daemon的存储驱动为zfs,父数据集为之前创建的zpool-docker/docker文件系统。

    ZFS与Docker性能

    有几个影响使用zfs存储驱动的docker性能的因素。

  • 内存。内存对ZFS性能有很大影响。这是因为ZFS刚开始是为有大量内存的Sun Solaris服务器设计的。使用ZFS时注意其内存使用情况。
  • ZFS功能。使用ZFS功能如去重,可能会明显增加ZFS内存使用量。出于内存消耗和性能考虑,建议关闭ZFS去重功能。不过,仍然可以使用堆栈中其他层(如SAN或NAS阵列)中的去重功能,因为这些不会影响ZFS内存使用和性能。
  • ZFS缓存。ZFS在一个称为自适应替换缓存(ARC)的内存结构中缓存硬盘数据块。ZFS的单拷贝ARC功能允许数据块的单个缓存副本由文件系统的多个克隆共享。这意味着多个正在运行的容器可以共享缓存数据块的单个副本。意味着ZFS是PaaS和其他类似用例的好选择。
  • 碎片。 碎片是像ZFS这样的写时拷贝文件系统的自然副产品。 然而,ZFS写入128K数据块中,并将slab(多个128K块)分配给CoW操作,以尝试减少碎片。 ZFS intent日志(ZIL)和合并写入(延迟写入)也有助于减少碎片。
  • 使用原生的Linux ZFS驱动。虽然Docker zfs存储驱动支持ZFS FUSE,当在需要高性能的场景下时不推荐使用。Linux的原生ZFS驱动的性能优于FUSE。
  • 标签:Docker 发布于:2019-11-20 03:03:12