命名空间——挂载 (mnt)

命名空间——挂载 (mnt)

一、先理解最基础的两个概念

  1. 挂载点(mount point)
    简单说,就是把一个存储设备(比如硬盘分区、虚拟内存文件系统)“连接”到Linux文件系统树中的某个目录。
    比如:把U盘插入电脑后,执行 mount /dev/sdb1 /mnt/usb,此后访问 /mnt/usb 就相当于访问U盘里的内容——/mnt/usb 就是“挂载点”。

  2. 命名空间的核心作用
    让不同的进程“看到的世界不一样”。对于挂载命名空间来说,就是让不同进程“看到的文件系统挂载点不一样”(即“文件系统视图”隔离)。

二、挂载命名空间:让进程拥有“独立的文件系统视图”

挂载命名空间(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)
为什么看不到?核心原因:两个终端在不同的挂载命名空间
  1. 终端A的 mount-dir 属于“新挂载命名空间”
    它挂载的 tmpfs 是这个命名空间独有的,相当于一块“独立的内存区域”,里面的文件(0、1、2)只属于这个命名空间。

  2. 终端B的 mount-dir 属于“默认挂载命名空间”
    它挂载的 tmpfs 是另一块“独立的内存区域”,和终端A的 tmpfs 没有任何关联(即使挂载点目录名称相同)。
    这就像两个完全隔离的“内存文件夹”,虽然都叫 mount-dir,但里面的内容各自独立。

如何让另一个终端看到这三个文件?

必须让另一个终端加入终端A所在的挂载命名空间,才能共享同一个 tmpfs 挂载点。具体步骤:

  1. 在终端A中查看当前进程的PID

    # 终端A中执行(此时仍在unshare创建的bash里)
    echo $$  # 假设输出 PID=1234
    
  2. 在终端B中加入终端A的挂载命名空间
    使用 nsenter 命令(基于 setns() 系统调用),进入终端A的命名空间:

    # 终端B中执行
    sudo nsenter --mount=/proc/1234/ns/mnt /bin/bash
    

    此时终端B的bash已经进入了终端A的挂载命名空间。

  3. 在终端B中查看文件

    # 终端B中执行(已进入终端A的命名空间)
    ls mount-dir  # 输出:0 1 2(成功看到文件!)
    
总结
  • tmpfs 虽然在内存中,但不同挂载命名空间的 tmpfs 是完全隔离的,即使挂载点目录名称相同,内容也不互通。
  • 只有让进程“加入同一个挂载命名空间”,才能共享该命名空间内的 tmpfs 挂载点及其中的文件(通过 nsenter 命令实现)。

这正是命名空间“资源隔离”的核心:同名目录不等于同一资源,关键看是否在同一个命名空间中

四、如何查看进程的挂载命名空间信息?

如果想知道某个进程在哪个挂载命名空间,或者它能看到哪些挂载点,可以用这些方法:

  1. 在终端A中查看当前进程的PID

    # 终端A中执行(此时仍在unshare创建的bash里)
    echo $$  # 假设输出 PID=1234
    
  2. 查看进程的挂载点详情
    /proc/[进程ID]/mountinfo 文件记录了该进程所在命名空间的所有挂载点信息。
    比如,查看刚才 unshare 启动的bash进程(假设PID是1234)的挂载点:

    cat /proc/1234/mountinfo | grep mount-dir
    

    会看到一行关于 mount-dir 的挂载记录,而其他进程的 mountinfo 里则没有。

  3. 查看当前环境的挂载点
    直接用 mount -ldf -h,它们显示的是“当前进程所在命名空间”的挂载点。

五、挂载命名空间的典型应用:容器的“独立文件系统”

Docker等容器技术能让每个容器有自己的“文件系统”(比如容器里的 / 和主机的 / 完全不同),核心就是通过挂载命名空间实现的:

  • 容器启动时,会创建一个新的挂载命名空间;
  • 然后在这个命名空间里挂载容器自己的根文件系统(比如一个打包好的镜像);
  • 容器内的进程看到的是这个独立的文件系统,不会影响主机的文件系统。

总结

挂载命名空间的核心是“隔离文件系统的挂载点”:

  • 不同命名空间的进程,看到的挂载点(文件系统结构)可以完全不同;
  • 通过 clone(CLONE_NEWNS)unshare -m 可以创建新的挂载命名空间;
  • 它是容器实现“独立文件系统”的底层技术之一。

简单说,就像每个命名空间是一个“独立的房间”,你在自己房间里“摆放家具”(挂载设备),其他房间的人完全看不到,也不会被影响。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值