OverlayFS 存储驱动程序
OverlayFS 是一个联合文件系统。
此页面将 Linux 内核驱动程序称为OverlayFS,将 Docker 存储驱动程序称为overlay2。
注意
对于
fuse-overlayfs驱动程序,请查看无根模式文档。
先决条件
OverlayFS 是推荐的存储驱动程序,如果您满足以下先决条件,则受支持
Linux 内核版本 4.0 或更高版本,或使用内核版本 3.10.0-514 或更高版本的 RHEL 或 CentOS。
overlay2驱动程序支持xfs后端文件系统,但仅在启用d_type=true的情况下。使用
xfs_info验证ftype选项是否设置为1。要正确格式化xfs文件系统,请使用标志-n ftype=1。更改存储驱动程序会使本地系统上现有的容器和镜像无法访问。在更改存储驱动程序之前,请使用
docker save保存您已构建的任何镜像或将其推送到 Docker Hub 或私有注册表,这样您以后就不需要重新创建它们了。
使用overlay2存储驱动程序配置 Docker
在执行此过程之前,您必须首先满足所有先决条件。
以下步骤概述了如何配置overlay2存储驱动程序。
停止 Docker。
$ sudo systemctl stop docker将
/var/lib/docker的内容复制到临时位置。$ cp -au /var/lib/docker /var/lib/docker.bk如果您想使用与
/var/lib/使用的不同的后端文件系统,请格式化文件系统并将其挂载到/var/lib/docker。确保将此挂载点添加到/etc/fstab以使其永久生效。编辑
/etc/docker/daemon.json。如果它尚不存在,请创建它。假设该文件为空,则添加以下内容。{ "storage-driver": "overlay2" }如果
daemon.json文件包含无效的 JSON,则 Docker 不会启动。启动 Docker。
$ sudo systemctl start docker验证守护程序是否正在使用
overlay2存储驱动程序。使用docker info命令并查找Storage Driver和Backing filesystem。$ docker info Containers: 0 Images: 0 Storage Driver: overlay2 Backing Filesystem: xfs Supports d_type: true Native Overlay Diff: true <...>
Docker 现在正在使用overlay2存储驱动程序,并已自动创建具有所需lowerdir、upperdir、merged和workdir结构的覆盖挂载点。
继续阅读有关 OverlayFS 如何在您的 Docker 容器中工作,以及有关其与不同后端文件系统兼容性限制的性能建议和信息。
overlay2驱动程序的工作原理
OverlayFS 将两个目录叠加在一个 Linux 主机上,并将它们显示为单个目录。这些目录称为层,合并过程称为联合挂载。OverlayFS 将下层目录称为lowerdir,将上层目录称为upperdir。统一视图通过其自己的目录merged公开。
overlay2驱动程序原生支持最多 128 个下层 OverlayFS 层。此功能可为与层相关的 Docker 命令(例如docker build和docker commit)提供更好的性能,并在后端文件系统上消耗更少的 inode。
磁盘上的镜像和容器层
使用docker pull ubuntu下载一个五层镜像后,您可以在/var/lib/docker/overlay2下看到六个目录。
警告
不要直接操作
/var/lib/docker/中的任何文件或目录。这些文件和目录由 Docker 管理。
$ ls -l /var/lib/docker/overlay2
total 24
drwx------ 5 root root 4096 Jun 20 07:36 223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7
drwx------ 3 root root 4096 Jun 20 07:36 3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b
drwx------ 5 root root 4096 Jun 20 07:36 4e9fa83caff3e8f4cc83693fa407a4a9fac9573deaf481506c102d484dd1e6a1
drwx------ 5 root root 4096 Jun 20 07:36 e8876a226237217ec61c4baf238a32992291d059fdac95ed6303bdff3f59cff5
drwx------ 5 root root 4096 Jun 20 07:36 eca1e4e1694283e001f200a667bb3cb40853cf2d1b12c29feda7422fed78afed
drwx------ 2 root root 4096 Jun 20 07:36 l
新的l(小写L)目录包含作为符号链接的缩短的层标识符。这些标识符用于避免遇到对mount命令的参数的页面大小限制。
$ ls -l /var/lib/docker/overlay2/l
total 20
lrwxrwxrwx 1 root root 72 Jun 20 07:36 6Y5IM2XC7TSNIJZZFLJCS6I4I4 -> ../3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 B3WWEFKBG3PLLV737KZFIASSW7 -> ../4e9fa83caff3e8f4cc83693fa407a4a9fac9573deaf481506c102d484dd1e6a1/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 JEYMODZYFCZFYSDABYXD5MF6YO -> ../eca1e4e1694283e001f200a667bb3cb40853cf2d1b12c29feda7422fed78afed/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 NFYKDW6APBCCUCTOUSYDH4DXAT -> ../223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 UL2MW33MSE3Q5VYIKBRN4ZAGQP -> ../e8876a226237217ec61c4baf238a32992291d059fdac95ed6303bdff3f59cff5/diff
最低层包含一个名为link的文件,其中包含缩短标识符的名称,以及一个名为diff的目录,其中包含层的 内容。
$ ls /var/lib/docker/overlay2/3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/
diff link
$ cat /var/lib/docker/overlay2/3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/link
6Y5IM2XC7TSNIJZZFLJCS6I4I4
$ ls /var/lib/docker/overlay2/3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/diff
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
第二低的层,以及每一层更高的层,都包含一个名为lower的文件,该文件表示其父层,以及一个名为diff的目录,其中包含其内容。它还包含一个merged目录,其中包含其父层和自身的内容的统一视图,以及一个work目录,OverlayFS内部使用该目录。
$ ls /var/lib/docker/overlay2/223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7
diff link lower merged work
$ cat /var/lib/docker/overlay2/223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7/lower
l/6Y5IM2XC7TSNIJZZFLJCS6I4I4
$ ls /var/lib/docker/overlay2/223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7/diff/
etc sbin usr var
要查看在 Docker 中使用overlay存储驱动程序时存在的挂载点,请使用mount命令。以下输出为了易读性而被截断。
$ mount | grep overlay
overlay on /var/lib/docker/overlay2/9186877cdf386d0a3b016149cf30c208f326dca307529e646afce5b3f83f5304/merged
type overlay (rw,relatime,
lowerdir=l/DJA75GUWHWG7EWICFYX54FIOVT:l/B3WWEFKBG3PLLV737KZFIASSW7:l/JEYMODZYFCZFYSDABYXD5MF6YO:l/UL2MW33MSE3Q5VYIKBRN4ZAGQP:l/NFYKDW6APBCCUCTOUSYDH4DXAT:l/6Y5IM2XC7TSNIJZZFLJCS6I4I4,
upperdir=9186877cdf386d0a3b016149cf30c208f326dca307529e646afce5b3f83f5304/diff,
workdir=9186877cdf386d0a3b016149cf30c208f326dca307529e646afce5b3f83f5304/work)
第二行上的rw表示overlay挂载点是读写的。
下图显示了 Docker 镜像和 Docker 容器如何分层。镜像层是lowerdir,容器层是upperdir。如果镜像有多个层,则使用多个lowerdir目录。统一视图通过名为merged的目录公开,该目录实际上是容器的挂载点。

