BTRFS 存储驱动
Btrfs 是一种写时复制文件系统,支持许多先进的存储技术,使其非常适合 Docker。Btrfs 已包含在 Linux 内核主线中。
Docker 的 btrfs 存储驱动利用许多 Btrfs 功能来管理镜像和容器。这些功能包括块级操作、精简配置、写时复制快照以及易于管理。您可以将多个物理块设备组合成一个单一的 Btrfs 文件系统。
本页面将 Docker 的 Btrfs 存储驱动称为 btrfs,并将整个 Btrfs 文件系统称为 Btrfs。
注意
btrfs存储驱动程序仅在 SLES、Ubuntu 和 Debian 系统上的 Docker Engine CE 中受支持。
前提条件
btrfs 在满足以下先决条件的情况下受支持:
btrfs仅推荐在 Ubuntu 或 Debian 系统上与 Docker CE 一起使用。更改存储驱动将导致您已创建的任何容器在本地系统上无法访问。使用
docker save保存容器,并将现有镜像推送到 Docker Hub 或私有仓库,以便您无需稍后重新创建它们。btrfs需要一个专用的块存储设备,例如物理磁盘。此块设备必须格式化为 Btrfs 并挂载到/var/lib/docker/。 下面的配置说明将引导您完成此过程。默认情况下,SLES/文件系统格式化为 Btrfs,因此对于 SLES,您不需要使用单独的块设备,但出于性能原因,您可以选择这样做。btrfs支持必须存在于您的内核中。要检查这一点,请运行以下命令:$ grep btrfs /proc/filesystems btrfs要在操作系统级别管理 Btrfs 文件系统,您需要
btrfs命令。如果您没有此命令,请安装btrfsprogs软件包 (SLES) 或btrfs-tools软件包 (Ubuntu)。
配置 Docker 以使用 btrfs 存储驱动
此过程在 SLES 和 Ubuntu 上基本相同。
停止 Docker。
将
/var/lib/docker/的内容复制到备份位置,然后清空/var/lib/docker/的内容:$ sudo cp -au /var/lib/docker /var/lib/docker.bk $ sudo rm -rf /var/lib/docker/*将您的专用块设备或设备格式化为 Btrfs 文件系统。此示例假设您正在使用名为
/dev/xvdf和/dev/xvdg的两个块设备。请仔细检查块设备名称,因为这是一个破坏性操作。$ sudo mkfs.btrfs -f /dev/xvdf /dev/xvdgBtrfs 还有更多选项,包括条带化和 RAID。请参阅 Btrfs 文档。
将新的 Btrfs 文件系统挂载到
/var/lib/docker/挂载点上。您可以指定用于创建 Btrfs 文件系统的任何块设备。$ sudo mount -t btrfs /dev/xvdf /var/lib/docker注意
通过向
/etc/fstab添加条目,使更改在重启后永久生效。将
/var/lib/docker.bk的内容复制到/var/lib/docker/。$ sudo cp -au /var/lib/docker.bk/* /var/lib/docker/配置 Docker 以使用
btrfs存储驱动。即使/var/lib/docker/现在使用 Btrfs 文件系统,这也是必需的。 编辑或创建文件/etc/docker/daemon.json。如果是新文件,添加以下内容。如果是现有文件,仅添加键和值, 注意如果该行不是结束花括号 (}) 前的最后一行,请以逗号结尾。{ "storage-driver": "btrfs" }请参阅 守护进程参考文档 中每个存储驱动程序的所有存储选项
启动 Docker。当它运行时,请确认
btrfs正在被用作存储驱动。$ 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 <...>当您准备好时,请删除
/var/lib/docker.bk目录。
管理 Btrfs 卷
Btrfs 的一个优势是无需卸载文件系统或重启 Docker 即可轻松管理 Btrfs 文件系统。
当空间不足时,Btrfs 会自动以大约 1 GB 的块为单位扩展卷。
要将块设备添加到 Btrfs 卷,请使用 btrfs device add 和
btrfs filesystem balance 命令。
$ sudo btrfs device add /dev/svdh /var/lib/docker
$ sudo btrfs filesystem balance /var/lib/docker
注意
虽然您可以在 Docker 运行时执行这些操作,但性能会受到影响。 最好计划一个停机窗口来平衡 Btrfs 文件系统。
btrfs 存储驱动的工作原理
btrfs 存储驱动与其他存储驱动的工作方式不同,因为整个 /var/lib/docker/ 目录存储在 Btrfs 卷上。
磁盘上的镜像和容器层
关于镜像层和可写容器层的信息存储在
/var/lib/docker/btrfs/subvolumes/ 中。此子目录为每个镜像或容器层包含一个目录,
其中包含由一层及其所有父层构建的统一文件系统。
子卷原生支持写时复制,并从底层存储池按需分配空间。
它们还可以嵌套和创建快照。下图显示了 4 个子卷。
“子卷 2”和“子卷 3”是嵌套的,而“子卷 4”显示了其自己的内部目录树。

只有镜像的基础层被存储为真正的子卷。所有其他层都作为快照存储,其中仅包含在该层中引入的差异。您可以创建快照的快照,如下图所示。

在磁盘上,快照的外观和行为就像子卷一样,但实际上它们要小得多且空间效率更高。写时复制技术被用于最大化存储效率并最小化层大小,容器可写层中的写入操作在块级别进行管理。下图展示了一个子卷及其快照共享数据的情况。

为了获得最大效率,当容器需要更多空间时,它将以大约 1 GB 的大小块进行分配。
Docker 的 btrfs 存储驱动将每个镜像层和容器存储在其
自己的 Btrfs 子卷或快照中。镜像的基础层存储为
子卷,而子镜像层和容器则存储为快照。
下图展示了这一点。

在运行 btrfs 驱动程序的 Docker 主机上创建镜像和容器的高级流程如下:
镜像的基础层存储在 Btrfs 子卷 中的
/var/lib/docker/btrfs/subvolumes下。后续的镜像层存储为父层子卷或快照的 Btrfs 快照,但包含该层引入的更改。这些差异存储在块级别。
容器的可写层是最终镜像层的 Btrfs 快照, 其中包含了运行容器引入的差异。这些差异 存储在块级别。
容器如何使用 btrfs 进行读写操作
读取文件
容器是镜像的一种节省空间的快照。快照中的元数据指向存储池中的实际数据块。这与子卷的情况相同。因此,对快照执行的读取操作本质上与对子卷执行的读取操作相同。
写入文件
作为一般注意事项,在 Btrfs 上写入和更新大量小文件可能会导致性能缓慢。
考虑在 Btrfs 上,容器打开文件进行写入访问的三种场景。
写入新文件
向容器写入新文件会触发按需分配操作,以便为容器的快照分配新的数据块。文件随后被写入到这个新空间中。按需分配操作是Btrfs所有写入操作的原生特性,与向子卷写入新数据相同。因此,向容器快照写入新文件以Btrfs的原生速度运行。
修改现有文件
更新容器中的现有文件是一项写时复制操作(重定向写入是 Btrfs 术语)。原始数据从文件当前所在的层读取,只有修改的块被写入容器的可写层。接下来,Btrfs 驱动程序更新快照中的文件系统元数据,以指向这个新数据。这种行为会产生轻微的开销。
删除文件或目录
如果容器删除了存在于较低层中的文件或目录,Btrfs 会屏蔽较低层中该文件或目录的存在。如果容器创建了一个文件然后删除它,这个操作会在 Btrfs 文件系统本身中执行,并回收空间。
Btrfs 和 Docker 性能
在 btrfs 存储驱动下,有几个因素会影响 Docker 的性能。
注意
对于写入密集型工作负载,使用 Docker 卷可以缓解许多这些因素,而不是依赖于将数据存储在容器的可写层中。然而,在 Btrfs 的情况下,Docker 卷仍然存在这些缺点,除非
/var/lib/docker/volumes/不由 Btrfs 支持。
页面缓存
Btrfs 不支持页面缓存共享。这意味着每个访问同一文件的进程都会将文件复制到 Docker 主机的内存中。因此,对于诸如 PaaS 之类的高密度用例,btrfs 驱动可能不是最佳选择。
小写入
执行大量小写入的容器(这种使用模式也与在短时间内启动和停止许多容器的情况相匹配)可能导致 Btrfs 块的使用不当。这可能会过早填满 Btrfs 文件系统,并导致 Docker 主机出现空间不足的情况。使用 btrfs filesys show 来密切监控 Btrfs 设备上的可用空间量。
顺序写入
Btrfs 在写入磁盘时使用日志技术。这可能会影响顺序写入的性能,导致性能下降高达 50%。
碎片化
碎片化是像 Btrfs 这样的写时复制(copy-on-write)文件系统的自然副产品。 许多小的随机写入可能会加剧这个问题。碎片化在使用 SSD 时表现为 CPU 尖峰, 在使用旋转磁盘时表现为磁头频繁移动。这些问题中的任何一个都会损害性能。
如果您的 Linux 内核版本是 3.9 或更高版本,您可以在挂载 Btrfs 卷时启用 autodefrag
功能。在将其部署到生产环境之前,请在您自己的工作负载上测试此功能,因为某些测试表明它会对性能产生负面影响。
SSD 性能
Btrfs 包含针对 SSD 介质的原生优化。要启用这些功能,
请在挂载 Btrfs 文件系统时使用 -o ssd 挂载选项。这些优化
包括通过避免不适用于固态介质的优化(如寻址
优化)来提升 SSD 写入性能。
经常平衡 Btrfs 文件系统
使用操作系统实用程序(例如 cron 作业)在非高峰时段定期平衡 Btrfs 文件系统。这可以回收未分配的块,并有助于防止文件系统不必要地被填满。除非向文件系统添加额外的物理块设备,否则无法重新平衡完全填满的 Btrfs 文件系统。
查看 Btrfs Wiki。
使用快速存储
固态硬盘(SSD)比旋转磁盘提供更快的读写速度。
使用卷处理高写入工作负载
卷为高写入工作负载提供了最佳且最可预测的性能。这是因为它们绕过了存储驱动程序,不会引入精简配置和写时复制可能带来的任何潜在开销。卷还有其他优势,例如允许您在容器之间共享数据,即使没有正在运行的容器使用它们,卷也会持久存在。