OverlayFS 是一个类似于 AUFS 的现代联合文件系统,但速度更快且实现更简单。Docker为OverlayFS提供了两个存储驱动程序:原始的overlay和更新更稳定的overlay2
将Linux内核驱动程序称为OverlayFS以及Docker存储驱动程序overlay或overlay2
注意:如果使用OverlayFS,请使用overlay2驱动程序,而不是overlay驱动程序,因为它在inode利用率方面更高效。要使用新的驱动程序,您需要4.0版或更高版本的Linux内核,或者使用3.10.0-514版或更高版本的RHEL或CentOS。
先决条件:
OverlayFS 是推荐的存储驱动程序,如果您满足以下先决条件,则支持该驱动程序:
☑ Linux 内核的 4.0 或更高版本,或者使用 3.10.0-514 或更高版本内核的 RHEL 或 CentOS。如果使用较旧的内核,则需要使用overlay驱动程序,不推荐使用。
☑ 在xfs备份文件系统上支持overlay和overlay2驱动程序,但只有启用 d_type=true 时才支持。
用于xfs_info验证该ftype选项是否设置为1。要正确格式化 xfs文件系统,请使用flag -n ftype=1。
警告:在没有 d_type 支持的 XFS 上运行现在会导致 Docker 跳过使用overlayoroverlay2驱动程序的尝试。现有安装将继续运行,但会产生错误。这允许用户迁移他们的数据。在未来的版本中,这将是一个致命的错误,它将阻止Docker启动。
☑ 更改存储驱动程序将使本地系统上无法访问现有的容器和映像。在更改存储驱动程序之前,使用docker save保存您已经构建的映像,或将它们推到docker Hub或私有注册表中,这样您就不需要在以后重新创建它们。
为Docker配置overlay或overlay2存储驱动程序
如果可能的话,强烈建议使用overlay2驱动程序,而不是overlay驱动程序。Docker EE不支持覆盖驱动程序。
要将 Docker 配置为使用overlay存储驱动程序,您的 Docker 主机必须运行 3.18 版的 Linux 内核(最好是更新的)并加载了覆盖内核模块。对于overlay2驱动程序,您的内核版本必须为 4.0 或更高版本。
以下步骤概述了如何配置overlay2存储驱动程序。如果您需要使用旧版overlay驱动程序,请指定它。
1.停止 Docker。
sudo systemctl stop docker
2.将内容复制/var/lib/docker到临时位置。
cp -au /var/lib/docker /var/lib/docker.bk
3.如果你想使用与/var/lib/使用的文件系统不同的备份文件系统,格式化文件系统并将其挂载到/var/lib/docker中。确保将此挂载添加到/etc/fstab,使其永久。
4.编辑/etc/docker/daemon.json. 如果它尚不存在,请创建它。假设文件为空,添加以下内容。
{
"storage-driver": "overlay2"
}
daemon.json如果文件包含格式错误的JSON,Docker 不会启动。
5.启动 Docker。
sudo systemctl start docker
验证守护程序是否正在使用overlay2存储驱动程序。使用docker info命令并查找Storage Driverand 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结构。
overlay2驱动是如何工作的
OverlayFS将单个Linux主机上的两个目录分层,并将它们显示为单个目录。这些目录称为层,统一过程称为联合挂载
。OverlayFS将下面的目录称为lowerdir,上面的目录称为upperdir。统一视图通过其自己的名为merged的目录公开。
overlay2驱动程序本机支持最多128个较低的OverlayFS层。该功能为与层相关的Docker命令 (如Docker build和Docker commit) 提供了更好的性能,并在后台文件系统上消耗更少的inode。
☑ 磁盘上的映像和容器层
在使用docker pull ubuntu下载五层图像后,你可以看到/var/lib/docker/overlay2下有六个目录
$ 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
警告:不要直接操作/var/lib/docker/中的任何文件或目录。这些文件和目录由Docker管理。
···
新的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的目录,其中包含父层和自身的统一内容,以及OverlayFS内部使用的work目录。
$ 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
使用mount命令查看Docker使用overlay存储驱动程序时存在的挂载。
$ 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)
☑ overlay驱动程序是如何工作的
OverlayFS将单个Linux主机上的两个目录分层,并将它们显示为单个目录
。这些目录称为层,统一过程称为联合挂载。OverlayFS将下面的目录称为lowerdir,上面的目录称为upperdir。统一视图通过其自己的名为merged的目录公开。
下图显示了Docker映像和Docker容器是如何分层的。 image layer是下目录,container layer是上目录。统一视图通过名为merged的目录公开,该目录实际上是容器的挂载点。该图显示了Docker结构如何映射到OverlayFS结构。
当image layer和container layer包含相同的文件时,container层“wins”并掩盖了image layer中相同文件的存在。
overlay驱动程序只适用于两层。这意味着multi-layered不能实现为多个OverlayFS层。相反,每个image层都被实现为其在/var/lib/docker/overlay下的单独目录。然后使用硬链接作为一种节省空间的方式来引用与较低层共享的数据。硬链接的使用会导致索引节点的过度使用,这是已知的遗留覆盖存储驱动程序的限制,并且可能需要对备份文件系统进行额外的配置。
要创建容器,overlay驱动程序将表示image’s顶层的目录和容器的新目录组合在一起。image的顶层是lowerdir并且是只读的。容器的新目录是upperdir并且是可写的。
☑ 磁盘上的映像和container层
下面的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
image层:
每个iamge层在/var/lib/docker/overlay/中都有自己的目录,其中包含了它的内容,如下所示镜像层id与目录id不对应。
warning:不要直接操作/var/lib/docker/中的任何文件或目录。这些文件和目录由Docker管理。
iamge层目录包含该层特有的文件以及与较lower layers共享的数据的硬链接。这允许有效地使用磁盘空间。
容器层:
Containers 也存在于Docker主机的文件系统/var/lib/docker/overlay/下的磁盘上。如果使用ls -l命令列出正在运行的容器的子目录,则存在三个目录和两个文件
$ ls -l /var/lib/docker/overlay/<directory-of-running-container>
total 16
-rw-r--r-- 1 root root 64 Jun 20 16:39 lower-id # lower-id文件包含contains所基于的 image顶层的ID,即OverlayFS的lowerdir(lower:底部)
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
$ cat /var/lib/docker/overlay/ec444863a55a9f1ca2df72223d459c5d940a721b2288ff86a3f27be28b53be6c/lower-id
55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358
upper目录包含容器的读写层的内容,它对应于OverlayFS的upper目录
merged的目录是lowerdir和upperdir的联合挂载,它们组成了运行容器中的文件系统视图
work目录是OverlayFS内部的
使用mount命令查看Docker使用overlay存储驱动程序时存在的挂载。为了可读性下面的输出被截断了:
$ mount | grep overlay
overlay on /var/lib/docker/overlay/ec444863a55a.../merged
type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay/55f1e14c361b.../root, 第二行上的rw表示overlay挂载是读写的。
upperdir=/var/lib/docker/overlay/ec444863a55a.../upper,
workdir=/var/lib/docker/overlay/ec444863a55a.../work)
容器读写如何与overlay或overlay2一起工作
Reading files
考虑三种场景,其中容器用overlay打开文件进行读访问。
该文件在容器层中不存在: 如果容器打开一个文件进行读访问,而该文件还不存在于容器(upperdir)中,则从image(lowerdir)中读取该文件。这带来的性能开销非常小。
该文件只存在于容器层中: 如果容器打开一个文件进行读访问,而该文件存在于容器中(upperdir)而不在映像中(lowerdir),则直接从容器中读取它。
文件既存在于容器层,也存在于映像层: 如果一个容器打开一个文件进行读访问,并且该文件存在于映像层和容器层中,则读取该文件在容器层中的版本。container层(upperdir)中的文件掩盖了image层 (lowerdir) 中同名的文件。
Modifying files or directories
考虑一些修改容器中的文件的场景:
Writing to a file for the first time:
当容器第一次写入现有文件时,该文件在容器中不存在(upperdir)。overlay/overlay2驱动程序执行一个copy_up操作,将文件从映像(lowerdir)复制到容器(upperdir)。然后容器将更改写入容器层中的文件的新副本。
然而,OverlayFS工作在file级别而不是块级别。这意味着所有OverlayFS copy_up操作都会复制整个文件,即使文件非常大,只修改了其中的一小部分。这可能会对容器写性能产生显著影响。不管怎样有两件事值得注意:
○ copy_up操作只在第一次写入给定文件时发生。对同一文件的后续写入操作对已经复制到容器中的文件的副本进行操作。
○ OverlayFS只适用于两层。这意味着性能应该比AUFS更好,AUFS在有很多层的图像中搜索文件时可能会出现明显的延迟。这一优势适用于overlay和overlay2驱动程序。Overlayfs2在初始读取时的性能略低于overlayfs,因为它必须查看更多的层,但它缓存结果,因此这只是一个很小的损失。
Deleting files and directories:
○ 当删除容器中的文件时,将在容器中创建一个临时性文件(upperdir)。图像层文件(lowerdir)的版本没有被删除(因为lowerdir是只读的)。但是该临时性文件阻止它对容器可用。
○ 当在容器中删除一个目录时,在容器中创建一个不透明目录(upperdir)。这与whiteout文件的工作原理相同,可以有效地阻止访问目录,即使它仍然存在于映像中(lowerdir)
Renaming directories:
只有当源路径和目标路径都在顶层时,才允许对目录调用rename(2)。否则,它将返回EXDEV错误(“跨设备链接不允许”)。您的应用程序需要设计为处理EXDEV,并退回到“复制和断开链接”策略。
OverlayFS和Docker性能
overlay2和overlay驱动程序都比aufs和devicemapper的性能更好。在某些情况下,overlay2也可能比btrfs性能更好。但是要注意以下细节:
☑ Page Caching: OverlayFS支持页面缓存共享。访问同一文件的多个容器共享该文件的单个页面缓存条目。这使得overlay和overlay2驱动程序在内存方面效率很高,并且是高密度用例(如PaaS)的一个很好的选择。
☑ copy_up: 与AUFS一样,OverlayFS在容器第一次写入文件时执行复制操作。这可能会增加写操作的延迟,特别是对于大文件。需要注意一旦文件被复制,对该文件的所有后续写入都发生在上层,而不需要进一步的复制操作。
OverlayFS copy_up操作比AUFS的相同操作更快,因为AUFS比OverlayFS支持更多的层,如果搜索多个AUFS层,可能会产生更大的延迟。Overlay2也支持多层,但是可以减少缓存对性能的影响。
☑ Inode limits: 使用legacy overlay 存储驱动程序可能导致过多的inode消耗。当Docker主机上存在大量映像和容器时,尤其如此。增加文件系统可用的inode数量的唯一方法是重新格式化它。为了避免遇到这个问题,强烈建议尽可能使用overlay2。
☑ 性能最佳实践
下面的通用性能最佳实践也适用于OverlayFS。
Use fast storage: 固态硬盘(ssd)提供比旋转磁盘更快的读写。
Use volumes for write-heavy workloads: Volumes为写量大的工作负载提供了最佳和最可预测的性能。这是因为它们绕过存储驱动程序,不会产生精简配置和写时复制带来的任何潜在开销。卷还有其他好处,比如允许您在容器之间共享数据,并且即使没有正在运行的容器使用数据,也可以持久化数据。
OverlayFS兼容性的限制
总结OverlayFS与其他文件系统不兼容的方面:
☑ open(2): OverlayFS只实现了POSIX标准的一个子集。这可能导致某些OverlayFS操作违反POSIX标准。其中一个操作就是copy-up操作。假设您的应用程序调用fd1=open(“foo”, O_RDONLY) ,然后fd2=open(“foo”, O_RDWR)。在本例中,应用程序期望fd1和fd2引用相同的文件。然而,由于在第二次调用open(2)之后发生了复制操作,描述符引用的是不同的文件。fd1继续引用映像中的文件(lowerdir), fd2引用容器中的文件(upperdir)。对此的一个解决办法是接触导致复制操作发生的文件。所有后续的open(2)操作,无论只读或读写访问模式,都会引用容器(upperdir)中的文件。
已知Yum会受到影响,除非安装yum-plugin-ovl包。如果yum-plugin-ovl包在6.8或7.2之前的RHEL/CentOS发行版中不可用,您可能需要在运行yum install之前运行touch /var/lib/rpm/*。这个包实现了yum上面引用的触摸解决方案。
☑ rename(2): OverlayFS不完全支持rename(2)系统调用。您的应用程序需要检测它的失败,并退回到“copy and unlink” 策略。
Own destiny own control, at the foot of the road without stopping.