答案1
编辑:自从写这个答案以来,overlayfs 中的一些内容发生了变化,即增加了一个必需参数workdir
,请参阅托蒂的回答下面了解有关此新参数的详细描述。
我终于找到了它。我在内核源代码中找到了对它的引用,但由于某种原因,它没有出现在 kernel.org 上的 git 树中。但是!如果你像这样拉取 Ubuntu 内核源代码:apt-get source linux-image-3.0.0-16-generic
你可以在 中找到它linux-3.0.0/Documentation/overlayfs.txt
。它也可以在 中的 linux-doc 包中找到/usr/share/doc/linux-doc/filesystems/overlayfs.txt.gz
。
由于实际的帮助文档更多的是“它如何工作”而不是“如何使用它安装”,这里有一个简短的概述(内核文档中有一个例子):
mount -t overlayfs -o [mount options] overlayfs [mountpoint for merged system]
其中 [mount options] 可以是:
- lowerdir=somedir:lowerdir 是您要放置新文件系统的目录,如果有重复,则这些目录将被 upperdir 的版本覆盖(实际上是隐藏起来)
- upperdir=somedir:upperdir 是要覆盖 lowerdir 的目录。如果 lowerdir 和 upperdir 中存在重复的文件名,则 upperdir 的版本优先。
- 标准安装选项。我从代码中看到的唯一选项是 ro/rw,但你可以尝试一下。
一开始让我感到困惑的一件事(所以我可能应该澄清一下)是,挂载 overlayfs 实际上并不挂载文件系统。我曾尝试使用 overlayfs 挂载来挂载 squashfs 文件系统,但事实并非如此。您必须首先将(在我的情况下是 squashfs)文件系统挂载到任意目录,然后使用 overlayfs 将挂载点(目录)和另一个目录合并到第三级目录(overlayfs 挂载点)(编辑:这个“第三级”目录实际上可以是 upperdir= 目录)。您将在第三级目录中看到合并的文件系统(或目录树 - 它很灵活)。
示例 1,覆盖根文件系统
我一直在研究 Ubuntu 混合启动盘,其中基本 Ubuntu 系统以 filesystem.squashfs 的形式存在,并且我有名为 ubuntu.overlay kubuntu.overlay xubuntu.overlay 和 lubuntu.overlay 的文件。.overlay 文件是上述系统的基本安装,其中 filesystem.squashfs 的内容已被删减(以节省空间)。然后我修改了 init 脚本,使用 overlayfs 和上述选项覆盖正确的发行版的 .overlay 文件(来自启动参数),它运行得非常好!
这些是我在初始化脚本中使用的行(一旦所有变量都被翻译):
mkdir -p /overlay
mount -t squashfs /cdrom/casper/ubuntu.overlay /overlay
mount -t overlayfs -o lowerdir=/filesystem.squashfs,upperdir=/overlay overlayfs /
请注意,上面的 filesystem.squashfs 是目录由 casper 创建,不是文件。
这三个语句创建一个/overlay
目录,在该目录上挂载一个 squashfs 文件系统,然后使用 OverlayFS 来合并/overlay
的内容。/overlay
/
示例2、透明合并两个目录
在为每个版本重新构建实时 USB 的过程中,我使用 OverlayFS 来节省大量时间。我首先从一个名为 ubuntu-base 的目录开始,其中包含最基本的安装 ubuntu-core 映像的内容。然后我将创建名为 ubuntu、kubuntu、lubuntu 和 xubuntu 的目录。
然后,我使用 OverlayFS 使 ubuntu-base 中的文件显示在各个目录中。我会使用类似这样的方法:
mount -t overlayfs -o lowerdir=ubuntu-base,upperdir=kubuntu overlayfs kubuntu
这会使 ubuntu-base 中的文件显示在 kubuntu 文件夹中。然后,我可以chroot
进入 kubuntu 文件夹并执行类似 的操作apt-get install kubuntu-desktop
。在此 OverlayFS 挂载中所做的任何更改都将保留在上层目录中,在本例中为 kubuntu 文件夹。然后,一旦我卸载 OverlayFS 挂载,ubuntu-base 中实际存在但“镜像”到 kubuntu 文件夹中的文件就会消失,除非它们已被更改。这使我不必在 ubuntu-base 中拥有文件的多个副本,同时仍然可以使用它们,就像它们在每个位置都实际存在一样。
答案2
从https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt:
上部和下部
覆盖文件系统结合了两个文件系统 - “上层”文件系统和“下层”文件系统。当两个文件系统中都存在名称时,“上层”文件系统中的对象可见,而“下层”文件系统中的对象则隐藏,或者在目录的情况下与“上层”对象合并。
称其为上层和下层“目录树”而不是“文件系统”更为正确,因为两个目录树完全有可能位于同一个文件系统中,并且没有要求为上层或下层提供文件系统的根。
下层文件系统可以是 Linux 支持的任何文件系统,不需要可写。下层文件系统甚至可以是另一个 overlayfs。上层文件系统通常是可写的,如果是,它必须支持创建受信任的.* 扩展属性,并且必须在 readdir 响应中提供有效的 d_type,因此 NFS 不适合。
两个只读文件系统的只读覆盖可以使用任何文件系统类型。
目录
覆盖主要涉及目录。如果给定名称同时出现在上层和下层文件系统中,并且引用其中任一文件系统中的非目录,则下层对象将被隐藏 - 该名称仅引用上层对象。
当上层对象和下层对象都是目录时,会形成合并目录。
在挂载时,作为挂载选项“lowerdir”和“upperdir”给出的两个目录将合并为一个合并目录:
mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,workdir=/work /merged
“workdir” 需要是与 upperdir 位于同一文件系统上的空目录。
然后,每当请求在这样的合并目录中进行查找时,都会在每个实际目录中执行查找,并将组合结果缓存在属于覆盖文件系统的 dentry 中。如果两个实际查找都找到目录,则将两个目录都存储起来并创建一个合并目录,否则只存储一个:如果存在则存储上层目录,否则存储下层目录。
仅合并目录中的名称列表。其他内容(如元数据和扩展属性)仅针对上层目录报告。下层目录的这些属性被隐藏。
答案3
最小可运行示例
# Create the filesystems.
dd if=/dev/zero of=lower.ext4 bs=1024 count=102400
mkfs -t ext4 lower.ext4
cp lower.ext4 upper.ext4
mkdir lower upper overlay
sudo mount lower.ext4 lower
sudo mount upper.ext4 upper
sudo chown "$USER:$USER" lower upper
printf lower-content > lower/lower-file
# Upper and work must be on the same filesystem.
mkdir upper/upper upper/work
printf upper-content > upper/upper/upper-file
# Work must be empty. E.g. this would be bad:
#printf work-content > upper/work/work-file
# Make the lower readonly to show that that is possible:
# writes actually end up on the upper filesystem.
sudo mount -o remount,ro lower.ext4 lower
# Create the overlay mount.
sudo mount \
-t overlay \
-o lowerdir=lower,upperdir=upper/upper,workdir=upper/work \
none \
overlay \
;
# Interact with the mount.
printf 'overlay-content' > overlay/overlay-file
ls lower upper/upper upper/work overlay
# Write to underlying directories while mounted
# gives undefined behaviour.
#printf lower-content-2 > lower/lower-file-2
#printf upper-content-2 > upper/upper-file-2
# Unmount the overlay and observe state.
sudo umount overlay
ls lower upper/upper upper/work
# Cleanup.
sudo umount upper lower
第一个ls
安装的输出:
lower:
lost+found lower-file
overlay:
lost+found lower-file overlay-file upper-file
upper/upper:
overlay-file upper-file
upper/work:
work
第二个ls
没有安装的输出:
lower:
lost+found lower-file
upper/upper:
overlay-file upper-file
upper/work:
work
解释:
- 较低:写入覆盖后没有变化
- upper:接收到对 overlay 的修改
- 覆盖:同时显示上层和下层的文件
- 工作:包含一些
work/
我们不应该关心的随机内容(目录)
示例改编自:OverlayFS 使用示例
这是一个更复杂的例子,有多个较低层:Overlayfs 使用多层重新加载(从 aufs 迁移)
在 Ubuntu 18.04、Linux 内核 4.15.0 上测试。
答案4
在 fstab 中挂载 OverlayFS
以上答案解释了如何从命令行和/或脚本挂载覆盖文件系统。也可以从以下位置挂载 OverlayFS:文件系统。
挂载 OverlayFS 存在固有问题。由于我们要挂载目录,因此这些目录必须存在和/或就绪。存在意味着特定目录所在的文件系统已挂载,而就绪意味着特定目录已“填充”。后者的示例是将 ISO 映像挂载到特定目录,或挂载网络共享(任何类型)。
挂载不存在的目录将会失败,但挂载尚未“填充”的目录不会失败,因为 OverlayFS 无法知道目录是否已准备就绪。
从 fstab 挂载文件系统时,这尤其成问题,因为所有挂载都是并行完成的,因此我们无法确保为 OverlayFS 做好一切都准备就绪。
但是,如果 Linux 发行版使用 systemd,则文件系统的挂载由它处理。Systemd 读取 fstab 文件,并动态创建挂载单元。之后,所有挂载都由 systemd 处理。Systemd 单元文件有选项:r需要,后,前,可用于控制fstab中定义的挂载顺序和依赖性,从而确保OverlayFS的挂载不会失败(至少不会因为顺序错误而失败)。
为了在 fstab 文件中设置挂载的顺序/依赖性,我们将声明 systemd 选项“要求“使用语法:x-systemd.require. 此选项的参数是应在给定挂载(在 fstab 中定义)之前成功挂载的挂载点。
例子:
为了展示一个例子(和语法文件系统条目),我们将展示一个案例,我们将覆盖挂载 iso 映像的目录,而这个特定的映像文件将存储在单独的硬盘上,在我们访问映像文件之前必须先挂载该硬盘。从而形成所需的事件顺序:
mount hdd -> mount iso image -> mount OverlayFS
对于给定的情况,fstab 条目将如下所示:
# 1. mount hdd partition
# 2. mount iso image from hdd partition, but only if/after hdd is mounted
# 3. overlay iso image, but only if/after iso image is mounted
#
/dev/hdb1 /mnt/hdd ext4 errors=remount-ro 0 2
/mnt/hdd/linux.iso /mnt/iso auto x-systemd.requires=/mnt/hdd,ro 0 0
overlay /mnt/merged overlay x-systemd.requires=/mnt/iso,lowerdir=/mnt/iso,upperdir=/overlay/lower,workdir=/overlay/working 0 0
如果链中的任何挂载失败,则不会执行依赖的挂载。
笔记:
在Arch Linux 维基有一个使用 fstab 挂载 OverlayFS 的示例,其中使用了以下选项:
noauto,x-systemd.automount
这将产生效果,覆盖文件系统将简单未安装在启动时(禁止自动选项),避免在先前的挂载尚未准备好时可能出现故障。首次访问覆盖目录时,将挂载文件系统(x-systemd.automount选项)。 这种方法有两个缺点:
- 如果所需的下层/上层目录尚未准备好,此挂载将失败。
- 即使下层/上层目录未填充,挂载也会成功(例如 ISO 未挂载)
我们可以通过添加来避免x-systemd.require到选项列表。