手机版

Docker用户指南(8) – OverlayFS存储驱动实践

时间:2020-03-11 来源:互联网 编辑:宝哥软件园 浏览:

OverlayFS是一个与AUFS类似的现代联合(union)文件系统。与AUFS比较,OverlayFS存在如下优势:

更简单的设计 从3.18版本开始已经进入Linux内核主线 可能更快

因此,OverlayFS在Docker社区迅速普及,许多人认为这可以代替AUFS。虽然OverlayFS发展前景很好,但仍然不够成熟。因此在生产环境上部署前,请慎重考虑。
Docker的overlay存储驱动利用OverlayFS几个功能来构建和管理镜像和容器在硬盘的结构。
从1.12版本起,Docker也提供了overlay2存储驱动,它比overlay在inode的使用方面更高效。不过overlay2只能用在Linux内核 4.0和更高的版本。
本文使用OverlayFS表示文件系统,overlay/overlay2表示存储驱动。

镜像分层及OverlayFS(overlay)共享

OverLayFS在一台Linux主机维护两个目录,一个在另一个上面,并提供一个统一的视图。这些目录通常称为数据层,用来叠加它们的技术叫做联合挂载(union mount)。OverlayFS底层称为“lowerdir”,顶层称为“upperdir”。通过它自己的”merged”目录提供一个统一视图。
下图显示一个Docker镜像和Docker容器是如何分层的。镜像数据层是“lowerdir”,容器数据层是”uppperdir”。通过目录为”merged”提供一个统一视图,该目录是容器的挂载点。下图显示Docker结构是如何映射到OverlayFS结构的。
Docker用户指南(8) – OverlayFS存储驱动实践
注意看容器数据层和镜像数据层能包含同样的文件。当出现此情况时,容器数据层”upperdir”的这个文件是显性的并隐藏了在镜像数据层“lowerdir”的相同文件的存在。容器挂载“merged”呈现一个统一视图。
overlay驱动只在两个层工作。这意味着多层的镜像无法实现为多个OverlayFS层。而是每个镜像数据层在自己的/var/lib/docker/overlay目录下实现多层关系。然后使用硬链接引用与更低层共享的数据。从Docker 1.10起,镜像数据层ID不再与/var/lib/docker下的目录名称相关。
要创建一个容器,overlay驱动将镜像顶层与一个新目录结合。镜像顶层是overlay的只读“lowerdir”。容器新的目录是可写的“upperdir”。

镜像和容器硬盘上的结构(overlay)示例

下面的docker pull命令显示Docker主机下载一个由5个层组成的Docker镜像。

$ sudo 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/下都有自己的对应目录。这些目录存储着每个镜像数据层的数据。
下面的命令输出显示5个存储着刚才下载的每个镜像数据层的数据的目录。不过就如你看到的镜像数据层ID没有匹配/var/lib/docker/overlay下目录的名称。

$ 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/overlay/38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8/root/bin/ls
 
19793696 /var/lib/docker/overlay/38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8/root/bin/ls
 
$ ls -i /var/lib/docker/overlay/55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358/root/bin/ls
 
19793696 /var/lib/docker/overlay/55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358/root/bin/ls

容器也在位于/var/lib/docker/overlay的Docker主机文件系统硬盘上。如果你使用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
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

这四个文件系统对象是OverlayFS的部件。lower-id文件包含容器基于的镜像的顶层ID。在OverlayFS上称为“loverdir”。

$ cat /var/lib/docker/overlay/ec444863a55a9f1ca2df72223d459c5d940a721b2288ff86a3f27be28b53be6c/lower-id
 
55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358

upper目录是容器的可写数据层。所有对容器的更改都是写到这个目录。
merged目录是容器的挂载点。这是镜像”loverdir”和容器“upperdir”的统一视图。任何对这个容器的修改将马上反映到这个目录。
work目录是OverlayFS执行操作时所需的目录。如执行copy_up操作。
你可以从mount命令的输出来验证这些结构。

$ mount | grep overlay
 
overlay on /var/lib/docker/overlay/ec444863a55a.../merged
type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay/55f1e14c361b.../root,
upperdir=/var/lib/docker/overlay/ec444863a55a.../upper,
workdir=/var/lib/docker/overlay/ec444863a55a.../work)

镜像分层和OverlayFS共享(overlay2)

overlay驱动仅支持单个lower OverlayFS层并且需要硬链接来实现多层的镜像,overlay2驱动原生支持多个lower OverlayFS层(最大到128层)。
因此overlay2驱动为与层相关的docker命令(如docker build和docker commit)提供了更好的性能,并且比overlay驱动消耗更少的inodes。

示例:镜像和容器在硬盘上的结构(overlay2)

使用docker pull ubuntu命令下载一个5层的镜像后,你可以在/var/lib/docker/overlay2目录下看到6个目录。

$ 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目录包含缩短的层标识符的软链接。这些缩短的标识符用于避免挂载参数的页大小限制。

$ 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目录。

$ 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

运行中的容器的目录也有类似的文件和目录。注意lower列表以冒号:分隔,并且从高层到低层排序。

$ ls -l /var/lib/docker/overlay/<directory-of-running-container>
 
$ cat /var/lib/docker/overlay/<directory-of-running-container>/lower
 
l/DJA75GUWHWG7EWICFYX54FIOVT:l/B3WWEFKBG3PLLV737KZFIASSW7:l/JEYMODZYFCZFYSDABYXD5MF6YO:l/UL2MW33MSE3Q5VYIKBRN4ZAGQP:l/NFYKDW6APBCCUCTOUSYDH4DXAT:l/6Y5IM2XC7TSNIJZZFLJCS6I4I4

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)

