登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

Linux mount namespace选择 shared、private 与 slave 传播属性的实现方法

来源:17golang原创

时间:2026-09-20 01:05:46 204浏览 收藏

我在排查容器或服务的挂载隔离时,最容易踩的坑不是命令不会写,而是把 namespace 隔离和挂载传播混成了一件事。创建新的 mount namespace 只复制挂载视图;如果挂载点仍属于 shared peer group,后续 mount、umount 事件仍可能沿着传播关系进入另一个 namespace。选择 shared、private 还是 slave,关键看事件方向:双向同步用 shared,只接收上游变化用 slave,完全不互通用 private。

要点速览
  • shared 会在同一 peer group 的挂载之间双向传播直接子挂载事件。
  • slave 接收 master shared group 的事件,但不会把本地事件传回上游。
  • private 不加入 peer group,事件既不进入也不出去;递归变更要显式使用 r 变体。
  • 复查时看 /proc/self/mountinfo 的 shared:X、master:X 等可选字段,不要只看目录是否存在。

资料入口:https://man7.org/linux/man-pages/man7/mount_namespaces.7.html

先按事件方向区分三种传播属性

把一个挂载点想成 namespace 边界上的“接收器”。shared 既接收也转发:同一 peer group 中某个挂载点下面创建或卸载直接子挂载,其他 peer 会看到对应变化。private 没有 peer group,变化停留在当前挂载树。slave 则保留一条从 master 到本地的输入通道,本地发生的挂载变化不会反向污染 master。

这也解释了为什么“我要隔离 namespace”并不自动等于“我要 private”。有些守护进程需要感知宿主的新挂载,但不能把自己的临时挂载带回宿主,这时 slave 比 private 更合适;需要多个 namespace 共享设备挂载时,才选择 shared。

Linux mount namespace 中 shared、slave、private 三种挂载传播方向的静态结构说明图
图1:Linux 挂载传播方向说明图,展示 shared 的双向关系、slave 的单向接收和 private 的隔离边界;这是静态说明图,不是运行截图。

按 namespace 的职责选择传播策略

可以先问三个问题:这个 namespace 是否要把新挂载同步给其他 namespace?是否只需要接收宿主或上游的挂载事件?是否要求本地 mount 和 umount 对外完全不可见?答案分别对应 shared、slave 和 private。

目标建议属性事件方向常见边界
多个视图共同管理挂载shared双向任一 peer 的直接子挂载变化可能传播
观察上游挂载但隔离本地操作slave上游到本地本地事件不回传 master
测试或沙箱完全隔离private要注意父挂载的继承和递归范围

传播属性是每个 mount point 的设置,不是整个 namespace 的抽象标签。父挂载是 shared 时,新建子挂载通常会继承 shared;否则新挂载通常是 private。使用 unshare 创建 namespace 时,util-linux 还可能把挂载递归改成 private;如果要保留原传播关系,需要显式关注 unshare 的 propagation 选项。

用 mount 的 make 变体设置传播属性

命令行操作最好先限定到明确的挂载点。下面的命令只展示配置语义,实际执行前应确认目标不是根文件系统上的关键共享路径:

# 双向传播:把 /srv/shared 加入一个 shared peer group
mount --make-shared /srv/shared

# 单向接收:/srv/worker 接收上游事件,但本地事件不回传
mount --make-slave /srv/worker

# 完全隔离:/srv/sandbox 不接收也不发送传播事件
mount --make-private /srv/sandbox

# 递归修改目标及其下方的挂载点;参数中的 r 表示 recursive
mount --make-rprivate /srv/sandbox

单点形式只改变目标 mount,递归形式会把目标以下的挂载一起处理。不要把 --make-private 和“删除挂载”混用:它不会卸载已有文件系统,只是改变后续 mount、umount 事件的传播关系。内核还不允许在一次底层 mount(2) 调用里混合多个传播标志,因此脚本里应把策略变更和其他挂载操作分开记录。

Linux mountinfo 中 shared、master 和无可选字段 private 标记的静态结构说明图
图2:mountinfo 复查说明图,突出 shared:X、master:X 与无可选传播字段的识别方式;这是静态说明图,不是命令运行结果截图。

用 mountinfo 复查,而不是凭目录现象猜测

设置后可以检查当前进程看到的挂载元数据。输出中的可选字段位于文件系统类型字段之前,常见标记如下:

# 只提取挂载点与传播相关的可选字段,便于人工核对
awk '{
  # 分隔符 “ - ” 左侧包含挂载点和可选字段
  split($0, left, " - ");
  if (left[1] ~ /shared:|master:|propagate_from:/) print left[1];
}' /proc/self/mountinfo
  • shared:X 表示该挂载属于编号为 X 的 peer group。
  • master:X 表示它是某个 shared peer group 的 slave。
  • 没有这些可选字段时,通常表示 private;如果看到 propagate_from:X,说明当前进程看不到 slave 的直接 master,但仍能观察到传播来源。

复查时要看目标挂载和它的父挂载。一个子目录显示为 shared,并不代表所有兄弟目录都共享;递归 bind、move 以及父挂载的传播属性都可能改变新挂载的最终状态。尤其在 shared 父挂载下移动挂载,可能受到内核共享子树语义的限制,不能只用“目录存在”判断操作成功。

常见问题

shared 和 slave 最大的区别是什么

shared 在 peer group 内双向传播挂载事件;slave 只从 master 接收,不能把本地事件传回 master。

private 会不会删除当前挂载

不会。private 只改变传播属性,已有挂载仍在,后续 mount 和 umount 事件不再跨该边界传播。

为什么设置 private 后子目录看起来仍有挂载

传播属性不会清除已有子挂载,而且单点设置不覆盖整棵树。需要隔离整棵树时使用 --make-rprivate,再用 mountinfo 逐级复查。

slave 能否同时参与其他传播关系

可以。一个 mount 既可能作为某个 peer group 的 slave 接收上游事件,也可能在另一个 peer group 中共享本地事件;排查时要同时关注 master 和 shared 标记。

实际选择时不要从命令名倒推结果,先画出“谁产生挂载事件、谁需要看到、谁不能被影响”的边界,再决定传播方向。最后把命令和 mountinfo 复查放在同一份部署记录里,后续迁移 namespace 或升级容器运行时才不容易出现隐性的挂载串线。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>