什么是“绑定安装”?我该如何做一个?有什么好处?

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

评论

坐骑和符号链接之间的有用替代说明:quora.com/…

#1 楼

什么是绑定安装?
绑定安装是目录树的备用视图。传统上,挂载会将存储设备的视图创建为目录树。绑定安装将采用现有的目录树,并在另一个位置复制它。绑定安装中的目录和文件与原始目录相同。因为两个视图显示的是相同的数据,所以任何一侧的修改都会立即反映在另一侧。
例如,发出Linux命令-
mount --bind /some/where /else/where

后,目录/some/where/else/where具有相同的内容,即/some/where的内容。 (如果/else/where不为空,则其先前的内容现在将被隐藏。)
与硬链接或符号链接不同,绑定安装不会影响文件系统上存储的内容。这是实时系统的属性。
如何创建绑定安装?
bindfs
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

nullfs
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的工作方式时,文件相同的事实才显而易见。目录树,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挂载与原始内核确实无法区分。最近的内核确实跟踪绑定安装并通过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允许将挂载声明为共享,从属,私有或不可绑定。这会影响该安装操作是否反映在复制安装点的绑定安装下。有关更多详细信息,请参见内核文档。
Linux还提供了一种移动安装的方式:--bind副本在其中--move移动了安装点。
在两个绑定安装的目录中可以有不同的安装选项。但是,有一个怪癖:不能自动完成绑定挂载和设置挂载选项,它们必须是两个连续的操作。 (较早的内核不允许这样做。)例如,以下命令创建了一个只读视图,但是/else/where处于读写状态的时间窗口很小:
mount --bind /some/where /else/where
mount -o remount,ro,bind /else/where

我可以
如果系统不支持FUSE,达到相同效果的经典技巧是运行NFS服务器,使其导出要公开的文件(允许访问localhost)并将它们安装在同一台计算机上。就内存和性能而言,这具有相当大的开销,因此绑定安装在可用的地方具有明显的优势(由于FUSE,在大多数Unix变体中都是这样)。
用例
只读视图
出于安全原因或出于确保您不会意外修改文件的安全性的考虑,创建文件系统的只读视图很有用。
使用bindfs:

使用Linux的简单方法是:
bindfs -r /some/where /mnt/readonly

这样就可以以较短的时间间隔来读写/mnt/readonly。如果出于安全考虑,请首先在只有root可以访问的目录中创建绑定安装,将其设置为只读,然后将其移动到公共安装点。在下面的代码段中,请注意/root/private(挂载点上方的目录)是私有的,这一点很重要。 /root/private/mnt的原始权限是无关紧要的,因为它们隐藏在安装点的后面。
mount --bind /some/where /mnt/readonly
mount -o remount,ro,bind /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。
主文件夹?并挂载-将其他用户作为我自己的另一个示例。
在监狱或容器中安装
chroot监狱或容器在系统目录树的子树中运行一个进程。这对于运行访问受限的程序很有用,例如运行一个网络服务器,该服务器只能访问自己的文件及其服务的文件,而不能访问存储在同一计算机上的其他数据。 chroot的局限性在于该程序仅限于一个子树:它无法访问独立的子树。绑定安装允许将其他子树嫁接到该主树上。这使它们成为Linux下最实际使用容器的基础。
例如,假设机器运行服务/usr/sbin/somethingd,该服务只能访问/var/lib/something下的数据。包含这两个文件的最小目录树是根。如何限制服务?一种可能性是使硬链接到/usr/sbin/somethingd下服务所需的所有文件(至少/var/lib/something和几个共享库)。但这很麻烦(每次升级文件时都需要更新硬链接),并且如果/var/lib/something/usr位于不同的文件系统上则不起作用。更好的解决方案是创建一个临时根目录并使用mounts进行填充:
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

Linux的mount名称空间一般化chroot。绑定挂载是如何以灵活的方式填充名称空间的方法。例如,请参见使进程读取具有相同文件名的其他文件。
运行不同的发行版
chroots的另一种用法是在目录中安装不同的发行版并从中运行程序,即使它们运行时要求在基本系统上不存在或内容不同的硬编码路径上的文件。例如,这可用于在不支持混合软件包的64位系统上安装32位发行版,安装发行版的较旧版本或其他发行版以测试兼容性,安装较新的发行版以进行测试最新的功能,同时保持稳定的基本系统等。请参见如何在64位Debian / Ubuntu上运行32位程序?以Debian / Ubuntu上的示例为例。
假设您在目录/f/unstable下安装了发行版的最新软件包,在该目录下,通过使用chroot /f/unstable切换到该目录来运行程序。要使此安装中的主目录可用,请将其绑定安装到chroot中:
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

schroot程序会自动执行此操作。在目录上挂载文件系统时,这会隐藏目录后的内容。在卸载目录之前,该目录中的文件将无法访问。由于BSD nullfs和Linux绑定安装的操作级别低于安装基础结构,因此文件系统的nullfs安装或绑定安装会公开隐藏在原始文件子安装后面的目录。
例如,假设您有一个tmpfs文件系统安装在/tmp上。如果在创建tmpfs文件系统时/tmp下存在文件,这些文件可能仍然保留,实际上无法访问,但占用了磁盘空间。运行
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)或
mount --bind /home /f/unstable/home