如果镜像层和容器层包含相同的文件,则容器层 (upperdir) 优先,并隐藏镜像层中相同文件的存在。
要创建容器,overlay2驱动程序将表示镜像顶层的目录与容器的新目录组合在一起。镜像的层是 overlay 中的lowerdirs,并且是只读的。容器的新目录是upperdir,并且是可写的。
磁盘上的镜像和容器层
以下docker pull命令显示 Docker 主机正在下载包含五个层的 Docker 镜像。
$ docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
5ba4f30e5bea: Pull complete
9d7d19c9dc56: Pull complete
ac6ad7efd0f9: Pull complete
e7491a747824: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:46fb5d001b88ad904c5c732b086b596b92cfb4a4840a3abd0e35dbb6870585e4
Status: Downloaded newer image for ubuntu:latest
镜像层
每个镜像层在/var/lib/docker/overlay/中都有自己的目录,其中包含其内容,如下例所示。镜像层 ID 与目录 ID 不对应。
警告
不要直接操作
/var/lib/docker/中的任何文件或目录。这些文件和目录由 Docker 管理。
$ ls -l /var/lib/docker/overlay/
total 20
drwx------ 3 root root 4096 Jun 20 16:11 38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8
drwx------ 3 root root 4096 Jun 20 16:11 55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358
drwx------ 3 root root 4096 Jun 20 16:11 824c8a961a4f5e8fe4f4243dab57c5be798e7fd195f6d88ab06aea92ba931654
drwx------ 3 root root 4096 Jun 20 16:11 ad0fe55125ebf599da124da175174a4b8c1878afe6907bf7c78570341f308461
drwx------ 3 root root 4096 Jun 20 16:11 edab9b5e5bf73f2997524eebeac1de4cf9c8b904fa8ad3ec43b3504196aa3801
镜像层目录包含该层特有的文件以及与较低层共享数据的硬链接。这允许有效地利用磁盘空间。
$ ls -i /var/lib/docker/overlay2/38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8/root/bin/ls
19793696 /var/lib/docker/overlay2/38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8/root/bin/ls
$ ls -i /var/lib/docker/overlay2/55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358/root/bin/ls
19793696 /var/lib/docker/overlay2/55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358/root/bin/ls
容器层
容器也存在于 Docker 主机文件系统的/var/lib/docker/overlay/下。如果使用ls -l命令列出正在运行的容器的子目录,则存在三个目录和一个文件。
$ ls -l /var/lib/docker/overlay2/<directory-of-running-container>
total 16
-rw-r--r-- 1 root root 64 Jun 20 16:39 lower-id
drwxr-xr-x 1 root root 4096 Jun 20 16:39 merged
drwxr-xr-x 4 root root 4096 Jun 20 16:39 upper
drwx------ 3 root root 4096 Jun 20 16:39 work
lower-id文件包含容器所基于的镜像顶层的 ID,它是 OverlayFS 的lowerdir。
$ cat /var/lib/docker/overlay2/ec444863a55a9f1ca2df72223d459c5d940a721b2288ff86a3f27be28b53be6c/lower-id
55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358
upper目录包含容器读写层的内容,对应于 OverlayFS 的upperdir。
merged目录是lowerdir和upperdirs的联合挂载,它包含从正在运行的容器内看到的的文件系统视图。
work目录是 OverlayFS 的内部目录。
要查看在 Docker 中使用overlay2存储驱动程序时存在的挂载点,请使用mount命令。以下输出为了易读性而被截断。
$ mount | grep overlay
overlay on /var/lib/docker/overlay2/l/ec444863a55a.../merged
type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/55f1e14c361b.../root,
upperdir=/var/lib/docker/overlay2/l/ec444863a55a.../upper,
workdir=/var/lib/docker/overlay2/l/ec444863a55a.../work)
第二行上的rw表示overlay挂载点是读写的。
overlay2如何处理容器的读写操作
读取文件
考虑三个场景,其中容器使用 overlay 打开文件进行读取访问。
容器层中不存在该文件
如果容器打开文件进行读取访问,并且该文件尚不存在于容器 (upperdir) 中,则从镜像 (lowerdir) 读取该文件。这几乎不会产生性能开销。
该文件仅存在于容器层
如果容器打开文件进行读取访问,并且该文件存在于容器 (upperdir) 中,而不存在于镜像 (lowerdir) 中,则直接从容器读取该文件。
该文件存在于容器层和镜像层中
如果容器打开文件进行读取访问,并且该文件存在于镜像层和容器层中,则读取容器层中的文件版本。容器层 (upperdir) 中的文件会隐藏镜像层 (lowerdir) 中同名文件。
修改文件或目录
考虑一些修改容器中文件的场景。
首次写入文件
容器第一次写入现有文件时,该文件不存在于容器 (upperdir) 中。overlay2驱动程序执行copy_up操作,将文件从镜像 (lowerdir) 复制到容器 (upperdir)。然后,容器将更改写入容器层中文件的新的副本。
但是,OverlayFS 在文件级别而不是块级别工作。这意味着所有 OverlayFS 的copy_up操作都会复制整个文件,即使文件很大,并且仅修改了文件的一小部分。这可能会对容器写入性能产生明显的影响。但是,有两点需要注意
copy_up操作仅在第一次写入给定文件时发生。随后对同一文件的写入操作针对已复制到容器的文件副本进行操作。OverlayFS 可与多个层一起工作。这意味着在搜索包含许多层的镜像中的文件时,可能会影响性能。
删除文件和目录
当在容器中删除文件时,会在容器 (
upperdir) 中创建一个白洞文件。镜像层 (lowerdir) 中的文件版本不会被删除(因为lowerdir是只读的)。但是,白洞文件会阻止容器访问该文件。当在容器中删除目录时,会在容器 (
upperdir) 中创建一个不透明目录。这与白洞文件的工作方式相同,并有效地阻止访问该目录,即使它仍然存在于镜像 (lowerdir) 中。
重命名目录
仅当源路径和目标路径都位于顶层时,才允许调用目录的rename(2)。否则,它将返回EXDEV错误(“不允许跨设备链接”)。您的应用程序需要设计为处理EXDEV并回退到“复制和取消链接”策略。
OverlayFS 和 Docker 性能
overlay2的性能可能比btrfs更好。但是,请注意以下细节
页面缓存
OverlayFS 支持页面缓存共享。访问同一文件的多个容器共享该文件的单个页面缓存条目。这使得overlay2驱动程序在内存方面效率很高,并且是 PaaS 等高密度用例的理想选择。
Copyup
与其他写时复制文件系统一样,每当容器第一次写入文件时,OverlayFS 都会执行复制操作。这可能会增加写入操作的延迟,尤其对于大型文件而言。但是,一旦文件被复制,对该文件的所有后续写入都发生在上层,无需进一步的复制操作。
性能最佳实践
以下通用性能最佳实践适用于 OverlayFS。
使用快速存储
固态驱动器 (SSD) 比旋转磁盘提供更快的读写速度。
对写入密集型工作负载使用卷
卷为写入密集型工作负载提供最佳且最可预测的性能。这是因为它们绕过了存储驱动程序,不会产生精简配置和写时复制带来的任何潜在开销。卷还有其他好处,例如允许您在容器之间共享数据,即使没有正在运行的容器使用它们,也可以持久保存您的数据。
OverlayFS 兼容性限制
总结 OverlayFS 与其他文件系统不兼容的方面
open(2)- OverlayFS 只实现 POSIX 标准的一个子集。这可能导致某些 OverlayFS 操作违反 POSIX 标准。其中一项操作是复制操作。假设您的应用程序调用
fd1=open("foo", O_RDONLY),然后调用fd2=open("foo", O_RDWR)。在这种情况下,您的应用程序期望fd1和fd2引用同一文件。但是,由于在第二次调用open(2)后发生的复制操作,描述符引用不同的文件。fd1继续引用镜像 (lowerdir) 中的文件,而fd2引用容器 (upperdir) 中的文件。对此的解决方法是touch文件,这会导致复制操作发生。所有后续的open(2)操作,无论读写模式如何,都将引用容器 (upperdir) 中的文件。除非安装了
yum-plugin-ovl包,否则已知yum会受到影响。如果在您的发行版(例如 RHEL/CentOS 6.8 或 7.2 之前的版本)中没有yum-plugin-ovl包,则可能需要在运行yum install之前运行touch /var/lib/rpm/*。此包实现了上面提到的yum的touch解决方法。 rename(2)- OverlayFS 不完全支持
rename(2)系统调用。您的应用程序需要检测其失败并回退到“复制和取消链接”策略。