Answers:
甲绑定安装是目录树的替换视图。传统上,安装会将存储设备的视图创建为目录树。绑定安装将采用现有的目录树,并在另一个位置复制它。绑定安装中的目录和文件与原始目录相同。一侧的任何修改都会立即反映在另一侧,因为这两个视图显示相同的数据。
例如,发出Linux命令后
mount --bind /some/where /else/where
目录/some/where
并/else/where
具有相同的内容。
与硬链接或符号链接不同,绑定安装不会影响文件系统上存储的内容。这是实时系统的属性。
该bindfs
文件系统是FUSE文件系统,可创建目录树的视图。例如,命令
bindfs /some/where /else/where
创建/else/where
一个挂载点,在该挂载点下内容/some/where
可见。
由于bindfs是一个单独的文件系统,因此文件/some/where/foo
和/else/where/foo
文件对于应用程序显示为不同的文件(bindfs文件系统具有其自己的st_dev
值)。一方的任何更改都“神奇地”反映在另一方,但是只有当人们知道bindfs的工作方式时,文件相同的事实才显而易见。
Bindfs不知道挂载点,因此,如果在其下有一个挂载点/some/where
,它将显示为下的另一个目录/else/where
。下面的装载或卸载文件系统/some/where
显示/else/where
为相应目录的更改。
Bindfs可以更改某些文件元数据:它可以显示伪造的权限和文件所有权。有关详细信息,请参见手册;有关示例,请参见下文。
可以以非root用户身份挂载bindfs文件系统,您只需要特权即可挂载FUSE文件系统。根据您的分布,这可能需要位于fuse
组中或允许所有用户使用。要卸载FUSE文件系统,请使用fusermount -u
代替umount
,例如
fusermount -u /else/where
FreeBSD提供了nullfs
文件系统,该文件系统创建文件系统的备用视图。以下两个命令是等效的:
mount -t nullfs /some/where /else/where
mount_nullfs /some/where /else/where
发出任何一个命令后,/else/where
将成为/some/where
可见其内容的安装点。
由于nullfs是一个单独的文件系统,因此文件/some/where/foo
与/else/where/foo
应用程序显示为不同的文件(nullfs文件系统具有其自己的st_dev
值)。一侧的任何更改都“神奇地”反映在另一侧,但是只有在知道nullfs的工作方式时,文件相同的事实才显而易见。
与在目录树级别起作用的FUSE bindfs不同,FreeBSD的nullfs在内核中的作用更深,因此其下的挂载点/else/where
不可见:只有与该挂载点属于同一挂载点的树才能在/some/where
上反映出来/else/where
。
nullfs文件系统可以在其他BSD变体(OS X,OpenBSD,NetBSD)下使用,但不会作为默认系统的一部分进行编译。
在Linux下,绑定安装可用作内核功能。您可以mount
通过传递--bind
命令行选项或bind
安装选项来使用命令创建一个。以下两个命令是等效的:
mount --bind /some/where /else/where
mount -o bind /some/where /else/where
在这里,“设备” /some/where
不是磁盘上的文件系统那样的磁盘分区,而是现有目录。挂载点/else/where
必须像往常一样是现有目录。请注意,都没有指定任何文件系统类型:进行绑定挂载不涉及文件系统驱动程序,它从原始挂载复制内核数据结构。
mount --bind
还支持将非目录装载到非目录:/some/where
可以是常规文件(在这种情况下也/else/where
需要是常规文件)。
Linux绑定安装与原始安装几乎没有区别。该命令df -T /else/where
显示与相同的设备和相同的文件系统类型df -T /some/where
。这些文件/some/where/foo
和/else/where/foo
是无法区分的,就好像它们是硬链接一样。可以卸载/some/where
,在这种情况下/else/where
仍保持安装状态。
对于较旧的内核(我不知道确切的时间,我想直到3.x左右),bind挂载与原始内核确实无法区分。最近的内核确实跟踪绑定安装,并通过PID / mountinfo公开信息,从而可以findmnt
这样指示绑定安装。
您可以在中放入绑定安装项/etc/fstab
。只需在选项中包括bind
(或其他rbind
)以及您想要的任何其他选项即可。“设备”是现有的树。文件系统列可以包含none
或bind
(将被忽略,但是使用文件系统名称会造成混淆)。例如:
/some/where /readonly/view none bind,ro
如果下面有安装点,则在下/some/where
看不到它们的内容/else/where
。代替的是bind
,您可以使用rbind
,也可以复制下面的安装点/some/where
。例如,如果/some/where/mnt
是安装点,则
mount --rbind /some/where /else/where
相当于
mount --bind /some/where /else/where
mount --bind /some/where/mnt /else/where/mnt
另外,Linux允许将挂载声明为shared,slave,private或unbindable。这会影响该安装操作是否反映在复制安装点的绑定安装下。有关更多详细信息,请参见内核文档。
Linux还提供了一种移动挂载的方法:在--bind
副本中--move
移动挂载点。
在两个绑定安装的目录中可能有不同的安装选项。但是,有一个怪癖:不能自动进行绑定挂载和设置挂载选项,它们必须是两个连续的操作。(较早的内核不允许这样做。)例如,以下命令创建一个只读视图,但是在/else/where
读写期间只有一小段时间:
mount --bind /some/where /else/where
mount -o remount,ro,bind /else/where
如果您的系统不支持FUSE,达到相同效果的经典技巧是运行NFS服务器,使其导出要公开的文件(允许访问localhost
)并将它们安装在同一台计算机上。就内存和性能而言,这具有相当大的开销,因此绑定安装在可用的地方具有明显的优势(这在大多数Unix变体中都归功于FUSE)。
出于安全原因或作为安全层来创建文件系统的只读视图可能很有用,以确保您不会意外修改它。
使用bindfs:
bindfs -r /some/where /mnt/readonly
使用Linux,简单的方法是:
mount --bind /some/where /mnt/readonly
mount -o remount,ro,bind /mnt/readonly
这就留出了较短/mnt/readonly
的读写时间间隔。如果出于安全考虑,请首先在只有root可以访问的目录中创建绑定安装,将其设置为只读,然后将其移动到公共安装点。在下面的代码段中,请注意/root/private
(挂载点上方的目录)私有是很重要的;原始的权限/root/private/mnt
无关紧要,因为它们隐藏在安装点后面。
mkdir -p /root/private/mnt
chmod 700 /root/private
mount --bind /some/where /root/private/mnt
mount -o remount,ro,bind /root/private/mnt
mount --move /root/private/mnt /mnt/readonly
文件系统通过其数字ID记录用户和组。有时,您最终会遇到多个系统,这些系统将不同的用户ID分配给同一个人。这不是网络访问的问题,但是当您将数据从一个系统传输到磁盘上的另一个系统时,它使用户ID变得毫无意义。假设您在Alice的用户ID为1000,Bob的用户ID为1001的系统上创建了一个由多用户文件系统(例如ext4,btrfs,zfs,UFS等)创建的磁盘,并且您想使该磁盘在一个系统,其中Alice的用户ID为1001,Bob的用户ID为1000。如果直接安装磁盘,则Alice的文件将显示为Bob的所有权(因为用户ID为1001),而Bob的文件将显示为Alice的所有权(因为用户ID为1000)。
您可以使用bindfs重新映射用户ID。首先将磁盘分区安装在专用目录中,只有root可以访问该目录。然后在公共区域中创建一个bindfs视图,并重新映射用户ID和组ID,以交换Alice和Bob的用户ID和组ID。
mkdir -p /root/private/alice_disk /media/alice_disk
chmod 700 /root/private
mount /dev/sdb1 /root/private/alice_disk
bindfs --map=1000/1001:1001/1000:@1000/1001:@1001/1000 /root/private/alice_disk /media/alice_disk
请参阅如何允许未访问系统的用户的主文件夹上的文件?并挂载--bind其他用户作为我自己的另一个示例。
一个chroot监牢或容器运行在系统目录树的子树的过程。这对于运行具有受限访问权限的程序很有用,例如,运行仅可访问其自己的文件及其服务的文件,而不能访问存储在同一计算机上的其他数据的网络服务器)。chroot的局限性在于该程序仅限于一个子树:它无法访问独立的子树。绑定安装允许将其他子树嫁接到该主树上。这使它们成为Linux下最实际使用容器的基础。
例如,假设机器运行的服务/usr/sbin/somethingd
只能访问的数据/var/lib/something
。包含这两个文件的最小目录树是根。如何限制服务?一种可能性是使硬链接到服务所需的所有文件(至少/usr/sbin/somethingd
和几个共享库)/var/lib/something
。但这很麻烦(每次升级文件时都需要更新硬链接),如果/var/lib/something
和/usr
在不同的文件系统上,则不起作用。更好的解决方案是创建一个临时根并使用mount填充它:
mkdir /run/something
cd /run/something
mkdir -p etc/something lib usr/lib usr/sbin var/lib/something
mount --bind /etc/something etc/something
mount --bind /lib lib
mount --bind /usr/lib usr/lib
mount --bind /usr/sbin usr/sbin
mount --bind /var/lib/something var/lib/something
mount -o remount,ro,bind etc/something
mount -o remount,ro,bind lib
mount -o remount,ro,bind usr/lib
mount -o remount,ro,bind usr/sbin
chroot . /usr/sbin/somethingd &
Linux的安装名称空间可以通用化chroot。绑定挂载是如何以灵活的方式填充名称空间的方法。有关示例,请参见使进程读取具有相同文件名的其他文件。
chroots的另一种用法是在目录中安装不同的发行版并从中运行程序,即使它们需要在基本系统上不存在或内容不同的硬编码路径上的文件。例如,这可以在不支持混合软件包的64位系统上安装32位发行版,安装发行版的较旧版本或其他发行版以测试兼容性,安装新发行版以进行测试时非常有用。最新的功能,同时保持稳定的基本系统等。请参见如何在64位Debian / Ubuntu上运行32位程序?以Debian / Ubuntu为例。
假设您在目录下安装了发行版的最新软件包/f/unstable
,您可以在其中通过切换到该目录来运行程序chroot /f/unstable
。要使主目录可从此安装中使用,请将它们绑定安装到chroot中:
mount --bind /home /f/unstable/home
程序schroot会自动执行此操作。
在目录上挂载文件系统时,这会隐藏目录后的内容。在卸载目录之前,该目录中的文件将无法访问。由于BSD nullfs和Linux绑定安装的运行级别比安装基础结构低,因此文件系统的nullfs安装或绑定安装会公开隐藏在原始子安装后面的目录。
例如,假设您在挂载了tmpfs文件系统/tmp
。如果在/tmp
创建tmpfs文件系统时存在文件,这些文件可能仍会保留,实际上无法访问,但占用了磁盘空间。跑
mount --bind / /mnt
(Linux)或
mount -t nullfs / /mnt
(FreeBSD)在处创建根文件系统的视图/mnt
。该目录/mnt/tmp
是根文件系统中的目录。
某些NFS服务器(例如NFSv4之前的Linux内核NFS服务器)在导出目录时总是公布实际的目录位置。也就是说,当客户端请求时server:/requested/location
,服务器将在location处提供树/requested/location
。有时希望允许客户端请求,/request/location
但实际上是在下提供文件/actual/location
。如果您的NFS服务器不支持服务备用位置,则可以为预期的请求创建绑定安装,例如
/requested/location *.localdomain(rw,async)
在/etc/exports
和以下/etc/fstab
:
/actual/location /requested/location bind bind
有时您希望创建符号链接使文件/some/where/is/my/file
出现在下面/else/where
,但是使用的应用程序会file
扩展符号链接并拒绝它/some/where/is/my/file
。绑定安装可以解决此问题:bind-mount /some/where/is/my
到/else/where/is/my
,然后realpath
报告/else/where/is/my/file
位于之下/else/where
,而不是之下/some/where
。
如果使用绑定安装,则需要照顾递归地遍历文件系统树的应用程序,例如备份和索引(例如,建立定位数据库)。
通常,应该从递归目录遍历中排除绑定安装,以便每个目录树在原始位置仅被遍历一次。如果可能,请使用bindfs和nullfs配置遍历工具以忽略这些文件系统类型。Linux绑定安装无法这样识别:新位置等同于原始位置。对于Linux绑定安装,或仅只能排除路径而不能排除文件系统类型的工具,您需要排除绑定安装的安装点。
遍历是停留在文件系统边界(例如find -xdev
,rsync -x
,du -x
当他们遇到一个bindfs或安装的nullfs点,...),会自动停止,因为安装点是不同的文件系统。使用Linux绑定安装时,情况要复杂一些:仅当绑定安装移植了另一个文件系统时才存在文件系统边界,而在移植相同文件系统的另一部分时则没有文件系统边界。
绑定安装提供了位于不同位置的目录树视图。它们公开相同的文件,可能具有不同的挂载选项和(使用bindfs)不同的所有权和权限。呈现目录树视图变更的文件系统称为覆盖文件系统或可堆叠文件系统。还有许多其他覆盖文件系统可以执行更高级的转换。这是一些常见的。如果此处未涵盖您所需的用例,请检查FUSE文件系统的存储库。
bindfs -r
,只是重量更轻一点。联合挂载 — 在单个目录下提供多个文件系统(称为分支):如果tree1
包含foo
和tree2
包含,bar
则其联合视图同时包含foo
和bar
。新文件将写入特定分支,或写入根据更复杂规则选择的分支。此概念有几种实现,包括:
mount --bind /dir1 /dir1
办?与安装源和安装目标不同的情况有何不同?
/proc/self/mountinfo
。至于chroot,它可以用于隔离,但不能单独使用。但是,您不需要安装名称空间:chroot对于文件系统名称空间部分就足够了。您确实需要确保chroot中的任何进程都不会与chroot外部的进程以同一用户身份运行。