OverlayFS 存储驱动程序

OverlayFS 是一个联合文件系统。

本页将 Linux 内核驱动程序称为 Docker storage 驱动程序设置为 .OverlayFSoverlay2

注意

对于 driver,请查看 Rootless mode 文档fuse-overlayfs

先决条件

OverlayFS 是推荐的存储驱动程序,如果您满足以下条件,则支持 OverlayFS 先决条件:

  • Linux 内核 4.0 或更高版本,或者使用 内核版本 3.10.0-514 或更高版本。

  • 该驱动程序在后备文件系统上受支持, 但仅限于 enabled。overlay2xfsd_type=true

    用于验证选项是否设置为 。要正确格式化文件系统,请使用标志 .xfs_infoftype1xfs-n ftype=1

  • 更改存储驱动程序会导致现有容器和镜像无法访问 在本地系统上。用于保存您构建的任何镜像,或 在更改存储驱动程序之前,将它们推送到 Docker Hub 或私有注册表, 这样您就不需要在以后重新创建它们。docker save

使用 overlay2 存储驱动程序配置 Docker

在执行此过程之前,您必须首先满足所有先决条件

以下步骤概述了如何配置存储驱动程序。overlay2

  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"
    }

    如果文件包含无效的 JSON,则 Docker 不会启动。daemon.json

  5. 启动 Docker。

    $ sudo systemctl start docker
    
  6. 验证守护程序是否正在使用存储驱动程序。 使用命令并查找 和 。overlay2docker infoStorage DriverBacking filesystem

    $ docker info
    
    Containers: 0
    Images: 0
    Storage Driver: overlay2
     Backing Filesystem: xfs
     Supports d_type: true
     Native Overlay Diff: true
    <...>
    

Docker 现在正在使用存储驱动程序,并自动 使用所需的 、 创建了覆盖挂载 和构造。overlay2lowerdirupperdirmergedworkdir

继续阅读有关 OverlayFS 如何在 Docker 中工作的详细信息 容器,以及性能建议和有关限制的信息 它与不同后备文件系统的兼容性。

overlay2 驱动程序的工作原理

OverlayFS 在单个 Linux 主机上对两个目录进行分层,并将它们显示为 单个目录。这些目录称为 层,而 unification 进程称为联合挂载。OverlayFS 引用较低的目录 as 和上层目录 a .统一视图公开 通过其自己的名为 .lowerdirupperdirmerged

该驱动程序本机支持多达 128 个较低的 OverlayFS 层。这 功能为与层相关的 Docker 命令提供更好的性能,例如 as 和 ,并且占用更少的 inode 文件系统。overlay2docker builddocker commit

磁盘上的镜像和容器层

使用 下载五层镜像后,您可以看到 下的 6 个目录。docker pull ubuntu/var/lib/docker/overlay2

警告

请勿直接操作 中的任何文件或目录。这些文件和目录由 Docker 管理。/var/lib/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

新(小写)目录包含缩短的层标识符,如 符号链接。这些标识符用于避免影响页面大小 对命令参数的限制。lLmount

$ 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

最低层包含一个名为 的文件,其中包含 shortened 标识符,以及一个名为 图层的内容。linkdiff

$ 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

第二低的图层和每个较高的图层都包含一个名为 、 的文件 which 表示其父级,以及一个名为 的目录,其中包含其 内容。它还包含一个目录,其中包含统一的 其父层及其自身的内容,以及使用的目录 内部由 OverlayFS 提供。lowerdiffmergedwork

$ 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,请使用命令。为了提高可读性,下面的输出被截断。overlaymount

$ 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)

第二行的 the 表示挂载是读写的。rwoverlay

下图显示了 Docker 镜像和 Docker 容器的 分层的。镜像层是 ,容器层是 .如果镜像具有多个图层,则多个目录 使用。统一视图通过名为 which 的目录公开 实际上是容器挂载点。lowerdirupperdirlowerdirmerged

How Docker constructs map to OverlayFS constructs

其中镜像层和容器层包含相同的文件, Container layer () 优先并掩盖 镜像层中的相同文件。upperdir

为了创建容器,驱动程序将表示 镜像的顶层加上容器的新目录。镜像的 图层位于叠加层中,并且是只读的。的新目录 容器是 和 是可写的。overlay2lowerdirsupperdir

磁盘上的镜像和容器层

以下命令显示了下载 Docker 的 Docker 主机 镜像包含五个图层。docker pull

$ 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

镜像图层

每个镜像图层在 中都有自己的目录,该目录 包含其内容,如以下示例所示。镜像图层 ID 与目录 ID 不对应。/var/lib/docker/overlay/

警告

请勿直接操作 中的任何文件或目录。这些文件和目录由 Docker 管理。/var/lib/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

该文件包含容器镜像顶层的 ID 基于,即 OverlayFS 。lower-idlowerdir

$ cat /var/lib/docker/overlay2/ec444863a55a9f1ca2df72223d459c5d940a721b2288ff86a3f27be28b53be6c/lower-id

55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358

该目录包含容器的读写层 它对应于 OverlayFS 。upperupperdir

该目录是 和 的联合挂载,它 包含正在运行的容器中的文件系统视图。mergedlowerdirupperdirs

