OverlayFS是一个与AUFS类似的现代联合(union)文件系统。与AUFS比较,OverlayFS存在如下优势:
因此,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结构的。
注意看容器数据层和镜像数据层能包含同样的文件。当出现此情况时,容器数据层”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对文件进行的读取操作的三个场景。
下面是容器中更改文件的几个场景。
不过OverlayFS工作在文件级别而不是块级别上。意味着所有的OverlayFS copy-up操作复制的是整个文件,即使是文件很大但只修改一小部分。这会对容器的写性能造成显着的影响。不过,下面两点值得注意:
1.copy_up操作只在对任意文件的首次写入时发生。随便对相同文件的写操作不再涉及到copy_up操作。
2.OverlayFS只工作在两层。这意味着它的性能应该比AUFS对很多层的镜像搜索一个文件时的性能要好。
配置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的copy_up操作应该比AUFS同样的操作会快。因为AUFS比OverlayFS支持更多的层,在AUFS需要对非常多层的镜像搜索一个文件时就会出现这种情况。
你只能在文件系统创建时指定inodes的数量。因此你可能希望把/var/lib/docker放置在有一个自己的文件系统的不同设备,或者在文件系统创建时手动指定inodes的数量。
下面的两点性能优化同样适合于OverlayFS。