共计 6215 个字符,预计需要花费 16 分钟才能阅读完成。
简介
Btrfs 是下一代的 copy-on-write 文件系统,它支持很多高级特性,使其更加适合 Docker。Btrfs 合并在内核主线中,并且它的 on-disk-format 也逐渐稳定了。不过,它的很多特性还仍然处于开发中。
Docker 的 btrfs 存储驱动利用了很多 Btrfs 特性来管理镜像和容器。这些特性中最重要的就是 thin provisioning(超配)、copy-on-write 和快照。
Btrfs 特性
Btrfs 一直被认为是 Linux 文件系统的未来。在 Linux 内核主线的全力支持下,稳定的 on-disk-format,关注于稳定性的积极开发,使得 Btrfs 逐渐成为现实。
只要 Docker 还在 Linux 平台上运行,人们就会认为 btrfs 存储驱动会替代 devicemapper 存储驱动,成为潜在的长期的存储驱动。然而,在写耗时上,devicemapper 被认为更安全,更稳定,更适合商品化。只有当你很了解 Btrfs,并且有丰富的经验时,才可以考虑 btrfs 驱动商品化。
镜像分层和共享 Btrfs
Docker 利用 Btrfs 的子卷(subvolumes)和快照来管理镜像和容器层的 on-disk 组件。Btrfs 子卷像是一个普通的 Unix 文件系统。同样,当挂靠到 Unix 文件系统时,它们可以有自己的内部目录结构。
子卷是原生的 copy-on-write,还有着按需分配的足够的空间,这些空间来自于下层的存储池。它们也可以拥有子卷,也可以使用快照。下图显示了 4 个子卷,子卷 2 和子卷 3 挂靠在其他子卷之上,子卷 4 显示了自己内部的目录树。
快照是某个时间点整个子卷的读写拷贝。它们直接位于其父 - 子卷之下。示例如下:
Btrfs 从下层的存储池中,按需地为子卷和快照分配空间。分配的单位是 chunk(大块),大块的大小通常是 1GB 左右。
快照是 Btrfs 文件系统的“一等公民”,它操作时就像普通的子卷。由于 Btrfs 原生的 copy-on-write 设计,创建快照可以直接在 Btrfs 文件系统中构建。这意味着 Btrfs 快照空间利用率很高,很少或是没有性能消耗。下图显示了子卷和它快照如何分享相同数据的。
Docker 的 btrfs 存储驱动把每个镜像层和容器都保存在它们自己的 Btrfs 子卷或者快照中。底部镜像保存为子卷,而他的子镜像层和容器都保存为快照。下图展示了该特性。
Docker 是如下使用 btrfs 驱动的:
1) 镜像的底层保存为 Btrfs 子卷,位于 /var/lib/docker/btrfs/subvolumes 目录下。
2) 随后的镜像层都保存为父层(子卷或快照)的 Btrfs 快照。
镜像和容器 on-disk 构建
镜像层和容器可在 Docker host 的文件系统下直接看到,目录为 /var/lib/docker/btrfs/subvolumes/。即使容器停止了,但其目录依然存在。这是因为 btrfs 存储驱动映射了一个默认的,最高等级的子卷在 /var/lib/docker/btrfs/subvolumes/ 下。所有其他的子卷都作为 Btrfs 文件系统给的对象而存在于该卷之下,而不是各自独立的映射。
因为 Btrfs 工作在文件系统级别,而不是块级别,可以通过普通的 Unix 命令直接浏览镜像和容器层的内容。可以通过 ls - l 等简单命令来显示镜像层的内容,以下为一个删节的输出:
$ ls -l /var/lib/docker/btrfs/subvolumes/0a17decee4139b0de68478f149cc16346f5e711c5ae3bb969895f22dd6723751/
total 0
drwxr-xr-x 1 root root 1372 Oct 9 08:39 bin
drwxr-xr-x 1 root root 0 Apr 10 2014 boot
drwxr-xr-x 1 root root 882 Oct 9 08:38 dev
drwxr-xr-x 1 root root 2040 Oct 12 17:27 etc
drwxr-xr-x 1 root root 0 Apr 10 2014 home
...output truncated...
容器使用 Btrfs 读写
容器是镜像的一个高效利用空间的快照,快照中的元数据指向存储池中的实际数据块,这个和子卷是一致的。因此,从快照中读和从子卷中读本质上是一样的。所以,Btrfs 驱动没有额外的性能损耗。
写一个新的文件,是一个按需分配的操作,会分配新的数据块给容器快照。文件也会写到这块新的空间。按需分配操作和所有 Btrfs 写操作一样,和写新数据到子卷也是一样的。因此,向容器快照写文件操作和原生的 Btrfs 操作速度一致。
在容器中更新一个已经存在的文件会引起 copy-on-write 操作(实际上是 redirect-on-write),驱动不操作源数据,新分配一块空间给快照。更新的数据写在这块新空间上,然后,驱动更新快照中的文件系统系统元数据,指向这块新数据。该行为只有极小的损耗。
使用 Btfs,写和更新大量小文件时,会使得性能缓慢。
在 Docker 中配置 Btrfs
btrfs 存储驱动只有在 /var/lib/docker 被映射在一个 Btrfs 文件系统时才能被使用。以下步骤展示如何在 Ubuntu 14.04 LTS 上配置 Brtfs。
准备知识
如果你已经在你的 Docker host 上使用了 Docker daemon,还有些镜像想保存,那么在尝试 Btrfs 之前,你需要先把镜像推送到 Docker Hub 或者你的私有仓库。
停止 Docker daemon。然后,确保你在 /dev/xvdb 下有空闲的块设备。
另外,还需要确定你的 OS 上是否已经加载了 Btrfs 模块。输入以下命令确认:
$ cat /proc/filesystems | grep btrfs
btrfs
在 Ubuntu 14.04 LTS 上配置 Btrfs
如果你的 OS 满足前面的要求,那么如下操作:
1) 安装 btrfs-tools 包。
$ sudo apt-get install btrfs-tools
Reading package lists... Done
Building dependency tree
<output truncated>
2) 创建 Btrfs 存储池。
通过 mkfs.btrfs 命令创建 Btrfs 存储池。给 mkfs.btrfs 命令传递多个设备则可以创建一个使用多个设备的存储池。这里我们演示一下创建单个设备(/dev/xvdb)的池。
$ sudo mkfs.btrfs -f /dev/xvdb
WARNING! - Btrfs v3.12 IS EXPERIMENTAL
WARNING! - see http://btrfs.wiki.kernel.org before using
Turning ON incompat feature 'extref': increased hardlink limit per file to 65536
fs created label (null) on /dev/xvdb
nodesize 16384 leafsize 16384 sectorsize 4096 size 4.00GiB
Btrfs v3.12
记得把 /dev/xvdb 替换为你系统中的实际设备名称。
再次提醒:如前面提到的,Btrfs 暂时来看,不建议作为产品来使用,除非你有着丰富的经验。
3) 在本地存储创建 /var/lib/docker。
$ sudo mkdir /var/lib/docker
4) 使 Btrfs 文件系统在系统重启时会自映射。
a. 获取 Btrfs 文件系统的 UUID。
$ sudo blkid /dev/xvdb
/dev/xvdb: UUID="a0ed851e-158b-4120-8416-c9b072c8cf47"
UUID_SUB="c3927a64-4454-4eef-95c2-a7d44ac0cf27" TYPE="btrfs"
b. 在 /etc/fstab 中增加一行条目,使得系统启动时可以自动映射 /var/lib/docker。下面两行每一行都可以生效,当然,在你实际操作中,记得替换为自己的 UUID。
/dev/xvdb /var/lib/docker btrfs defaults 0 0
UUID="a0ed851e-158b-4120-8416-c9b072c8cf47" /var/lib/docker btrfs defaults 0 0
5. 映射新的文件系统,并确认操作是否成功。
$ sudo mount -a
$ mount
/dev/xvda1 on / type ext4 (rw,discard)
<output truncated>
/dev/xvdb on /var/lib/docker type btrfs (rw)
6. 然后,重启 docker 服务。
$ sudo service docker start
docker start/running, process 2315
当然,由于你使用的 Linux 发行版可能不同,启动 Docker Daemon 的方法可能也不同。
这里,在启动 Docker Daemon 之前,你可以强行指定 Daemon 的存储驱动为 btrfs 存储驱动。可以在 daemon 启动命令行时传递 –storage-driver=btrfs 参数,也可以在 Docker 配置文件中修改 DOCKER_OPTS 参数。
7. 通过 docker info 命令验证。
$ sudo docker info
Containers: 0
Images: 0
Storage Driver: btrfs
[...]
btrfs 和 Docker 性能
在 btrfs 存储驱动下,有以下一些原因可以影响 Docker 的性能。
- Page caching,页缓存。Btrfs 不支持页缓存共享,也就是说 n 个容器访问同一个文件会请求 n 份缓存拷贝。因此,btrfs 驱动可能不是 Paas 或者高密集容器的最优选项。
- Small writes,小的写请求。容器执行大量写的写请求(包括 Docker host 启动和停止很多容器)会导致 Btrfs 大块只使用了很小一部分,最终会导致 Docker host 空间不足,停止服务。这是当前使用 Btrfs 的一个最重大的缺点。
如果使用 btrfs 存储驱动,需要密切监视 Btrfs 文件系统的可用空间,可用使用 btrfs filesys shwo 来观察。不用相信常规的 Unix 命令(如 df)的输出。 - Sequential writes,顺序写。Btrfs 通过日志技术写数据到磁盘,这回导致顺序写的性能减半。
- Fragmentation。存储残片是像 Btrfs 这种 copy-on-write 文件系统的天然副产品,很多小的随机写会产生这个问题。它可以表现为使用 SSD 介质的 Docker 主机上的 CPU 峰值和使用旋转介质的 Docker 主机上的抖动(It can manifest as CPU spikes on Docker hosts using SSD media and head thrashing on Docker hosts using spinning media. 不是很理解这句)。这两个都会导致性能很差。
Btrfs 的最近版本允许你制定 autodefrag 作为一个映射点。这种模式下,会探测到随机写并进行碎片整理。在确定使用 Btrfs 之前,你应该在你的 Docker host 上进行测试。一些测试显示,在执行大量的 samll writes 操作时(包括启停很多容器),这个选项会有一些负面的性能问题。 - Solid State Devices(SSD)。Btrfs 有原生的 SSD 优化,可以通过映射时加上 -o ssd 映射选项来使能它。这些优化包括在 SSD 介质上避免 seek 之类的操作来增强 SSD 写性能,因为这类操作在 SSD 上没有任何作用。
Btrfs 也支持 TRIM/Discard 元操作。然而,映射时加上 -o discard 的选项会导致性能问题。因此,还是建议在使用之前做些测试。 - Use Data Volumes。数据卷提供最优和最可预测的性能。因为它们可以绕过存储驱动,不会引起任何超配和 copy-on-write 可能会导致的潜在的负载。
-
Balance BTRFS。开启一个 cron 任务来均衡你的 BTRFS 设备,比如均衡地传输子卷的块给 raid 设备,回收未使用的块。如果不这样做,docker 删除的快照和子卷会遗留分配了的块,这些块装满了 BTRFS 根卷的。一旦你没有执行再均衡操作,在不添加额外的存储设备情况下,会导致潜在的不可恢复的状态。如果你不愿意使用 crond 来自动执行,另一个方法是在非峰值时手动执行再均衡命令,因此为这种操作时磁盘 I / O 密集型操作。此命令按要求所有的大块使用了 1% 或者更少:
$ sudo btrfs filesystem balance start -dusage=1 /var/lib/docker Dumping filters: flags 0x1, state 0x0, force is off DATA (flags 0x2): balancing, usage=1 Done, had to relocate 673 out of 842 chunks
小结
Btrfs 存储驱动的主要特性就是超配,copy-on-write 和快照。与 AuFS 或者 devmapper 不同,要在 Docker 上使用 Btrfs,要求整个 /var/lib/docker 所处的文件系统就是 Btrfs。此外,btrfs 存储驱动由于现在还在重度开发中,现在最多的就是各种性能问题。所以,官方也不建议直接在 Docker 生产环境中使用,除非,你在 Btrfs 上有着丰富的经验。
更多 Docker 相关教程见以下内容:
Docker 安装应用(CentOS 6.5_x64) http://www.linuxidc.com/Linux/2014-07/104595.htm
Ubuntu 14.04 安装 Docker http://www.linuxidc.com/linux/2014-08/105656.htm
Ubuntu 使用 VNC 运行基于 Docker 的桌面系统 http://www.linuxidc.com/Linux/2015-08/121170.htm
阿里云 CentOS 6.5 模板上安装 Docker http://www.linuxidc.com/Linux/2014-11/109107.htm
Ubuntu 15.04 下安装 Docker http://www.linuxidc.com/Linux/2015-07/120444.htm
在 Ubuntu Trusty 14.04 (LTS) (64-bit)安装 Docker http://www.linuxidc.com/Linux/2014-10/108184.htm
在 Ubuntu 15.04 上如何安装 Docker 及基本用法 http://www.linuxidc.com/Linux/2015-09/122885.htm
Ubuntu 16.04 上 Docker 使用手记 http://www.linuxidc.com/Linux/2016-12/138490.htm
Docker 的详细介绍:请点这里
Docker 的下载地址:请点这里
本文永久更新链接地址:http://www.linuxidc.com/Linux/2017-03/141580.htm