--- outline: [2,5] --- # BTRFS 存储驱动程序 Btrfs 是一种写入时复制文件系统,支持许多高级存储技术,非常适合 Docker。Btrfs 包含在主线 Linux 内核中。 Docker 的 `btrfs` 存储驱动程序利用许多 Btrfs 功能进行映像和容器管理。这些功能包括块级操作、精简配置、写入时复制快照和易于管理。您可以将多个物理块设备合并到一个 Btrfs 文件系统中。 本页将 Docker 的 Btrfs 存储驱动程序称为 `btrfs`,将整个 Btrfs 文件系统称为 Btrfs。 :::tip 注意 `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` 支持。要检查这一点,请运行以下命令: ```bash grep btrfs /proc/filesystems btrfs ``` - 要在操作系统级别管理 Btrfs 文件系统,您需要 `btrfs` 命令。如果您没有此命令,请安装 `btrfsprogs` package (SLES) 或 `btrfs-tools` package (Ubuntu) 的 Package。 ## 配置 Docker 以使用 btrfs 存储驱动程序 此过程在 SLES 和 Ubuntu 上基本相同。 1. 停止 Docker。 2. 将 `/var/lib/docker/` 的内容复制到备份位置,然后清空 `/var/lib/docker/` 的内容: ```bash sudo cp -au /var/lib/docker /var/lib/docker.bk sudo rm -rf /var/lib/docker/* ``` 3. 将专用块设备格式化为 Btrfs 文件系统。此示例假定您使用的是两个名为 `/dev/xvdf` 和 `/dev/xvdg` 中。仔细检查块设备名称,因为这是一个破坏性操作。 ```bash sudo mkfs.btrfs -f /dev/xvdf /dev/xvdg ``` Btrfs 还有更多选项,包括条带化和 RAID。请参阅 [Btrfs 文档][0]。 4. 将新的 Btrfs 文件系统挂载到 `/var/lib/docker/` 挂载点。您可以指定用于创建 Btrfs 文件系统的任何块设备。 ```bash sudo mount -t btrfs /dev/xvdf /var/lib/docker ``` :::tip 注意 通过添加一个条目来使更改在重新启动后永久生效 `/etc/fstab` 。 ::: 5. 将 `/var/lib/docker.bk` 的内容复制到 `/var/lib/docker/`。 ```bash sudo cp -au /var/lib/docker.bk/* /var/lib/docker/ ``` 6. 配置 Docker 以使用`btrfs`存储驱动程序。即使`/var/lib/docker/`现在使用 Btrfs 文件系统,这也是必需的。编辑或创建文件`/etc/docker/daemon.json` 。如果是新文件,添加以下内容。如果它是现有文件,则仅添加键和值,如果不是结束大括号 ( `}` ) 之前的最后一行,请小心地以逗号结束该行。 ```json { "storage-driver": "btrfs" } ``` 查看每个存储驱动程序的所有存储选项 [守护进程参考文档][1] 7. 启动 Docker。当它运行时,验证`btrfs`是否被用作存储驱动程序。 ```bash 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 <...> ``` 8. 准备好后,删除 `/var/lib/docker.bk` 目录。 ## 管理 Btrfs 卷 Btrfs 的优点之一是可以轻松管理 Btrfs 文件系统,无需卸载文件系统或重新启动 Docker。 当空间不足时,Btrfs 会自动以大约 1 GB 的块扩展卷。 要将块设备添加到 Btrfs 卷,请使用`btrfs device add`和 `btrfs filesystem balance`命令。 ```bash sudo btrfs device add /dev/svdh /var/lib/docker sudo btrfs filesystem balance /var/lib/docker ``` :::note 笔记 虽然您可以在 Docker 运行时执行这些操作,但性能会受到影响。最好计划一个中断窗口来平衡 Btrfs 文件系统。 ::: ## `btrfs`存储驱动程序如何工作 `btrfs`存储驱动程序的工作方式与其他存储驱动程序不同,因为整个`/var/lib/docker/`目录都存储在 Btrfs 卷上。 ### 磁盘上的映像和容器层 有关图像层和可写容器层的信息存储在 `/var/lib/docker/btrfs/subvolumes/` 。该子目录包含每个图像或容器层一个目录,以及从一层及其所有父层构建的统一文件系统。子卷本质上是写时复制,并从底层存储池按需分配空间。它们还可以嵌套和快照。下图显示了 4 个子卷。 “子卷 2”和“子卷 3”是嵌套的,而“子卷 4”显示其自己的内部目录树。 ![btfs_subvolume](./btfs_subvolume.webp) 仅图像的基础层被存储为真正的子体积。所有其他层都存储为快照,其中仅包含该层中引入的差异。您可以创建快照的快照,如下图所示。 ![btfs_snapshots](./btfs_snapshots.webp) 在磁盘上,快照看起来和感觉上都像子卷,但实际上它们要小得多并且更节省空间。写时复制用于最大化存储效率并最小化层大小,并且容器可写层中的写入在块级别进行管理。下图显示了子卷及其快照共享数据。 ![btfs_pool](./btfs_pool.webp) 为了最大程度地提高效率,当容器需要更多空间时,会以大约 1 GB 大小的块进行分配。 Docker 的`btrfs`存储驱动程序将每个镜像层和容器存储在其自己的 Btrfs 子卷或快照中。映像的基础层存储为子卷,而子映像层和容器存储为快照。如下图所示。 ![btfs_container_layer](./btfs_container_layer.webp) 在运行`btrfs`驱动程序的 Docker 主机上创建映像和容器的高级流程如下: 1. 图像的基础层存储在 Btrfs子卷中 `/var/lib/docker/btrfs/subvolumes` 。 2. 后续映像层存储为父层子卷或快照的 Btrfs快照,但包含该层引入的更改。这些差异存储在块级别。 3. 容器的可写层是最终镜像层的 Btrfs 快照,其中存在由运行容器引入的差异。这些差异存储在块级别。 ## 容器如何与btrfs一起读写 ### 读取文件 容器是镜像的节省空间的快照。快照中的元数据指向存储池中的实际数据块。这与子卷相同。因此,对快照执行的读取本质上与对子卷执行的读取相同。 ### 写入文件 一般注意事项是,使用 Btrfs 写入和更新大量小文件可能会导致性能下降。 考虑容器使用 Btrfs 打开文件进行写访问的三种场景。 ### 写入新文件 将新文件写入容器会调用按需分配操作,将新数据块分配给容器的快照。然后文件被写入这个新空间。按需分配操作是 Btrfs 的所有写入操作的本机操作,与将新数据写入子卷相同。因此,将新文件写入容器的快照将以本机 Btrfs 速度运行。 ### 修改现有文件 更新容器中的现有文件是写时复制操作(写时重定向是 Btrfs 术语)。从文件当前所在的层读取原始数据,仅将修改的块写入容器的可写层。接下来,Btrfs 驱动程序更新快照中的文件系统元数据以指向此新数据。此行为会产生少量开销。 ### 删除文件或目录 如果容器删除了下层存在的文件或目录,Btrfs 会屏蔽下层文件或目录的存在。如果容器创建一个文件然后删除它,则该操作将在 Btrfs 文件系统本身中执行,并回收空间。 ## Btrfs 和 Docker 性能 `btrfs`下影响Docker性能的因素有几个 存储驱动程序。 :::note 笔记 通过使用 Docker 卷来处理写入量大的工作负载,而不是依赖于将数据存储在容器的可写层中,可以缓解许多这些因素。然而,就 Btrfs 而言,Docker 卷仍然存在这些缺点,除非`/var/lib/docker/volumes/`不受 Btrfs 支持。 ::: ### 页面缓存 Btrfs 不支持页面缓存共享。这意味着访问同一文件的每个进程都会将该文件复制到 Docker 主机的内存中。因此, `btrfs`驱动程序可能不是 PaaS 等高密度用例的最佳选择。 ### 小写入 执行大量小写入的容器(这种使用模式也与您在短时间内启动和停止许多容器时发生的情况相匹配)可能会导致 Btrfs 块的使用不当。这可能会过早填满 Btrfs 文件系统并导致 Docker 主机上出现空间不足的情况。使用`btrfs filesys show`密切监视 Btrfs 设备上的可用空间量。 ### 顺序写入 Btrfs 在写入磁盘时使用日志技术。这可能会影响顺序写入的性能,使性能降低高达 50%。 ### 碎片化 碎片是 Btrfs 等写时复制文件系统的自然副产品。许多小的随机写入会使这个问题变得更加复杂。碎片可能表现为使用 SSD 时的 CPU 峰值或使用旋转磁盘时的磁头抖动。这些问题中的任何一个都会损害性能。 如果您的Linux内核版本是3.9或更高版本,您可以启用autodefrag 安装 Btrfs 卷时的功能。在您自己的工作负载上测试此功能 在将其部署到生产中之前,因为一些测试显示出负面影响 关于性能。 ### 固态硬盘性能 Btrfs 包括针对 SSD 介质的本机优化。要启用这些功能,请使用`-o ssd`挂载选项挂载 Btrfs 文件系统。这些优化包括通过避免优化(例如不适用于固态介质的寻道优化)来增强 SSD 写入性能。 ### 经常平衡 Btrfs 文件系统 使用操作系统实用程序(例如`cron`作业)在非高峰时段定期平衡 Btrfs 文件系统。这会回收未分配的块并有助于防止文件系统不必要地填满。除非向文件系统添加额外的物理块设备,否则无法重新平衡完全满的 Btrfs 文件系统。 请参阅 [维基百科](https://btrfs.wiki.kernel.org/index.php/Balance_Filters#Balancing_to_fix_filesystem_full_errors)。 ### 使用快速存储 固态硬盘 (SSD) 提供比旋转磁盘更快的读取和写入速度。 ### 使用卷来处理写入量大的工作负载 卷为写入密集型工作负载提供最佳且最可预测的性能。这是因为它们绕过存储驱动程序,并且不会产生精简配置和写入时复制带来的任何潜在开销。卷还有其他好处,例如允许您在容器之间共享数据,甚至在没有正在运行的容器使用它们时也能保留数据。 ## 相关信息 - [卷][20] - [了解镜像、容器和存储驱动程序][21] - [选择存储驱动程序][22] [0]:https://btrfs.wiki.kernel.org/index.php/Using_Btrfs_with_Multiple_Devices [1]:https://docs.docker.com/reference/cli/dockerd/#options-per-storage-driver [20]:# [21]:# [22]:./select-storage-driver