当前位置:首页 > 文章列表 > 文章 > linux > mount namespace 中绑定挂载的传播属性

mount namespace 中绑定挂载的传播属性

来源:17golang原创 2026-10-10 19:23:25 0浏览 收藏

在 Linux 里,mount --bind 只是在另一个路径上建立同一挂载的视图;它不会自动决定后续挂载事件是否同步。真正决定“这个目录里的新挂载要不要出现在另一个位置”的,是挂载传播属性。常用的四种状态是 shared、slave、private 和 unbindable。

官方地址:https://docs.kernel.org/filesystems/sharedsubtree.html

把 bind mount 理解成“复制挂载视图”,把传播属性理解成“挂载事件的边界”:需要双向同步时用 shared,需要只从宿主接收时用 slave,需要隔离时用 private;unbindable 则是在 private 基础上禁止再次绑定。

先分清 bind mount 和传播属性

绑定挂载连接的是一个已有的挂载树和新的挂载点。它可以让两个路径看到相同的文件系统内容,但“看到相同内容”和“收到之后产生的新挂载”不是一回事。比如在源路径下面后来挂载一个临时文件系统,目标路径是否出现对应的子挂载,取决于两边的传播关系。

mount namespace 也不能替代传播属性。创建新的命名空间时,会得到一份挂载视图;如果相关挂载属于 shared peer group,事件仍可能跨命名空间传播。如果需要完全隔离,通常要在子命名空间中把目标树设为 private,再进行后续操作。

本次实验只使用独立的临时目录和 bind mount,不直接修改生产根目录。下面的命令需要 root 权限,适合在一次性虚拟机或专门的 Linux 实验环境中阅读和操作。

shared、slave、private 和 unbindable 四种挂载传播状态及其事件方向的静态结构说明图
图1:四种挂载传播属性的方向与绑定限制说明图,不是截图或运行证据。

四种状态分别意味着什么

可以先用一张速查表建立判断标准:

状态接收事件转发事件适合的边界
shared是是多个挂载视图需要保持同步
slave从 master 接收否子环境只跟随宿主,不反向影响宿主
private否否命名空间或服务需要独立挂载树
unbindable否否还要禁止该挂载被再次 bind

shared 的多个挂载属于同一个 peer group,挂载和卸载事件会在组内传播。slave 有一个 master,只接收来自 master 的事件,slave 自己产生的事件不会回传。private 不接收也不转发传播事件。unbindable 的传播语义和 private 类似,但它不能作为 bind mount 的源。

建立一个可回收的绑定挂载实验

先创建实验目录,再绑定一个子目录。这里不挂载真实块设备,而是把另一个普通目录作为后续的“挂载事件”演示对象,避免实验依赖具体磁盘。

# 建立独立实验树;不要直接把生产目录作为实验源路径
LAB=/tmp/mount-propagation-lab
mkdir -p "$LAB/source/incoming" "$LAB/bind/incoming" "$LAB/event-source"

# 创建 bind mount,让 bind 目录先看到 source 的内容
mount --bind "$LAB/source" "$LAB/bind"

# 读取挂载点和传播状态;PROPAGATION 列是判断依据
findmnt -o TARGET,FSTYPE,PROPAGATION "$LAB/source" "$LAB/bind"

# 显式设为 private,先得到不会向外传播的基线
mount --make-private "$LAB/source"
mount --make-private "$LAB/bind"
findmnt -o TARGET,PROPAGATION "$LAB/source" "$LAB/bind"

检查时重点看 PROPAGATION 列,而不是只看两个路径能否列出相同文件。实验树如果原本继承了宿主的 shared 属性,后续命令可能影响其他挂载视图,所以先显式设为 private 更容易解释和回收。

用 shared 观察双向传播

shared 的核心是“挂载事件属于同一个传播组”。先让源挂载成为 shared,再建立一个共享的 bind 视图;随后在其中一个视图下面创建新的挂载,理论上另一个 peer 也会获得对应的挂载点。

# 把源挂载加入 shared peer group;这是传播关系,不是文件复制
mount --make-shared "$LAB/source"

# 在源树上建立第二个视图,并把目标也明确设为 shared
mount --bind "$LAB/source" "$LAB/bind"
mount --make-shared "$LAB/bind"

# 用 findmnt 读取传播标记;shared:数字表示 peer group 标识
findmnt -o TARGET,PROPAGATION "$LAB/source" "$LAB/bind"

# 在源树中建立一个新的 bind mount,模拟“后来发生的挂载事件”
mount --bind "$LAB/event-source" "$LAB/source/incoming"

# 检查两个视图是否都出现 incoming;不要只检查目录是否存在
findmnt -R "$LAB/source"
findmnt -R "$LAB/bind"

这段实验的结论不是“bind 一定双向同步”,而是“当挂载处在同一个 shared 传播关系中时,新的挂载事件可以同步到 peer”。如果只做了 mount --bind,没有确认传播状态,就不能从 bind 这一动作推断后续事件的方向。

用 slave 把传播方向限制为单向