(FreeBSD)在/mnt处创建根文件系统的视图。目录/mnt/tmp是根文件系统中的目录。
NFS导出到不同的路径
某些NFS服务器(例如NFSv4之前的Linux内核NFS服务器)在导出目录时总是公布实际的目录位置。即,当客户端请求server:/requested/location时,服务器在位置/requested/location处为树提供服务。有时希望允许客户端请求/request/location但实际上在/actual/location下提供文件。如果您的NFS服务器不支持在备用位置提供服务,则可以为预期的请求创建绑定安装,例如,在
/etc/exports中的
/etc/fstab
,在/some/where/is/my/file中的以下内容:
mount --bind / /mnt

替代符号链接
有时您想创建符号链接以使文件/else/where出现在file下,但是使用/some/where/is/my/file的应用程序会扩展符号链接并拒绝/some/where/is/my。绑定安装可以解决此问题:将/else/where/is/my绑定到realpath,然后/else/where/is/my/file将报告/else/where/some/where之下,而不是find -xdev之下。
bind mounts的副作用
递归目录遍历
如果您使用绑定装载,则需要照顾递归遍历文件系统树的应用程序,例如备份和索引(例如,建立定位数据库)。
通常,绑定装载应从递归目录遍历中排除,因此,每个目录树在原始位置仅被遍历一次。如果可能,请使用bindfs和nullfs配置遍历工具以忽略这些文件系统类型。 Linux绑定安装无法这样识别:新位置与原始位置相同。使用Linux绑定安装,或者使用只能排除路径而不是文件系统类型的工具,您需要排除绑定安装的安装点。
在文件系统边界停止的遍历(例如,rsync -xdu -xbindfs -r等)当他们遇到bindfs或nullfs挂载点时,它将自动停止,因为该挂载点是一个不同的文件系统。使用Linux绑定安装时,情况要复杂一些:仅当绑定安装移植了另一个文件系统时才存在文件系统边界,而在移植同一文件系统的另一部分时则没有文件系统边界。
超越绑定安装< br挂架提供了位于不同位置的目录树视图。它们公开相同的文件,可能具有不同的装入选项,并且(具有bindfs)具有不同的所有权和权限。呈现目录树视图更改的文件系统称为覆盖文件系统或可堆叠文件系统。还有许多其他覆盖文件系统可以执行更高级的转换。这是一些常见的。如果此处未涵盖您所需的用例,请检查FUSE文件系统的存储库。


loggedfs-记录所有文件系统访问以进行调试或监视(配置文件语法,是否可以找到哪些程序或脚本创建了给定文件?,列出程序访问的文件)

过滤可见文件


clamfs-在读取文件时通过病毒扫描程序运行文件


filterfs-隐藏文件系统的一部分


rofs-只读视图。与tree1相似,只是更轻巧。


联合挂载—在单个目录下显示多个文件系统(称为分支):如果foo包含tree2bar包含foo,则它们的并集视图包含bar和q4312079q。新文件将写入特定分支,或写入根据更复杂规则选择的分支。此概念有几种实现,包括:


aufs — Linux内核实现,但在上游被多次拒绝。 br />
mhddfs —保险丝,基于可用空间将文件写入分支
overlay — Linux内核实现,在Linux v3.18中合并到上游

unionfs -fuse — FUSE,具有缓存和写入时复制功能



修改文件名和元数据


ciopfs —大小写-不敏感的文件名(对于挂载Windows文件系统可能有用)

convmvfs —在字符集之间转换文件名(示例)

posixovl —存储Unix文件名和其他元数据(权限,所有权) ,…),例如VFAT等受限制的文件系统(示例)

查看更改的文件内容档案(示例,更多示例)。还有许多FUSE文件系统,它们将特定的存档显示为目录。

fuseflt —在读取文件时通过管道运行文件,例如重新编码文本文件或媒体文件(示例)

lzopfs-压缩文件的透明解压缩

mp3fs-读取FLAC文件时将它们转换为MP3(示例)

scriptfs —执行脚本以提供内容(一种本地CGI)(示例)

修改内容的存储方式


chironfs —将文件复制到多个基础存储(目录树级别的RAID-1)

copyfs —保留文件所有版本的副本

encfs —加密文件

pcachefs-慢速远程文件系统的磁盘缓存层

simplecowfs-通过提供的视图将更改存储在内存中,保留原始文件完整

wayback —保留文件所有版本的副本


评论


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

– dothebart
16-09-22在11:06

mount --bind / dir1 / dir1有什么作用?与安装源和安装目标不同的情况有何不同?

–马克
18年2月16日在1:16

我在使用Linux 5.0的/ proc / self / mountinfo中没有看到任何记录。内核没有告诉我是否绑定绑定。而且一个进程可以轻易破坏chroot,必须通过mount名称空间来实现隔离。

–炸鱼薯条德里克
19年3月22日在3:19

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

–吉尔斯'所以-不再是邪恶的'
19-09-10在17:36

吉勒斯,谢谢您提供了惊人的详细答案。我建议您在第一个命令后阐明以下语句:“目录/ some / where和/ else / where具有相同的内容。”这比起坐骑更让人联想到硬链接。其中哪个包含数据,哪个是空目录(挂载点)? (我知道答案,这是对改进您的参考的建议)IMO,通过使用/ mnt作为示例安装点,可以轻松避免这种混淆。这立即使您清楚哪个arg是绑定的源,哪个是安装点。当然,由您决定。再次感谢。

–kkm
12月17日12:39

#2 楼

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

评论


这是使用绑定安装的方法之一,但是绑定安装本身与容器无关。我在回答中提到了这一点,但其名称是“监狱”而不是“容器”。添加“容器”将是很有价值的编辑(我会做)。这也是一个很差的描述:为什么要提及在外部进行的更改也可以在内部进行而不用相反地提及?

–吉尔斯'所以-不再是邪恶的'
19-09-10 17:20