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 驱动程序将表示镜像顶层的目录与容器的新目录结合起来。镜像的层是覆盖层中的 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。
使用快速存储
固态硬盘(SSDs)比旋转磁盘提供更快的读写速度。
使用卷来处理写密集型工作负载
卷为写密集型工作负载提供了最佳和最可预测的性能。这是因为它们绕过了存储驱动程序,并且不会因精简配置和写时复制而引入任何潜在的开销。卷还有其他好处,例如允许您在容器之间共享数据,并且即使没有运行的容器使用它们,也能持久化您的数据。
OverlayFS兼容性的限制
总结OverlayFS与其他文件系统不兼容的方面:
open(2)- OverlayFS only implements a subset of the POSIX standards.
This can result in certain OverlayFS operations breaking POSIX standards. One
such operation is the copy-up operation. Suppose that your application calls
fd1=open("foo", O_RDONLY)and thenfd2=open("foo", O_RDWR). In this case, your application expectsfd1andfd2to refer to the same file. However, due to a copy-up operation that occurs after the second calling toopen(2), the descriptors refer to different files. Thefd1continues to reference the file in the image (lowerdir) and thefd2references the file in the container (upperdir). A workaround for this is totouchthe files which causes the copy-up operation to happen. All subsequentopen(2)operations regardless of read-only or read-write access mode reference the file in the container (upperdir).yum已知会受到影响,除非安装了yum-plugin-ovl包。 如果您的发行版(如 RHEL/CentOS 6.8 或 7.2 之前的版本)中没有yum-plugin-ovl包, 您可能需要在运行yum install之前运行touch /var/lib/rpm/*。 此包实现了上述针对yum的touch解决方法。 rename(2)- OverlayFS does not fully support the
rename(2)system call. Your application needs to detect its failure and fall back to a "copy and unlink" strategy.