命名空间——挂载 (mnt)
一、先理解最基础的两个概念
-
挂载点(mount point):
简单说,就是把一个存储设备(比如硬盘分区、虚拟内存文件系统)“连接”到Linux文件系统树中的某个目录。
比如:把U盘插入电脑后,执行mount /dev/sdb1 /mnt/usb,此后访问/mnt/usb就相当于访问U盘里的内容——/mnt/usb就是“挂载点”。 -
命名空间的核心作用:
让不同的进程“看到的世界不一样”。对于挂载命名空间来说,就是让不同进程“看到的文件系统挂载点不一样”(即“文件系统视图”隔离)。
二、挂载命名空间:让进程拥有“独立的文件系统视图”
挂载命名空间(mnt namespace)是Linux最早实现的命名空间,它的核心功能是:让不同的进程组拥有独立的“挂载点集合”。
也就是说:
- 进程A在自己的挂载命名空间里挂载了一个设备到
/test,进程B如果在另一个挂载命名空间,它的/test可能还是空的,完全看不到A的挂载; - 进程A卸载了某个挂载点,也不会影响进程B看到的文件系统。
三、如何创建和使用挂载命名空间?
1. 通过 clone() 系统调用创建(编程层面)
clone() 是创建新进程的函数,当给它传递 CLONE_NEWNS 标志时,会为新进程创建一个全新的挂载命名空间。
- 这个新命名空间会先“复制”父进程当前的所有挂载点(相当于“继承”初始状态);
- 之后新进程对挂载点的修改(比如挂载/卸载设备),只会影响自己的命名空间,父进程完全看不到。
为什么标志叫 CLONE_NEWNS 而不是 CLONE_NEWMNT?
因为它是第一个命名空间,当时开发者没想到后来会有其他类型(比如PID、网络命名空间),所以名字起得比较笼统(NS = Namespace)。
2. 通过 unshare 命令创建(命令行层面,更直观)
unshare 命令对应 unshare() 系统调用,作用是“让当前进程脱离原来的命名空间,创建并进入新的命名空间”(不创建新进程,直接改当前进程的归属)。
步骤1:在第一个终端创建带文件的 tmpfs(新命名空间)
# 终端A:创建新的挂载命名空间并进入
# 1. 用 unshare -m 创建并进入新的挂载命名空间(-m 对应挂载命名空间)
sudo unshare -m /bin/bash
# 此时你进入了一个新的bash进程,它已经在新的挂载命名空间里了
# 2. 在当前目录创建一个文件夹作为挂载点
mkdir mount-dir
# 3. 挂载一个tmpfs(内存虚拟文件系统,数据只存在内存中)到 mount-dir
mount -n -o size=10m -t tmpfs tmpfs mount-dir
# 4. 查看挂载结果:会看到 mount-dir 已经挂载了tmpfs
df mount-dir # 能看到一行关于 mount-dir 的挂载信息
# 5. 在这个挂载点里创建几个文件
touch mount-dir/{0,1,2}
ls mount-dir # 能看到 0、1、2 三个文件
步骤2:在第二个终端直接挂载 tmpfs 到同一目录(原命名空间)
# 终端B:使用系统默认的挂载命名空间(不执行unshare)
# 注意:如果mount-dir不存在,先创建
mkdir -p mount-dir
# 直接挂载tmpfs到mount-dir
sudo mount -n -o size=10m -t tmpfs tmpfs mount-dir
# 查看文件
ls mount-dir # 输出:(空的!看不到终端A创建的0、1、2)
为什么看不到?核心原因:两个终端在不同的挂载命名空间
-
终端A的
mount-dir属于“新挂载命名空间”:
它挂载的tmpfs是这个命名空间独有的,相当于一块“独立的内存区域”,里面的文件(0、1、2)只属于这个命名空间。 -
终端B的
mount-dir属于“默认挂载命名空间”:
它挂载的tmpfs是另一块“独立的内存区域”,和终端A的tmpfs没有任何关联(即使挂载点目录名称相同)。
这就像两个完全隔离的“内存文件夹”,虽然都叫mount-dir,但里面的内容各自独立。
如何让另一个终端看到这三个文件?
必须让另一个终端加入终端A所在的挂载命名空间,才能共享同一个 tmpfs 挂载点。具体步骤:
-
在终端A中查看当前进程的PID:
# 终端A中执行(此时仍在unshare创建的bash里) echo $$ # 假设输出 PID=1234 -
在终端B中加入终端A的挂载命名空间:
使用nsenter命令(基于setns()系统调用),进入终端A的命名空间:# 终端B中执行 sudo nsenter --mount=/proc/1234/ns/mnt /bin/bash此时终端B的bash已经进入了终端A的挂载命名空间。
-
在终端B中查看文件:
# 终端B中执行(已进入终端A的命名空间) ls mount-dir # 输出:0 1 2(成功看到文件!)
总结
tmpfs虽然在内存中,但不同挂载命名空间的tmpfs是完全隔离的,即使挂载点目录名称相同,内容也不互通。- 只有让进程“加入同一个挂载命名空间”,才能共享该命名空间内的
tmpfs挂载点及其中的文件(通过nsenter命令实现)。
这正是命名空间“资源隔离”的核心:同名目录不等于同一资源,关键看是否在同一个命名空间中。
四、如何查看进程的挂载命名空间信息?
如果想知道某个进程在哪个挂载命名空间,或者它能看到哪些挂载点,可以用这些方法:
-
在终端A中查看当前进程的PID:
# 终端A中执行(此时仍在unshare创建的bash里) echo $$ # 假设输出 PID=1234 -
查看进程的挂载点详情:
/proc/[进程ID]/mountinfo文件记录了该进程所在命名空间的所有挂载点信息。
比如,查看刚才unshare启动的bash进程(假设PID是1234)的挂载点:cat /proc/1234/mountinfo | grep mount-dir会看到一行关于
mount-dir的挂载记录,而其他进程的mountinfo里则没有。 -
查看当前环境的挂载点:
直接用mount -l或df -h,它们显示的是“当前进程所在命名空间”的挂载点。
五、挂载命名空间的典型应用:容器的“独立文件系统”
Docker等容器技术能让每个容器有自己的“文件系统”(比如容器里的 / 和主机的 / 完全不同),核心就是通过挂载命名空间实现的:
- 容器启动时,会创建一个新的挂载命名空间;
- 然后在这个命名空间里挂载容器自己的根文件系统(比如一个打包好的镜像);
- 容器内的进程看到的是这个独立的文件系统,不会影响主机的文件系统。
总结
挂载命名空间的核心是“隔离文件系统的挂载点”:
- 不同命名空间的进程,看到的挂载点(文件系统结构)可以完全不同;
- 通过
clone(CLONE_NEWNS)或unshare -m可以创建新的挂载命名空间; - 它是容器实现“独立文件系统”的底层技术之一。
简单说,就像每个命名空间是一个“独立的房间”,你在自己房间里“摆放家具”(挂载设备),其他房间的人完全看不到,也不会被影响。
820

被折叠的 条评论
为什么被折叠?