该目录是 OverlayFS 的内部目录。work

查看在将存储驱动程序与 Docker,请使用命令。以下输出被截断 可读性。overlay2mount

$ 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)

第二行的 the 表示挂载是读写的。rwoverlay

容器读取和写入如何与 overlay2 配合使用

读取文件

考虑三种情况,其中容器使用 覆盖。

文件在容器层中不存在

如果容器打开文件以进行读取访问,并且该文件尚不存在 在容器中 () 中,它是从镜像 () 中读取的。这 产生的性能开销非常小。upperdirlowerdir

该文件仅存在于容器层中

如果容器打开一个文件进行读取访问,并且该文件存在于 container () 而不是在镜像 () 中,则直接读取它 从容器中。upperdirlowerdir

该文件同时存在于容器层和镜像层中

如果容器打开文件进行读取访问,并且该文件存在于镜像中 layer 和容器层,则文件在容器层中的版本为 读。容器层中的文件 () 会遮盖具有相同 name 在镜像图层 () 中。upperdirlowerdir

修改文件或目录

请考虑修改容器中文件的一些情况。

首次写入文件

容器首次写入现有文件时,该文件不会 存在于容器中 () 中。驱动程序执行一个操作,将文件从镜像 () 复制到 容器 ()。然后,容器将更改写入新副本 的文件。upperdiroverlay2copy_uplowerdirupperdir

但是,OverlayFS 在文件级别而不是块级别工作。这 表示所有 OverlayFS 操作都会复制整个文件,即使 文件很大,并且只有一小部分被修改。这可以有 对容器写入性能有明显影响。然而,有两件事是 值得注意的是:copy_up

  • 该操作仅在首次写入给定文件时发生 自。对同一文件的后续写入将对文件的副本进行操作 已复制到容器。copy_up

  • OverlayFS 适用于多个图层。这意味着性能可以是 在包含多个图层的镜像中搜索文件时受到影响。

删除文件和目录

  • 在容器中删除文件时,将在 容器 ()。镜像层中的文件版本 () 不会被删除(因为 是只读的)。然而 whiteout 文件会阻止它对容器可用。upperdirlowerdirlowerdir

  • 删除容器中的目录时,不透明目录为 在容器中创建 ()。其工作方式与 whiteout 文件,并有效阻止目录被访问, 即使它仍然存在于镜像中 () 中。upperdirlowerdir

重命名目录

仅当源和 目标路径位于顶层。否则,它将返回 error (“不允许跨设备链接”)。您的应用程序需要设计为 处理并回退到 “Copy and unlink” 策略。rename(2)EXDEVEXDEV

OverlayFS 和 Docker 性能

overlay2可能比 性能更好。但是,请注意以下详细信息:btrfs

页面缓存

OverlayFS 支持页面缓存共享。多个容器访问相同的 文件共享该文件的单个页面缓存条目。这使得驱动程序能够高效地使用内存,并且是高密度用例的不错选择,例如 作为 PaaS。overlay2

复制

与其他写入时复制文件系统一样,OverlayFS 执行复制操作 每当容器首次写入文件时。这可能会增加延迟 写入操作,尤其是对于大文件。但是,一旦文件 已复制,则对该文件的所有后续写入都发生在上部 层,而无需进一步的复制操作。

性能最佳实践

以下通用性能最佳实践适用于 OverlayFS。

使用快速存储

固态驱动器 (SSD) 的读取和写入速度比旋转磁盘更快。

将卷用于写入密集型工作负载

卷为写入密集型数据提供最佳且最可预测的性能 工作量。这是因为它们绕过了存储驱动程序,并且不会产生任何 精简配置和写入时复制可能引入的开销。 卷还有其他好处,例如允许您在 容器并保留数据,即使没有正在运行的容器正在使用它们。

OverlayFS 兼容性限制

总结 OverlayFS 与其他不兼容的方面 文件系统:

open(2)
OverlayFS 仅实现 POSIX 标准的子集。 这可能会导致某些 OverlayFS 操作违反 POSIX 标准。一 此类操作称为复制操作。假设您的应用程序先调用 .在这种情况下, 您的应用程序期望 和 引用同一个文件。然而,由于 复制到第二次调用 后发生的复制操作中, 描述符引用不同的文件。继续引用文件 在镜像 () 中,并引用容器中的文件 ().解决方法是针对导致 复制操作。所有后续操作,无论 read-only 或 read-write 访问模式引用 容器 ()。fd1=open("foo", O_RDONLY)fd2=open("foo", O_RDWR)fd1fd2open(2)fd1lowerdirfd2upperdirtouchopen(2)upperdir

yum已知会受到影响,除非安装了该软件包。 如果该软件包在您的分配中不可用,例如 低于 6.8 或 7.2 的 RHEL/CentOS,您可能需要先运行,然后再运行 。此软件包实现了解决方法 上文中引用的 。yum-plugin-ovlyum-plugin-ovltouch /var/lib/rpm/*yum installtouchyum

rename(2)
OverlayFS 不完全支持 system 调用。你 应用程序需要检测其故障并回退到“复制并取消链接” 策略。rename(2)