【Docker】4.NameSpace空间隔离实战

文章目录

  • [1. 基础准备](#1. 基础准备)
    • [1.1 dd 命令详解与镜像创建](#1.1 dd 命令详解与镜像创建)
    • [1.2 mkfs 命令与文件系统格式化](#1.2 mkfs 命令与文件系统格式化)
      • [1.2.1 为什么要格式化?](#1.2.1 为什么要格式化?)
    • [1.3 df命令详解](#1.3 df命令详解)
    • [1.4 mount 命令与磁盘挂载原理](#1.4 mount 命令与磁盘挂载原理)
      • [1.4.1 U盘类比](#1.4.1 U盘类比)
    • [1.5 unshare 命令概览](#1.5 unshare 命令概览)
  • [2. PID 隔离实战](#2. PID 隔离实战)
    • [2.1 PID 隔离实验操作](#2.1 PID 隔离实验操作)
  • [3. Mount 隔离与文件系统视图](#3. Mount 隔离与文件系统视图)
  • [4. 思维导图](#4. 思维导图)

1. 基础准备

1.1 dd 命令详解与镜像创建

dd (Data Duplicator): 这是一个底层的命令行工具,用于在 Linux 系统上读取、转换并输出原始数据。它可以直接操作字节流,因此常用于备份分区、销毁数据或创建指定大小的空文件(镜像)。

dd 可从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件、设备或标准输出。

Linux 中,最常用于创建、转换和拷贝原始数据的工具就是 dd 命令。

语法:

shell 复制代码
dd OPTION 

参数 :

  1. if=文件名:输入文件名,默认为标准输入。即指定源文件。

  2. of=文件名:输出文件名,默认为标准输出。即指定目的文件。

  3. ibs=bytes:一次读入 bytes 个字节,即指定一个块大小为 bytes 个字节。

    obs=bytes:一次输出 bytes 个字节,即指定一个块大小为 bytes 个字节。

    bs=bytes:同时设置读入/输出的块大小为 bytes 个字节。

  4. cbs=bytes:一次转换 bytes 个字节,即指定转换缓冲区大小。

  5. skip=blocks:从输入文件开头跳过 blocks 个块后再开始复制。

  6. seek=blocks:从输出文件开头跳过 blocks 个块后再开始复制。

  7. count=blocks:仅拷贝 blocks 个块,块大小等于 ibs 指定的字节数。

  8. conv=<关键字>,关键字可以有以下 11 种:

    1. conversion:用指定的参数转换文件。
    2. ascii:转换 ebcdic 为 ascii
    3. ebcdic:转换 ascii 为 ebcdic
    4. ibm:转换 ascii 为 alternate ebcdic
    5. block:把每一行转换为长度为 cbs,不足部分用空格填充
    6. unblock:使每一行的长度都为 cbs,不足部分用空格填充
    7. lcase:把大写字符转换为小写字符
    8. ucase:把小写字符转换为大写字符
    9. swap:交换输入的每对字节
    10. noerror:出错时不停止
    11. notrunc:不截短输出文件
    12. sync:将每个输入块填充到 ibs 个字节,不足部分用空(NUL)字符补齐。
  9. --help:显示帮助信息

  10. --version:显示版本信息

  • 数据量计算: 最终生成文件的大小 = bs × count
  • /dev/zero 这是一个特殊的设备文件,它会提供无限的空字符(NULL),常作为 if 来创建空镜像。

示例:创建一个 8,80MB 的磁盘镜像

shell 复制代码
# 创建一个名为 testns 的新目录
root@yudukai:~# mkdir testns

# 进入 testns 目录
root@yudukai:~# cd testns

# 查看当前目录的详细信息
# total 0 表示目录为空
root@yudukai:~/testns# ls -l
total 0

# 使用 dd 命令创建一个8MB的测试文件
# if=/dev/zero:输入文件为 /dev/zero(生成全0字节)
# of=test.img:输出文件名为 test.img
# bs=8k:块大小为8KB
# count=1024:复制1024个块
# 总大小 = 8KB × 1024 = 8MB
root@yudukai:~/testns# dd if=/dev/zero of=test.img bs=8k count=1024
1024+0 records in      # 读入1024个记录
1024+0 records out     # 写出1024个记录
8388608 bytes (8.4 MB, 8.0 MiB) copied, 0.00944598 s, 888 MB/s
# 文件大小8MB,耗时约0.009秒,速度888 MB/s

# 以人类可读格式查看文件信息
root@yudukai:~/testns# ll -h
total 8.1M
drwxr-xr-x  2 root root 4.0K Jul 29 18:14 ./
drwx------ 15 root root 4.0K Jul 29 18:13 ../
-rw-r--r--  1 root root 8.0M Jul 29 18:14 test.img
# 可以看到 test.img 文件大小为 8.0M

# 使用 dd 命令创建一个80MB的测试文件
# 总大小 = 8KB × 10240 = 80MB
root@yudukai:~/testns# dd if=/dev/zero of=test2.img bs=8k count=10240
10240+0 records in
10240+0 records out
83886080 bytes (84 MB, 80 MiB) copied, 0.0827256 s, 1.0 GB/s
# 文件大小80MB,耗时约0.083秒,速度1.0 GB/s

# 查看目录中的所有文件
root@yudukai:~/testns# ll -h
total 89M
drwxr-xr-x  2 root root 4.0K Jul 29 18:14 ./
drwx------ 15 root root 4.0K Jul 29 18:13 ../
-rw-r--r--  1 root root  80M Jul 29 18:14 test2.img  # 80MB文件
-rw-r--r--  1 root root 8.0M Jul 29 18:14 test.img    # 8MB文件
shell 复制代码
# 使用 vi 编辑器创建一个名为 in.txt 的文件
root@yudukai:~/testns# vi in.txt
# 在 vi 中输入了内容 "Hello World" 并保存退出

# 使用 dd 命令将 in.txt 转换为大写并输出到 out.txt
# if=in.txt:输入文件为 in.txt
# of=out.txt:输出文件为 out.txt
# conv=ucase:转换选项,将小写字母转换为大写字母(uppercase)
root@yudukai:~/testns# dd if=in.txt of=out.txt conv=ucase
0+1 records in      # 读入0+1个记录(不满一个块)
0+1 records out     # 写出0+1个记录
12 bytes copied, 0.000178502 s, 67.2 kB/s
# 共复制了12字节("Hello World\n",含换行符)

# 查看 in.txt 文件内容
root@yudukai:~/testns# cat in.txt
Hello World

# 查看 out.txt 文件内容(已全部转为大写)
root@yudukai:~/testns# cat out.txt
HELLO WORLD

1.2 mkfs 命令与文件系统格式化

mkfs (Make Filesystem): 这是一个用于在设备(或镜像文件)上建立 Linux 文件系统的命令。它会在磁盘空间内构建必要的数据结构,如 Superblock(超级块)、Inode 列表和数据块区。
Linux 中,刚创建的镜像文件就像一张白纸,虽然有了空间,但没有"格子"和"页码"。为了让操作系统能够管理文件、目录和权限,我们需要对其进行格式化。

语法:

shell 复制代码
mkfs [-V] [-t fstype] [fs-options] filesys [blocks] 

参数:

  • -t fstype:指定要建立何种文件系统;如 ext3ext4
  • filesys :指定要创建的文件系统对应的设备文件名;
  • blocks:指定文件系统的磁盘块数。
  • -V : 详细显示模式
  • fs-options:传递给具体的文件系统的参数

1.2.1 为什么要格式化?

  • dd 创建的镜像: 像是一本刚从造纸厂出来的、没有任何线条的空白本子。虽然它有厚度(空间),但你很难整齐地书写信息,事后也很难查找某个特定的段落。
  • mkfs 格式化后: 相当于给这本本子画上了行线、印上了页码,并预留了目录页 。有了这些结构,操作系统(读者)就能根据目录(Inode)快速找到对应的文字内容(Data Block)。

Namespace 隔离实战中,只有经过格式化的镜像,才能被 mount 命令识别并挂载到文件系统中,作为一个独立的"小世界"存在。
mkfs 实际上是一系列命令的通用前端。当你执行格式化时,它会根据你指定的类型调用对应的程序(如 mkfs.ext4mkfs.xfs

Linux 容器技术中,ext4 是最常用的日志文件系统之一,它稳定且支持各种高级特性。

示例:

shell 复制代码
# 在 test.img 文件上创建 ext4 类型的文件系统
# -t ext4:指定文件系统类型为 ext4
# ./test.img:目标文件(之前创建的8MB空文件)
root@yudukai:~/testns# mkfs -t ext4 ./test.img
mke2fs 1.46.5 (30-Dec-2021)		 # mke2fs 工具版本信息
Discarding device blocks: done   # 丢弃设备块(针对虚拟设备的优化)                         
Creating filesystem with 2048 4k blocks and 2048 inodes# 创建文件系统信息:
# - 2048 个 4KB 块 = 2048 × 4KB = 8MB 总大小
# - 2048 个 inode(索引节点,用于存储文件元数据)

Allocating group tables: done      # 分配组表(文件系统结构)                      
Writing inode tables: done         # 写入 inode 表                   
Creating journal (1024 blocks): done# 创建日志(1024个块,用于数据安全恢复)
Writing superblocks and filesystem accounting information: done# 写入超级块和文件系统统计信息

root@yudukai:~/testns# 

1.3 df命令详解

Linux df(英文全拼:disk free) 命令用于显示目前在 Linux 系统上的文件系统磁盘使用情况统计。

语法:

shell 复制代码
df [OPTION]... [FILE]...

常见参数

  • -a, --all:包含所有的具有 0 Blocks 的文件系统
  • -h, --human-readable:使用人类可读的格式(预设值是不加这个选项的...)
  • -H, --si:很像 -h, 但是用 1000 为单位而不是用 1024
  • -t, --type=TYPE:限制列出文件系统的 TYPE
  • -T, --print-type:显示文件系统的形式

案例:

shell 复制代码
root@yudukai:~/testns# df
Filesystem     1K-blocks     Used Available Use% Mounted on
tmpfs             814028    79784    734244  10% /run
/dev/vda1      185458052 25534852 151950328  15% /
tmpfs            4070132        0   4070132   0% /dev/shm
tmpfs               5120        0      5120   0% /run/lock
tmpfs             814024        0    814024   0% /run/user/0
root@yudukai:~/testns# df -a
Filesystem     1K-blocks     Used Available Use% Mounted on
sysfs                  0        0         0    - /sys
proc                   0        0         0    - /proc
udev             4012160        0   4012160   0% /dev
devpts                 0        0         0    - /dev/pts
tmpfs             814028    79784    734244  10% /run
/dev/vda1      185458052 25534852 151950328  15% /
securityfs             0        0         0    - /sys/kernel/security
tmpfs            4070132        0   4070132   0% /dev/shm
tmpfs               5120        0      5120   0% /run/lock
cgroup2                0        0         0    - /sys/fs/cgroup
pstore                 0        0         0    - /sys/fs/pstore
bpf                    0        0         0    - /sys/fs/bpf
systemd-1              -        -         -    - /proc/sys/fs/binfmt_misc
mqueue                 0        0         0    - /dev/mqueue
hugetlbfs              0        0         0    - /dev/hugepages
debugfs                0        0         0    - /sys/kernel/debug
tracefs                0        0         0    - /sys/kernel/tracing
fusectl                0        0         0    - /sys/fs/fuse/connections
configfs               0        0         0    - /sys/kernel/config
none                   0        0         0    - /run/credentials/systemd-sysusers.service
binfmt_misc            0        0         0    - /proc/sys/fs/binfmt_misc
tracefs                0        0         0    - /sys/kernel/debug/tracing
tmpfs             814024        0    814024   0% /run/user/0
root@yudukai:~/testns# df -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           795M   78M  718M  10% /run
/dev/vda1       177G   25G  145G  15% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           795M     0  795M   0% /run/user/0
root@yudukai:~/testns# df -H
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           834M   82M  752M  10% /run
/dev/vda1       190G   27G  156G  15% /
tmpfs           4.2G     0  4.2G   0% /dev/shm
tmpfs           5.3M     0  5.3M   0% /run/lock
tmpfs           834M     0  834M   0% /run/user/0
root@yudukai:~/testns# df -Th
Filesystem     Type   Size  Used Avail Use% Mounted on
tmpfs          tmpfs  795M   78M  718M  10% /run
/dev/vda1      ext4   177G   25G  145G  15% /
tmpfs          tmpfs  3.9G     0  3.9G   0% /dev/shm
tmpfs          tmpfs  5.0M     0  5.0M   0% /run/lock
tmpfs          tmpfs  795M     0  795M   0% /run/user/0
root@yudukai:~/testns# 

1.4 mount 命令与磁盘挂载原理

Linux 的世界里,有一个非常迷人的哲学:一切皆文件 。即使我们刚刚创建并格式化了一个 80MB 的虚拟磁盘 fdimage.img,如果你直接用文本编辑器打开它,你看到的只会是一堆乱码。

要真正像访问普通文件夹那样去读写它,我们需要执行"挂载(Mount"操作。
挂载 (Mounting): 是指将一个存储设备(如硬盘分区、镜像文件)的内容连接到 Linux 系统目录树中的某个特定目录(称为挂载点)的过程。一旦挂载成功,该目录就成了进入该存储设备的"入口"。


1.4.1 U盘类比

我们可以把挂载想象成在电脑上插 U 盘:

  • 镜像文件 (fdimage.img): 就像是一个物理 U 盘。虽然你手里拿着它,但如果不把它插进接口,你无法查看里面的数据。
  • 挂载点 (Mount Point): 就像是电脑上的 USB 接口(或路径) 。在 Linux 中,这通常是一个空的文件夹(如 /data/tmpmount)。
  • 执行 mount 就像是把 U 盘插入接口。动作完成后,你访问那个文件夹,实际上就是在读写这个虚拟镜像里的内容。
    mount的作用:

通过 mount,我们可以把这个镜像挂载到特定的 Namespace 中,让在该空间运行的进程只能看到这个镜像里的文件,从而实现文件系统的完全隔离

语法:

shell 复制代码
mount [-l] 
mount [-t vfstype] [-o options] device dir

常见参数:

  • -l:显示已加载的文件系统列表;
  • -t:加载文件系统类型支持常见系统类型的 ext3,ext4,iso9660,tmpfs,xfs 等,大部分情况可以不指定,mount 可以自己识别
  • -o options:主要用来描述设备或档案的挂接方式。
    • loop:用来把一个文件当成硬盘分区挂接上系统
    • ro:采用只读方式挂接设备
    • rw:采用读写方式挂接设备
  • device:要挂接(mount)的设备。
  • dir:挂载点的目录

案例:

shell 复制代码
root@yudukai:~/testns# ll
total 86144
drwxr-xr-x  2 root root     4096 Jul 29 18:16 ./
drwx------ 15 root root     4096 Jul 29 18:15 ../
-rw-r--r--  1 root root       12 Jul 29 18:15 in.txt
-rw-r--r--  1 root root       12 Jul 29 18:16 out.txt
-rw-r--r--  1 root root 83886080 Jul 29 18:14 test2.img
-rw-r--r--  1 root root  8388608 Jul 29 18:18 test.img
# 再次对 test.img 进行 ext4 文件系统格式化
# 注意:系统检测到该文件已包含一个 ext4 文件系统,并询问是否继续
root@yudukai:~/testns# mkfs -t ext4 ./test.img
mke2fs 1.46.5 (30-Dec-2021)
./test.img contains a ext4 file system
	created on Wed Jul 29 18:18:39 2026
Proceed anyway? (y,N) y
Discarding device blocks: done                            
Creating filesystem with 2048 4k blocks and 2048 inodes

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (1024 blocks): done
Writing superblocks and filesystem accounting information: done

# 创建挂载目录
# -p 参数确保父目录 /data 不存在时会自动创建
root@yudukai:~/testns# mkdir -p /data/testmymount
root@yudukai:~/testns# ll /data/testmymount/
total 8
drwxr-xr-x 2 root root 4096 Jul 29 18:42 ./
drwxr-xr-x 3 root root 4096 Jul 29 18:42 ../

# 将 test.img 挂载到 /data/testmymount
# 此时系统会自动使用 loop 设备(/dev/loop0)来挂载这个镜像文件
root@yudukai:~/testns# mount ./test.img /data/testmymount/

# 查看磁盘空间,确认挂载成功
root@yudukai:~/testns# df -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           795M   78M  718M  10% /run
/dev/vda1       177G   25G  145G  15% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           795M     0  795M   0% /run/user/0
/dev/loop0      3.5M   24K  3.0M   1% /data/testmymount
# 可以看到 loop0 设备大小为 3.5M(8MB镜像扣除元数据后的实际可用空间较小)
# 这里显示 3.5M 是因为 8MB 空间很大一部分被日志(4MB)和元数据占用了

# 进入挂载目录
root@yudukai:~/testns# cd /data/testmymount/

# 写入字符串 "123" 到 test.txt 文件
root@yudukai:/data/testmymount# echo "123" > test.txt
root@yudukai:/data/testmymount# ll -h
total 28K
drwxr-xr-x 3 root root 4.0K Jul 29 18:43 ./
drwxr-xr-x 3 root root 4.0K Jul 29 18:42 ../
drwx------ 2 root root  16K Jul 29 18:42 lost+found/ # ext4 自动创建的恢复目录
-rw-r--r-- 1 root root    4 Jul 29 18:43 test.txt    # 新创建的文件
root@yudukai:/data/testmymount# cat test.txt
123
root@yudukai:/data/testmymount# 

1.5 unshare 命令概览

unshare: 顾名思义,它的作用是"不共享"。它允许一个进程与其父进程脱离关系,不再共享某些指定的命名空间(Namespace),从而拥有自己独立的运行环境。

  • 默认情况下: 你和你的父进程(比如当前的 Shell)生活在同一个"空间"里。你改了主机名,它也能看到;你挂载了磁盘,它也跟着变。
  • 执行 unshare 后: 你瞬间开启了一个平行空间 。在这个空间里,你可以随意修改系统设置(如网络、进程 ID、挂载点),而原本那个空间(父进程所在的空间)对此一无所知,完全不受影响。

语法:

shell 复制代码
unshare [options] program [arguments] 

参数:

  • -i, --ipc:不共享 IPC 空间
  • -m, --mount:不共享 Mount 空间
  • -n, --net:不共享 Net 空间
  • -p, --pid:不共享 PID 空间
  • -u, --uts:不共享 UTS 空间
  • -U, --user:不共享用户
  • -V, --version:版本查看
  • --fork:执行 unshare 的进程 fork 一个新的子进程,在子进程里执行 unshare 传入的参数。
  • --mount-proc:执行子进程前,将 proc 优先挂载过去

案例:

shell 复制代码
# 创建新的 UTS 命名空间并在其中运行 /bin/bash
# -u 参数表示创建新的 UTS 命名空间
root@yudukai:/data/testmymount# unshare -u /bin/bash
# 此时进入了一个隔离的 shell 环境,拥有独立的 hostname

# 在新命名空间中修改主机名
root@yudukai:/data/testmymount# hostname test1
# 这里的修改只影响当前命名空间,不影响宿主机

# 在新命名空间中查看主机名
root@yudukai:/data/testmymount# hostname
test1
# 显示的是新设置的主机名(仅在当前命名空间内有效)

# 退出命名空间
root@yudukai:/data/testmymount# exit
exit
# 退出后回到原来的命名空间(宿主机环境)

# 在原命名空间中查看主机名
root@yudukai:/data/testmymount# hostname
yudukai
# 显示原来的主机名,证明刚才的修改没有影响宿主机
  • 在执行 exit 之前,你在隔离 Shell 里看到的是新名字。
  • 执行 exit 后,你会发现宿主机的主机名完全没有变化
    通过这个实验,我们成功验证了 UTS Namespace 的隔离能力。

虽然进程依然运行在同一台物理机器和同一个内核上,但通过 Namespace,我们为进程营造了一个"我拥有独立主机名"的假象。这是容器能够拥有独立身份标识的基础。


2. PID 隔离实战

2.1 PID 隔离实验操作

PID (Process ID) Namespace 的作用是隔离进程 ID 空间。在不同的 PID 命名空间里,可以有相同的 PID。这也是为什么每个容器都可以有一个 PID1init 进程,而互不干扰。
--fork 参数: 告诉 unshare 命令创建一个新的子进程(Fork),并让这个子进程 进入新的 PID

主机A

shell 复制代码
root@yudukai:/data/testmymount# unshare -p /bin/bash
bash: fork: Cannot allocate memory # 直接运行 unshare --pid /bin/bash,内核会尝试让当前的 unshare 进程进入新空间,这违反了内核规则,通常会导致报错:Cannot allocate memory(无法分配内存)
root@yudukai:/data/testmymount# exit
exit
root@yudukai:/data/testmymount# unshare -p --fork /bin/bash
root@yudukai:/data/testmymount#

主机B

shell 复制代码
ps -ef

主机A

shell 复制代码
ps -ef

然后主机A

shell 复制代码
root@yudukai:/data/testmymount# exit
exit
root@yudukai:/data/testmymount# unshare -p --fork --mount-proc /bin/bash

如果你只是开启了 PID Namespace 而不处理 /proc,新创建的子进程依然会沿用宿主机的 /proc 挂载点。这意味着,虽然你的进程在内核里确实被隔离了,但 ps 工具由于读取的是旧的"窗口",依然会把宿主机的进程全部显示出来。

--mount-proc 这个参数会在进入新 Namespace 的同时,自动为我们重新挂载一个只属于当前 Namespace/proc 文件系统。这样,ps 就只能看到当前空间内的进程了。

使用 --mount-proc 时,内核并不是创建了一个新的文件夹,而是为当前 PID Namespace 提供了一个定制化的接口 。这个接口会过滤掉不属于该 Namespace 的所有进程信息。

执行后,主机A:

shell 复制代码
root@yudukai:/data/testmymount# ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 19:17 pts/0    00:00:00 /bin/bash
root           9       1  0 19:17 pts/0    00:00:00 ps -ef
root@yudukai:/data/testmymount# 

主机B:

一堆进程


3. Mount 隔离与文件系统视图

设备A

shell 复制代码
root@yudukai:/data/testmymount# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1       177G   25G  145G  15% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           795M   78M  718M  10% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           795M     0  795M   0% /run/user/0
/dev/loop0      3.5M   28K  3.0M   1% /data/testmymount
root@yudukai:/data/testmymount# exit
exit
root@yudukai:/data/testmymount# 
root@yudukai:/data/testmymount# unshare --fork --mount /bin/bash
root@yudukai:/data/testmymount# ll -h
total 28K
drwxr-xr-x 3 root root 4.0K Jul 29 18:43 ./
drwxr-xr-x 3 root root 4.0K Jul 29 18:42 ../
drwx------ 2 root root  16K Jul 29 18:42 lost+found/
-rw-r--r-- 1 root root    4 Jul 29 18:44 test.txt
root@yudukai:/data/testmymount# dd if=/dev/zero of=data2.img bs=8k count=10240
dd: error writing 'data2.img': No space left on device
423+0 records in
422+0 records out
3457024 bytes (3.5 MB, 3.3 MiB) copied, 0.00879398 s, 393 MB/s
root@yudukai:/data/testmymount# ls -l
total 3400
-rw-r--r-- 1 root root 3457024 Jul 29 19:22 data2.img
drwx------ 2 root root   16384 Jul 29 18:42 lost+found
-rw-r--r-- 1 root root       4 Jul 29 18:44 test.txt
root@yudukai:/data/testmymount# mkfs -t ext4 ./data2.img
mke2fs 1.46.5 (30-Dec-2021)

Filesystem too small for a journal
Discarding device blocks: done                            
Creating filesystem with 844 4k blocks and 848 inodes

Allocating group tables: done                            
Writing inode tables: done                            
Writing superblocks and filesystem accounting information: done

root@yudukai:/data/testmymount# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1       177G   25G  145G  15% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           795M   78M  718M  10% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           795M     0  795M   0% /run/user/0
/dev/loop0      3.5M  188K  2.8M   7% /data/testmymount
root@yudukai:/data/testmymount# mkdir -p /data/maxhou/data2mount
root@yudukai:/data/testmymount# ll
total 188
drwxr-xr-x 3 root root    4096 Jul 29 19:22 ./
drwxr-xr-x 4 root root    4096 Jul 29 19:24 ../
-rw-r--r-- 1 root root 3457024 Jul 29 19:23 data2.img
drwx------ 2 root root   16384 Jul 29 18:42 lost+found/
-rw-r--r-- 1 root root       4 Jul 29 18:44 test.txt
root@yudukai:/data/testmymount# ll /data/maxhou/data2mount
total 8
drwxr-xr-x 2 root root 4096 Jul 29 19:24 ./
drwxr-xr-x 3 root root 4096 Jul 29 19:24 ../
root@yudukai:/data/testmymount# mount -t ext4 ./data2.img /data/maxhou/data2mount
root@yudukai:/data/testmymount# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1       177G   25G  145G  15% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           795M   78M  718M  10% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           795M     0  795M   0% /run/user/0
/dev/loop0      3.5M  188K  2.8M   7% /data/testmymount
/dev/loop1      3.1M   24K  2.9M   1% /data/maxhou/data2mount
root@yudukai:/data/testmymount# cd /data/maxhou/data2mount/
root@yudukai:/data/maxhou/data2mount# echo "hello test"> test.txt
root@yudukai:/data/maxhou/data2mount# ll
total 28
drwxr-xr-x 3 root root  4096 Jul 29 19:27 ./
drwxr-xr-x 3 root root  4096 Jul 29 19:24 ../
drwx------ 2 root root 16384 Jul 29 19:23 lost+found/
-rw-r--r-- 1 root root    11 Jul 29 19:27 test.txt
root@yudukai:/data/maxhou/data2mount# cat test.txt
hello test
root@yudukai:/data/maxhou/data2mount# 

设备B

shell 复制代码
root@yudukai:/data/testmymount# df -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           795M   78M  718M  10% /run
/dev/vda1       177G   25G  145G  15% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           795M     0  795M   0% /run/user/0
/dev/loop0      3.5M  188K  2.8M   7% /data/testmymount
root@yudukai:/data/testmymount# ll /data/maxhou/data2mount/test.txt
ls: cannot access '/data/maxhou/data2mount/test.txt': No such file or directory
root@yudukai:/data/testmymount# 

执行 unshare --fork --mount /bin/bash 时,内核为设备 A 复制了一份当前的挂载点信息,但此后设备 A 的任何挂载操作都是私有的。

  • 设备 A 的视角: 你执行了 mount -t ext4 ./data2.img /data/maxhou/data2mount。内核将这个新的挂载信息记录在了设备 A 的私有挂载表中。因此,执行 df -h 时,你能看到 /dev/loop1 成功挂载。
  • 设备 B 的视角: 宿主机的挂载表没有任何变化。在它的认知里,/data/maxhou/data2mount 仅仅是一个普通目录。
  • 在设备 A 中: 执行 echo "hello test" > test.txt。这个文件实际上被写进了 data2.img 这个文件系统镜像里。
  • 在设备 B 中: 执行 ll /data/maxhou/data2mount/test.txt。系统返回 No such file or directory

结论: 虽然大家都在访问 /data/maxhou/data2mount/,但设备 A 访问的是镜像挂载后的内容 ,而设备 B 访问的是底层文件系统的空目录
为什么容器需要 Mount 隔离?

通过 Mount Namespace,容器可以拥有自己独立的 / 目录(根文件系统)。容器启动时:

  1. 开启 Mount Namespace
  2. 使用 pivot_rootchroot 将私有挂载点切换为根目录。
  3. 这样,容器里的进程就只能看到镜像里的 /bin, /etc,而完全感知不到宿主机的存在。

4. 思维导图

相关推荐
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题 第207题】【09_Zookeeper篇】第8题:谈谈 ZooKeeper 的可靠性保障机制
java·zookeeper·高可用·可靠性·分布式系统
harmful_sheep1 小时前
maven多版本包导致java.lang.NoClassDefFoundError
java·maven
Mark_ZP1 小时前
【锁2】锁的分类与概念
java·
caishenzhibiao1 小时前
顺势捕猎者副图 同花顺期货通指标
java·c语言·c#
有续技术2 小时前
哈斯 (Haas) 机床 IP、端口号配置内容总结
运维·服务器
小张同学a.2 小时前
LAMP架构2
linux·运维·网络·架构·负载均衡
千河殇 多想和她2 小时前
如何在Reaonix中使用CodeGraph以及CodeGraph效果实测经验分享
linux·运维·ubuntu
VortMall2 小时前
出海引流运维双升级|VortMall微服务商城系统v1.3.12 升级更新
运维·微服务·facebook
心念枕惊2 小时前
新写了个直播录制工具,可录制抖音快手斗鱼直播
运维·服务器·数据库