容器和服务隔离经常需要这样的关系:宿主新增的挂载能被子环境看到,但子环境自己的挂载不能反向出现在宿主。这时可以让子侧成为 master 的 slave。

# 先让源树成为 shared,作为 master 传播端
mount --make-shared "$LAB/source"

# 创建 bind 视图,再将目标变成 slave;它接收 master 事件但不反向发送
mount --bind "$LAB/source" "$LAB/bind"
mount --make-slave "$LAB/bind"

# 读取 master/slave 关系,确认 bind 端不再是普通 private 视图
findmnt -o TARGET,PROPAGATION "$LAB/source" "$LAB/bind"

# 生产脚本中应先用 findmnt 找到目标,再决定是否允许该挂载传播
findmnt -R "$LAB"

slave 不是“只读目录”。它仍然可以在自己的视图中进行允许的挂载操作,只是这些新事件不会回传给 master。需要双向协作时不要误用 slave;需要彻底隔离时也不要把 slave 当成 private。

把传播属性放进 mount namespace

进入新的 mount namespace 后,最容易踩的坑是只看到“路径不同”,却没有判断挂载树是否仍处于 shared 传播关系。可以在 namespace 内先把根挂载树设为 private,再对确实需要从宿主接收的子树使用 slave。

宿主 mount namespace、子 mount namespace、bind mount 与 shared、slave、private 传播边界的静态结构说明图
图2:mount namespace 与绑定挂载传播边界的结构说明图,不是截图或运行证据。
# 在一次性实验中创建新的 mount namespace;需要 root 或相应的 namespace 权限
unshare --mount --fork /bin/sh 

mount --make-rprivate / 会改变当前命名空间内根挂载树的传播属性,因此应只在隔离的实验进程中使用。若实际目标是让容器接收宿主的设备或卷挂载,通常只把明确的子树设为 slave 或 shared,而不是对整个根树做宽泛修改。

检查与清理时看哪些证据

排查传播问题时,把检查拆成三层:挂载点是否存在、传播类型是什么、后续事件是否出现在预期视图。findmnt 适合看当前挂载树;/proc/self/mountinfo 可以作为更底层的补充,但不要把一串数字直接当成传播方向。

# 只列出实验树,先确认 bind mount 的 TARGET 和 SOURCE
findmnt -R "$LAB"

# 单独读取传播属性,关注 shared、master、propagate_from 等字段
findmnt -o TARGET,SOURCE,FSTYPE,PROPAGATION "$LAB/source" "$LAB/bind"

# 结束实验时先卸载子挂载,再卸载 bind mount,最后删除空目录
umount "$LAB/source/incoming" 2>/dev/null || true
umount "$LAB/bind/incoming" 2>/dev/null || true
umount "$LAB/bind" 2>/dev/null || true
rmdir "$LAB/source/incoming" "$LAB/bind/incoming" 2>/dev/null || true
rm -rf "$LAB"

清理命令里的 || true 只是让“已经不存在的实验挂载”不阻塞后续回收;生产脚本不应吞掉所有卸载错误,而应记录仍被进程占用的挂载点。删除目录不会卸载挂载本身,必须先处理挂载关系。

按需求选择传播属性

需求优先考虑主要原因
多个视图需要看到同一批新挂载shared事件在 peer group 内传播
子环境跟随宿主但不能反向影响宿主slave只接收 master 事件
服务或 namespace 完全自主管理挂载private不接收也不转发事件
挂载树不能作为 bind 源unbindable阻止再次绑定

最后记住三个判断顺序:先确认自己正在看的挂载点,接着读取它的传播属性,最后用一个受控的子挂载验证事件方向。这样即使 mount namespace、bind mount 和容器运行时叠在一起,也能把“看得到文件”与“传播新挂载”分开定位。

常见问题

为什么做了 bind mount,目标目录却没有同步新挂载?

因为 bind mount 不等于 shared。先用 findmnt -o TARGET,PROPAGATION 读取两边状态;如果是 private,就不会接收或转发新挂载事件。

slave 和 private 有什么区别?

private 完全不参与传播;slave 可以从 master 接收事件,只是不把自己的事件反向转发。容器需要跟随宿主挂载时,slave 通常比 private 更贴合目标。

为什么实验会影响宿主机的挂载树?

常见原因是实验目录继承了 shared 属性,或者在没有隔离的 mount namespace 中直接修改了共享挂载。实验开始时使用独立目录,并在 namespace 内显式执行 mount --make-rprivate /。

unbindable 什么时候有用?

当一棵挂载树不应该被再次 bind,且也不需要接收或转发事件时,可以使用 unbindable。它主要表达“不可复制这个挂载入口”的限制,不是更强的权限控制。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Fetch Streams 分段读取大响应体的背压控制Fetch Streams 分段读取大响应体的背压控制
上一篇
Fetch Streams 分段读取大响应体的背压控制
database/sql 查询上下文取消后的 rows 状态
下一篇
database/sql 查询上下文取消后的 rows 状态
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    408次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    484次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    494次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    440次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    268次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码