使用 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 指的是下层目录 aslowerdir
和上层目录 a upperdir
。统一视图通过其自己的名为 的目录公开merged
。
该overlay2
驱动程序本身支持多达 128 个较低的 OverlayFS 层。此功能为与层相关的 Docker 命令(例如docker build
和docker commit
)提供了更好的性能,并在支持文件系统上消耗更少的 inode。
磁盘上的映像和容器层
使用 下载完五层镜像后docker pull ubuntu
,可以看到 下有 6 个目录/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
overlay
要查看将存储驱动程序与 Docker 结合使用时存在的挂载,请使用以下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
叠加层中并且是只读的。容器的新目录是 theupperdir
并且是可写的。
磁盘上的映像和容器层
以下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 内部。
overlay2
要查看将存储驱动程序与 Docker 结合使用时存在的挂载,请使用以下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一起读写
读取文件
考虑容器打开文件以通过覆盖进行读取访问的三种场景。
容器层不存在该文件
如果容器打开文件进行读取访问,并且该文件尚不存在于容器 ( upperdir
) 中,则会从映像 ( lowerdir
) 中读取该文件。这会产生非常小的性能开销。
该文件只存在于容器层
如果容器打开文件进行读取访问,并且该文件存在于容器 ( upperdir
) 中而不是映像 ( lowerdir
) 中,则直接从容器中读取该文件。
该文件同时存在于容器层和镜像层
如果容器打开一个文件进行读访问,并且该文件存在于镜像层和容器层中,则读取该文件在容器层中的版本。容器层(upperdir
)中的文件掩盖了镜像层( )中的同名文件lowerdir
。
修改文件或目录
考虑一些修改容器中的文件的场景。
第一次写入文件
容器第一次写入现有文件时,该文件在容器中不存在 ( upperdir
)。驱动overlay2
程序执行
copy_up
将文件从映像 ( lowerdir
) 复制到容器 ( upperdir
) 的操作。然后,容器将更改写入容器层中文件的新副本。
然而,OverlayFS 在文件级别而不是块级别工作。这意味着所有 OverlayFScopy_up
操作都会复制整个文件,即使文件很大并且只修改了其中的一小部分。这会对容器写入性能产生显着影响。然而,有两件事值得注意:
该
copy_up
操作仅在第一次写入给定文件时发生。对同一文件的后续写入将针对已复制到容器的文件副本进行操作。OverlayFS 适用于多个层。这意味着在具有多层的图像中搜索文件时,性能可能会受到影响。
删除文件和目录
当删除容器内的文件时,会在容器中创建一个空白
upperdir
文件 ( )。图像层 ( ) 中的文件版本lowerdir
不会被删除(因为它lowerdir
是只读的)。但是,whiteout 文件会阻止容器使用它。当删除容器内的目录时,会在容器内创建一个不透明目录
upperdir
( )。这与whiteout文件的工作方式相同,并且有效地防止目录被访问,即使它仍然存在于图像中(lowerdir
)。
重命名目录
rename(2)
只有当源路径和目的路径都在顶层时,才允许调用目录。否则,它将返回EXDEV
错误(“不允许跨设备链接”)。您的应用程序需要设计为能够处理EXDEV
和回退到“复制和取消链接”策略。
OverlayFS 和 Docker 性能
overlay2
可能比 表现更好btrfs
。但是,请注意以下详细信息:
页面缓存
OverlayFS 支持页面缓存共享。访问同一文件的多个容器共享该文件的单个页面缓存条目。这使得overlay2
驱动程序能够高效利用内存,并且是 PaaS 等高密度用例的良好选择。
复制
与其他写时复制文件系统一样,每当容器首次写入文件时,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
yum-plugin-ovl
除非安装该软件包,否则已知会受到影响。如果yum-plugin-ovl
您的发行版(例如 6.8 或 7.2 之前的 RHEL/CentOS)中没有该软件包,您可能需要在touch /var/lib/rpm/*
运行yum install
.该包实现了touch
上面提到的yum
. rename(2)
- OverlayFS不完全支持
rename(2)
系统调用。您的应用程序需要检测其故障并回退到“复制并取消链接”策略。