使用overlay进行容器的读和写

下面是容器使用ovelay对文件进行的读取操作的三个场景。

文件不在容器数据层。如果容器要打开读取一个文件且这个文件不在容器的upperdir目录,那它就从镜像的lowerdir读取。这个操作对性能影响很小。 文件只存在于容器数据层。如果一个容器打开读取一个文件且这个在容器的upperdir不在镜像的lowerdir,那么直接从容器读取文件。 文件既存在于容器数据层也存在于镜像数据层。如果一个容器打开一个既存在于镜像数据层也存在于容器数据层的文件,那么就读取在容器数据层的文件。这是因为在容器数据层upperdir的文件隐藏了在镜像数据层lowerdir的同一个文件。

下面是容器中更改文件的几个场景。

首次写入一个文件。首次在容器中写入一个存在的文件且文件不在容器upperdir。overlay/overlay2驱动执行一个copy_up操作来从镜像lowerdir复制文件到容器upperdir。然后容器把更改的数据写入到新复制过来的文件中。
不过OverlayFS工作在文件级别而不是块级别上。意味着所有的OverlayFS copy-up操作复制的是整个文件,即使是文件很大但只修改一小部分。这会对容器的写性能造成显着的影响。不过,下面两点值得注意:
1.copy_up操作只在对任意文件的首次写入时发生。随便对相同文件的写操作不再涉及到copy_up操作。
2.OverlayFS只工作在两层。这意味着它的性能应该比AUFS对很多层的镜像搜索一个文件时的性能要好。 删除文件和目录。当删除容器中的一个文件时,相当于在容器的upperdir创建了一个对应的空白(whiteout)文件。在镜像数据层lowerdir的文件版本不会被删除。只不过是容器中的空白(whiteout)文件隐藏了它。删除容器中的目录会在“upperdir”中创建不透明(opaque)的目录。这与一个空白(whiteout)文件的作用一样。这个不透明(opaque)目录有效地隐藏了镜像lowerdir同一个目录的存在。 重命名目录。仅当源和目标路径都位于顶层(upperdir)时,才允许为目录调用rename(2)。否则返回EXDEV (“cross-device link not permitted”).

配置Docker使用overlay/overlay2存储驱动

要配置Docker使用ovelay存储驱动,你的Docker主机必须运行在加载有overlay内核模式的3.18版本的Linux内核或更高的版本上。对于overlay2驱动,内核版本必须为4.0或更高版本。OverlayFS能用在大多数支持的Linux文件系统上。不过在生产环境中推荐使用ext4。
下面是配置Docker主机使用OverlayFS的步骤。假设你已经停止docker daemon。
1.如果docker在运行,先停止它。
2.验证内核版本和overlay内核模式是否加载

$ uname -r
 
 3.19.0-21-generic
 
 $ lsmod | grep overlay
 
 overlay

3.带overlay/overlay2存储驱动启动docker。

$ dockerd --storage-driver=overlay &
 
 [1] 29403
 root@ip-10-0-0-174:/home/ubuntu# INFO[0000] Listening for HTTP on unix (/var/run/docker.sock)
 INFO[0000] Option DefaultDriver: bridge
 INFO[0000] Option DefaultNetwork: bridge
 <output truncated>

另外,你可以通过编辑docker的配置文件增加–storage-driver=overlay到DOCKER_OPTS行来强制docker自动启动时启用overlay/overlay2驱动。
4.验证docker是否已经是使用overlay/overlay2存储驱动。

$ docker info
 
 Containers: 0
 Images: 0
 Storage Driver: overlay
  Backing Filesystem: extfs
 <output truncated>

OverlayFS与Docker性能

一般来说,overlay/overlay2驱动性能应该很好。大多时候会比aufs和devicemapper要好。在一些场景下可能比btrfs还高。我们在使用overlay/overlay2存储驱动时需要注意几点与性能相关的事项。

页缓存。OverlayFS支持页缓存共享。意味着多个容器访问同一个文件可以共享单个页缓存条目。这使得overlay/overlay2驱动在内存利用方面高效,且是PaaS和其它类似场景的一个好选择。 copy_up。AUFS和OverlayFS在首次对容器的一个文件写入时都会执行copy-up操作。这会增加写操作的延迟 – 特别是如果要拷贝的文件非常大时。不过,一旦文件已经复制上去,随便的所有写操作都不需要copy-up操作了。
OverlayFS的copy_up操作应该比AUFS同样的操作会快。因为AUFS比OverlayFS支持更多的层,在AUFS需要对非常多层的镜像搜索一个文件时就会出现这种情况。 Inode限制。使用overlay存储驱动可能会消耗更多的inode。特别是Docker主机上的镜像和容器数量很多时。一个Docker主机上有大量的镜像和大量的启动和停止容器时会更多消耗完inodes。overlay2没有这种问题。

你只能在文件系统创建时指定inodes的数量。因此你可能希望把/var/lib/docker放置在有一个自己的文件系统的不同设备,或者在文件系统创建时手动指定inodes的数量。
下面的两点性能优化同样适合于OverlayFS。

固态设备(SSD)。 为了获得最佳性能,使用快速存储介质(如固态设备(SSD))总是个好主意。 使用数据卷。 数据卷提供最佳和最可预测的性能。这是因为他们绕过存储驱动,并且不会引入任何通过精简置备和写时拷贝的潜在开销。

版权声明:Docker用户指南(8) – OverlayFS存储驱动实践是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。

相关文章推荐