Docker存储驱动—Btrfs「译」

Btrfs是下一代copy-on-write文件系统,它支持很多先进存储技术,这使得它能很好的适用与Docker。Btrfs已经引入了内核主线

Docker的btrfs存储驱动利用了很多Btrfs的特征来管理容器和镜像。这些特征有块级操作,瘦供给(thin provisioning),copy-on-write快照,以及管理轻便性。你可以很容易的将多个物理块设备结合成一个单一的Btrfs文件系统

这篇文章中使用“btrfs”代表Docker的Btrfs存储驱动,使用“Btrfs”表示Btrfs文件系统。注意在Ubuntu或者Debian上只有Docker CE支持btrfs存储驱动,在SLES上,只有Docker EE / CS 支持btrfs存储驱动

基本条件

为了支持btrfs,必须满足下列条件:

  • Docker CE:只有Ubuntu或Debian中支持btrfs
  • Docker EE:只有SLES中支持btrfs
  • 改变存储驱动会使你本地系统创建的所有容器都无法访问。在改变存储驱动前记得使用保存容器,然后推送到Docker hub或者私有仓库
  • btrfs需要一个专用的块设备(如物理磁盘)。这个块设备必须格式化为Btrfs然后挂载到/var/lib/docker。下面的配置流程会指导你完成这些步骤。对于SLES来说,根文件系统默认情况下就是Btrfs,所以无需另外的专用块设备,但出于性能方面的考虑,你可以选择使用另外一个专用块设备
  • 内核必须支持btrfs,可以运行下面的命令检测:

    1
    2
    $ sudo cat /proc/filesystems | grep btrfs
    btrfs
  • 在操作系统层管理Btrfs文件系统需要使用btrfs命令。如果系统中还未安装,安装btrfsprogs包(SLES)或btrfs-tools包(Ubuntu)


配置Docker使用btrfs存储驱动

  1. 停止Docker;
  2. /var/lib/docker/中的内容进行备份,然后清空该目录;
