【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:指定要建立何种文件系统;如 ext3,ext4
  • filesys :指定要创建的文件系统对应的设备文件名;
  • blocks:指定文件系统的磁盘块数。
  • -V : 详细显示模式
  • fs-options:传递给具体的文件系统的参数

1.2.1 为什么要格式化?

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

在 Namespace 隔离实战中,只有经过格式化的镜像,才能被 mount 命令识别并挂载到文件系统中,作为一个独立的"小世界"存在。
mkfs 实际上是一系列命令的通用前端。当你执行格式化时,它会根据你指定的类型调用对应的程序(如 mkfs.ext4 或 mkfs.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。这也是为什么每个容器都可以有一个 PID 为 1 的 init 进程,而互不干扰。
--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_root 或 chroot 将私有挂载点切换为根目录。
  3. 这样,容器里的进程就只能看到镜像里的 /bin, /etc,而完全感知不到宿主机的存在。

4. 思维导图

相关推荐
xcl092515 小时前
北京24小时自助健身房系统软件开发实战:从架构到部署全流程指南
java·spring boot·架构
wtblszn17 小时前
自动化包装生产线设备可视化管理方案
运维·自动化
一 乐17 小时前
动漫书销售商城|基于springboot + vue动漫书销售商城(源码+数据库+文档)
java·数据库·vue.js·spring boot·毕业设计
卓怡学长17 小时前
w214基于jsp知道特产网
java·intellij-idea
步行cgn17 小时前
Spring 注解使用详解
java·spring
一条小小yu17 小时前
Spring IoC的理解
java·后端·spring
落魄实习生18 小时前
Agent Scope Java 2.x 系列【7】工具使用
java·开发语言·ai
心之语歌18 小时前
Tkinter 画布基本梳理
运维·服务器·python
旺仔学长 哈哈18 小时前
springboot钓鱼爱好者交流平台APP设计与实现
java·spring boot·mysql·充电桩管理系统
Shulex18 小时前
面向跨境电商多渠道消息系统的技术架构:亚马逊站内信合规对接与自动化执行链路设计
运维·架构·自动化