AUFS 驱动
AUFS
存储驱动程序已被弃用,并在 Docker Engine v24.0 中被删除。 如果您使用 AUFS
,则必须先迁移到受支持的存储驱动程序,然后再升级到 Docker Engine v24.0。
请阅读 Docker
存储驱动程序页面以了解支持的存储驱动程序。
AUFS 是一个联合文件系统。aufs
存储驱动程序以前是用于管理 Docker 上的镜像和层的默认存储驱动程序,适用于 Ubuntu 以及 Stretch 之前的 Debian 版本。
如果您的 Linux 内核是 4.0 或更高版本,并且您使用 Docker Engine - Community,请考虑使用较新的overlay2
,它比aufs
存储驱动程序具有潜在的性能优势。
先决条件
- 对于 Docker Engine - Community,Ubuntu 以及 Stretch 之前的 Debian 版本支持
AUFS
。 - 对于 Docker EE,Ubuntu 支持
AUFS
。 - 如果您使用 Ubuntu,则需要将
AUFS
模块添加到内核中。 如果不安装这些包,则需要使用overlay2
。 - AUFS 无法使用以下支持文件系统:
aufs
、btrfs
或ecryptfs
。 这意味着包含/var/lib/docker/aufs
的文件系统不能是这些文件系统类型之一。
配置 Docker
使用 AUFS
存储驱动程序
如果您在启动 Docker 时将 AUFS
驱动程序加载到内核中,并且没有配置其他存储驱动程序,则 Docker 默认使用它。
-
使用以下命令验证内核是否支持
AUFS
。grep aufs /proc/filesystems nodev aufs
-
检查 Docker 正在使用的存储驱动程序。
docker info <truncated output> Storage Driver: aufs Root Dir: /var/lib/docker/aufs Backing Filesystem: extfs Dirs: 0 Dirperm1 Supported: true <truncated output>
-
如果您使用不同的存储驱动程序,则
AUFS
未包含在内核中(在这种情况下使用不同的默认驱动程序),或者 Docker 已被显式配置为使用不同的驱动程序。 检查/etc/docker/daemon.json
或ps auxw | grep dockerd
的输出查看 Docker 是否已使用--storage-driver
标志启用。
AUFS
存储驱动程序是如何工作的
AUFS
是一个联合文件系统,这意味着它在单个 Linux 主机上分层为多个目录并将它们呈现为单个目录。
这些目录在 AUFS
术语中称为分支,在 Docker 术语中称为层。
统一过程称为
union mount
。
下图显示了基于ubuntu:latest
镜像的 Docker 容器。
每个镜像层和容器层在 Docker 主机上都表示为/var/lib/docker/
中的子目录。
union mount
提供所有层的统一视图。目录名称并不直接对应于层本身的 ID
。
AUFS
使用写时复制 (CoW) 策略来最大限度地提高存储效率并最大限度地减少开销。
Example: 镜像和容器在磁盘上的构成
以下docker pull
命令显示 Docker 主机下载包含五层的 Docker 镜像。
$ docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
b6f892c0043b: Pull complete
55010f332b04: Pull complete
2955fb827c94: Pull complete
3deef3fcbd30: Pull complete
cf9722e506aa: Pull complete
Digest: sha256:382452f82a8bbd34443b2c727650af46aced0f94a44463c62a9848133ecb1aa8
Status: Downloaded newer image for ubuntu:latest
镜像层
/var/lib/docker/
中的文件或目录,这些文件和目录由 Docker 管理。
有关镜像和容器层的所有信息都存储在/var/lib/docker/aufs/
的子目录中。
diff/
:每一层的 内容,每层存放在单独的子目录中Layers/
:有关镜像层如何堆叠的元数据。 该目录包含 Docker 主机上每个镜像或容器层的一个文件。 每个文件都包含堆栈中位于其下方的所有层(其父层)的 ID。mnt/
:挂载点,每个镜像或容器层一个,用于组装和挂载容器的统一文件系统。 对于只读镜像,这些目录始终为空。
容器层
如果容器正在运行,/var/lib/docker/aufs/
的内容将按以下方式更改:
diff/
:可写容器层中引入的差异,例如新的或修改的文件。Layers/
:有关可写容器层父层的元数据。mnt/
:每个正在运行的容器的统一文件系统的挂载点,与容器内的显示完全相同。
容器如何读取和写入 AUFS
读文件
考虑容器使用 aufs
打开文件进行读取访问的三种场景。
- 文件不存在于容器层中: 如果容器打开一个文件进行读访问,并且该文件不存在于容器层中,则存储驱动程序会在镜像层中搜索该文件,从容器层下面的层开始。它是从找到它的层中读取的。
- 文件只存在于容器层: 如果容器打开一个文件进行读访问,并且该文件存在于容器层,则从那里读取该文件。
- 文件同时存在于容器层和镜像层: 如果容器打开一个文件进行读访问,并且该文件存在于容器层和一个或多个镜像层中,则从容器层读取该文件。容器层中的文件会掩盖镜像层中同名的文件。
修改文件或目录
考虑一些修改容器中的文件的场景。
-
第一次写入文件: 容器第一次写入现有文件时,该文件在容器(
upperdir
)中不存在。aufs
驱动执行copy_up
操作, 将文件从其所在的镜像层复制到可写容器层。然后,容器将更改写入容器层中文件的新副本。然而,
AUFS
在文件级别而不是块级别工作。 这意味着所有copy_up
操作都会复制整个文件,即使文件非常大并且只修改了其中的一小部分。 这会对容器写入性能产生显著影响。 在多层镜像中搜索文件时,AUFS
可能会出现明显的延迟。但是,值得注意的是,copy_up
操作仅在第一次写入给定文件时发生。 对同一文件的后续写入将针对已复制到容器的文件副本进行操作。 -
删除文件和目录:
- 当在容器内删除文件时,会在容器层中创建一个
whiteout
文件。 镜像层中的文件版本不会被删除(因为镜像层是只读的)。 但是,whiteout
文件会阻止容器使用它。 - 当删除容器内的目录时,会在容器层中创建一个不透明文件。 这与
whiteout
文件的工作方式相同,并且有效地防止目录被访问,即使它仍然存在于镜像层中。
- 当在容器内删除文件时,会在容器层中创建一个
-
重命名目录:
AUFS
不完全支持对目录调用rename(2)
。 即使源路径和目标路径位于同一 AUFS 层,它也会返回EXDEV
("cross-device link not permitted"
不允许跨设备链接),除非该目录没有子目录。 您的应用程序需要设计为处理EXDEV
并回退到"copy and unlink"
的策略。
AUFS 和 Docker 性能
总结一些已经提到的与性能相关的方面:
-
AUFS
存储驱动程序的性能低于Overlay2
驱动程序,但对于 PaaS 和容器密度很重要的其他类似用例来说是一个不错的选择。 这是因为 AUFS 在多个正在运行的容器之间有效地共享镜像,从而实现快速容器启动,时间消耗少以及最少的磁盘空间使用。 -
AUFS
如何在镜像层和容器之间共享文件的底层机制非常有效地使用页面缓存。 -
AUFS
存储驱动程序可能会给容器写入性能带来显着的延迟。 这是因为容器第一次写入任何文件时,需要找到该文件并将其复制到容器的顶层可写层中。 当这些文件存在于许多镜像层下方并且文件本身很大时,这些延迟会增加并加剧。
性能最佳实践
以下通用性能最佳实践也适用于 AUFS
。
- 固态设备 (SSD) 提供比旋转磁盘更快的读取和写入速度。
- 将卷用于写入密集型工作负载: 卷为写入密集型工作负载提供最佳且最可预测的性能。 这是因为它们绕过存储驱动程序,并且不会产生精简配置和写时复制带来的任何潜在开销。 卷还有其他好处,例如允许您在容器之间共享数据,甚至在没有正在运行的容器使用它们时也能保留数据。