1
2
$ sudo cp -au /var/lib/docker /var/lib/docker.bk
$ sudo rm -rf /var/lib/docker/*
  1. 将你的专用块设备格式化成Btrfs。现在假设有2个分别名为/dev/xvdf/dev/xvdg的块设备
1
$ sudo mkfs.btrfs -f /dev/xvdf /dev/xvdg
  1. 将新的Btrfs文件系统挂载到/var/lib/docker/
1
$ sudo mount -t btrfs /dev/xvdf /var/lib/docker

不要忘了在/etc/fstab中添加新的项使这个改变永久化

  1. /var/lib/docker.bk拷贝到/var/lib/docker/
1
$ sudo cp -au /var/lib/docker.bk/* /var/lib/docker/
  1. 配置Docker使用btrfs存储驱动。尽管现在/var/lib/docker/已经是Btrfs文件系统,但是这个配置步骤也是需要的。编辑文件/etc/docker/daemon.json。加入下列内容(如果下列内容不是在末尾,记得在最后一行后面加上逗号)
1
2
3
{
"storage-driver": "btrfs"
}
  1. 启动Docker,证实存储驱动已经是btrfs
1
2
3
4
5
6
7
8
9
10
11
12
$ docker info

Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 17.03.1-ce
Storage Driver: btrfs
Build Version: Btrfs v4.4
Library Version: 101
<output truncated>
  1. 如果确认/var/lib/docker.bk将不再使用则将其删除


管理一个Btrfs卷

Btrfs的一个好处就是管理方便,不需要卸载文件系统或重启Docker就能对其进行管理

当空间不足时,btrfs自动按大约1GB的块来扩充卷

可以使用btrfs device addbtrfs filesystem balance将一个块设备添加到Btrfs卷

1
2
3
$ sudo btrfs device add /dev/svdh /var/lib/docker

$ sudo btrfs filesystem balance /var/lib/docker


btrfs存储驱动如何工作

btrfs和其它存储驱动不同,整个/var/lib/docker目录都被存储为Btrfs卷

镜像和容器的磁盘结构

镜像层和可写的容器层的信息存储在/var/lib/docker/btrfs/subvolumes/中。每个容器层或镜像层在这个目录下都有一个相应的目录。子卷具有copt-on-write的特性它们的空间由一个底层存储池来按需分配。它们也能被嵌套和快照。下图展示了4个子卷。‘Subvolume 2’和’Subvolume 3’是嵌套的。而’Subvolume 4’展示了自身的内部目录树

一个镜像只有基层会被存储为一个真实的子卷。所有其它的层被存储为快照,它们只包含那一层的改变。如下图所示,可以创建快照的快照:

在磁盘上快照看起来就像子卷,但是事实上它们更小。copy-on-write的使用可以获得最大的存储效益以及最小的层大小,容器层写为块级。下面中镜像和它的块组共享数据:

为了最大化效益,当一个容器需要更多空间时,会按1GB的大块进行分配

Docker的btrfs存储驱动将每个镜像层和容器存储在自己的btrfs子卷或快照中。镜像的基层存储为一个子卷而孩子层以及容器层存储为快照。如下图所示:

在运行btrfs存储的Docker主机上创建镜像和容器的过程如下:

  1. 镜像的基层存储在Btrfs子卷中/var/lib/docker/btrfs/subvolumes
  2. 随后的镜像层存储为父层子卷或快照的快照,但是这一层会引入改变。这些改变以块级为单位进行存储
  3. 容器的可写层是最上层镜像层的快照,这一层会引入改变。这些改变以块级为单位进行存储


容器的读写

读文件

容器是一个镜像的快照。快照中的元数据指向存储池中的实际数据块。这和一个子卷一样。因此,对快照执行读基本上与对子卷执行的读相同

写文件

  • 写新文件:写一个新文件到容器会触发一个按需分配操作来将新的数据块分配到容器的快照。然后文件会被写入这个新的空间。这和写新的数据到一个子卷一样。写新文件到容器的快照可以获得原始Btrfs的速度
  • 修改存在的文件:修改一个已存在文件是一个copy-on-write操作。会从文件所在的层读取原始数据,只有修改的块会被写入容器层。接着,btrfs驱动更新快照中文件系统的元数据以指向新的数据。这些行为开销很低
  • 删除文件或目录:如果一个容器删除镜像层中的文件或者目录,Btrfs屏蔽了下层中文件或目录的存在。如果容器创建了一个文件,然后将其删除,则此操作将在btrfs文件系统本身中执行,并回收空间

使用btrfs,写入和更新大量小文件会导致低性能。

Btrfs和Docker的性能

使用btrfs存储驱动时,有几个因素会影响Docker的性能

注意:很多这些因素可以依靠使用Docker卷来缓解,而不是依赖于容器可写层来存储数据。但是,就Btrfs来说,Docker卷仍然可能受到影响,除非/var/lib/docker/volumes/并不是挂载在Btrfs下

  • 页缓存:Btrfs不支持页缓存共享。这意味着访问相同文件的进程都会将文件拷贝到内存中。因此btrfs驱动可能不是高密集使用场景(如PaaS)的最好选择
  • 小文件:容器执行大量的小的写(比如当短时间内启动和停止大量容器)会影响Btrfs大块的使用。这会持续消耗Btrfs文件系统的空间。可以使用btrfs filesys show来监控Btrfs设备的空间信息
  • 顺序写:当写入磁盘时,Btrfs使用了日志技术。这会影响顺序写的性能,最多可能会减少50%的性能。
  • 碎片:碎片是copy-on-write文件系统的副作用。当使用SSD时或者在使用旋转磁盘发生磁头摆动时,碎片可能表现为CPU峰值。这些问题中的任何一个都可能损害性能
  • SSD性能:Btrfs与生俱来具备对SSD介质的优化。为了使这些特征生效,使用-o ssd选项来挂载Btrfs文件系统。这些优化包括:通过避免寻道优化从而加强SSD的写性能
  • 经常平衡Btrfs文件系统:在非高峰时段,使用操作系统实用程序(如cron作业)定期平衡btrfs文件系统。这将回收未分配的块,并有助于防止文件系统不必要地填充。除非向文件系统添加额外的物理块设备,否则无法重新平衡整个完整的btrfs文件系统
  • 使用快存储:SSD提供更快的读写速度
  • 为写密集的负载使用卷:对于写密集的负载,卷提供了最好和最可预测的性能。因为卷旁路了存储驱动从而避开了由瘦供给(thin provisioning)和copy-on-write引入的潜在开销。卷还具有其它好处,比如允许你在容器间共享数据以及持久化数据

相关资料

文章目录
  1. 1. 基本条件
  2. 2. 配置Docker使用btrfs存储驱动
  3. 3. 管理一个Btrfs卷
  4. 4. btrfs存储驱动如何工作
    1. 4.1. 镜像和容器的磁盘结构
  5. 5. 容器的读写
    1. 5.1. 读文件
    2. 5.2. 写文件
  6. 6. Btrfs和Docker的性能
  7. 7. 相关资料
|