什么是绑定安装?


325

什么是“绑定安装”?我该怎么做?到底有什么好处呢?

有人告诉我对某些东西使用绑定安装,但是我不知道它是什么或如何使用。


2
安装件和符号链接之间有用的替代的澄清:quora.com/...
查理帕克

Answers:


564

什么是绑定安装?

绑定安装是目录树的替换视图。传统上,安装会将存储设备的视图创建为目录树。绑定安装将采用现有的目录树,并在另一个位置复制它。绑定安装中的目录和文件与原始目录相同。一侧的任何修改都会立即反映在另一侧,因为这两个视图显示相同的数据。

例如,发出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绑定安装

在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)以及您想要的任何其他选项即可。“设备”是现有的树。文件系统列可以包含nonebind(将被忽略,但是使用文件系统名称会造成混淆)。例如:

/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允许将挂载声明为sharedslaveprivateunbindable。这会影响该安装操作是否反映在复制安装点的绑定安装下。有关更多详细信息,请参见内核文档

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导出的路径不同

某些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 -xdevrsync -xdu -x当他们遇到一个bindfs或安装的nullfs点,...),会自动停止,因为安装点是不同的文件系统。使用Linux绑定安装时,情况要复杂一些:仅当绑定安装移植了另一个文件系统时才存在文件系统边界,而在移植相同文件系统的另一部分时则没有文件系统边界。

超越绑定坐骑

绑定安装提供了位于不同位置的目录树视图。它们公开相同的文件,可能具有不同的挂载选项和(使用bindfs)不同的所有权和权限。呈现目录树视图变更的文件系统称为覆盖文件系统可堆叠文件系统。还有许多其他覆盖文件系统可以执行更高级的转换。这是一些常见的。如果此处未涵盖您所需的用例,请检查FUSE文件系统存储库

过滤可见文件

  • clamfs —在读取文件时通过病毒扫描程序运行文件
  • filterfs —隐藏文件系统的一部分
  • rofs-只读视图。与相似bindfs -r,只是重量更轻一点。
  • 联合挂载 — 在单个目录下提供多个文件系统(称为分支):如果tree1包含footree2包含,bar则其联合视图同时包含foobar。新文件将写入特定分支,或写入根据更复杂规则选择的分支。此概念有几种实现,包括:

修改文件名和元数据

  • ciopfs —不区分大小写的文件名(对挂载Windows文件系统很有用)
  • convmvfs —在字符集之间转换文件名(示例
  • posixovl —将Unix文件名和其他元数据(权限,所有权等)存储在更严格的文件系统(例如 VFAT)上(示例

查看更改的文件内容

修改内容的存储方式


1
可能需要添加一个如何使用systemd的示例:utcc.utoronto.ca/~cks/space/blog/linux/SystemdBindMountUnits
dothebart

1
怎么mount --bind /dir1 /dir1办?与安装源和安装目标不同的情况有何不同?
标记

使用linux 5.0在/ proc / self / mountinfo中没有看到任何记录。内核没有告诉我是否是绑定安装。而且一个进程可以轻易破坏chroot,必须通过mount名称空间完成隔离。
炸鱼薯条德里克

@炸鱼薯条德里克我认为链接的问题unix.stackexchange.com/questions/295525/…地址/proc/self/mountinfo。至于chroot,它可以用于隔离,但不能单独使用。但是,您不需要安装名称空间:chroot对于文件系统名称空间部分就足够了。您确实需要确保chroot中的任何进程都不会与chroot外部的进程以同一用户身份运行。
吉尔斯

@Mark绑定目录本身不是很有用。我想您可以使用它来隐藏安装在某个目录下的文件系统,但是我想不到要专门执行此操作的时间。
吉尔斯

-1

很简单,当您使用绑定安装时,会将主机上的文件或目录安装到容器中,因此,主机上文件目录内部所做的任何更改都将自动在目录中的容器内可用。


这是使用绑定安装的方法之一,但是绑定安装本身与容器无关。我在回答中提到了这一点,但其名称是“监狱”而不是“容器”。添加“容器”将是很有价值的编辑(我会做)。这也是一个很差的描述:为什么要提及在外部进行的更改也可以在内部进行而不用相反地提及?
Gilles
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.