NameSpace 隔离实战
一、实战目的
了解隔离能力并不是 docker 提供的,而是操作系统内核提供基本能力
二、基础知识
1.dd 命令详解
Linux dd 命令用于读取、转换并输出数据。
dd 可从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件、设备或标准输出。
dd option
参数 | 说明 |
---|---|
if = 文件名 | 输入文件名,默认为标准输入,指定源文件 |
of = 文件名 | 输出文件名,默认为标准输出,指定目的文件 |
ibs=bytes | 一次读入 bytes 个字节,指定读入块大小 |
obs=bytes | 一次输出 bytes 个字节,指定输出块大小 |
bs=bytes | 同时设置读入 / 输出的块大小为 bytes 个字节 |
cbs=bytes | 一次转换 bytes 个字节,指定转换缓冲区大小 |
skip=blocks | 从输入文件开头跳过 blocks 个块后开始复制 |
seek=blocks | 从输出文件开头跳过 blocks 个块后开始复制 |
count=blocks | 仅拷贝 blocks 个块,块大小等于 ibs 指定的字节数 |
conv=<关键字> | conversion:用指定的参数转换文件。 ascii:转换 ebcdic 为 ascii。 ebcdic:转换 ascii 为 ebcdic。 ibm:转换 ascii 为 alternate ebcdic。 block:把每一行转换为长度为 cbs,不足部分用空格填充。 unblock:使每一行的长度都为 cbs,不足部分用空格填充。 lcase:把大写字符转换为小写字符。 ucase:把小写字符转换为大写字符。 swap:交换输入的每对字节。 noerror:出错时不停止。 notrunc:不截短输出文件。 sync:将每个输入块填充到 ibs 个字节,不足部分用空(NUL)字符补齐。 |
–help | 显示帮助信息 |
–version | 显示版本信息 |
生成test.img 和 test2.img两个镜像文件:
将 in.txt 文件中的所有英文字母转换为大写,然后转成为 out.txt 文件:
【疑问1】.img是什么
.img而是一种通用的文件扩展名,在不同场景下含义不同:
- 系统镜像文件:在操作系统领域,
.img
文件常用于存储磁盘或光盘的镜像,包含了完整的磁盘或光盘数据。比如在安装系统时,下载的系统镜像可能是.img
格式,像一些嵌入式系统的镜像文件也常是这种格式,可用于系统的烧录和恢复。 - 虚拟磁盘文件:在虚拟机软件中,
.img
文件可作为虚拟磁盘使用,用来模拟物理磁盘的功能,存储数据和操作系统,就像真实的硬盘一样被虚拟机识别和读写。 - 图像文件:虽然相对少见,但部分软件也会将
.img
作为图像文件的扩展名,用于存储图片数据
【疑问2】/dev/zero是什么?
在类 UNIX 操作系统(如 Linux、FreeBSD 等)中,/dev/zero
是一个特殊的虚拟字符设备文件,有以下特点和用途:
- 提供零字节数据流:当从
/dev/zero
读取数据时,它会源源不断地输出值为 0 的字节 (空字符,ASCII NUL,即 0x00),可生成无限数量的零数据。 - 初始化数据存储:常用于快速清空或填充新创建的磁盘分区、文件等数据存储。比如使用
dd if=/dev/zero of=/dev/sdb bs=1m
命令,能从/dev/zero
读取数据块并写入到/dev/sdb
对应的存储设备中,完成初始化。 - 覆盖敏感信息:处理敏感数据时,可利用
/dev/zero
输出的零字节流覆盖原文件内容,以防止数据恢复。但对于高安全标准的数据擦除,这种方式可能不足,需要使用更专业的工具和方法。 - 模拟大容量数据:在调试大数据应用程序或验证存储解决方案时,可借助它生成指定大小的 “占位” 数据。例如通过
dd if=/dev/zero of=/mnt/bigdata/bigfile bs=1m count=5120
命令,能创建一个 5GB 的虚拟数据集,便于在无需真实大量数据的情况下,对相关应用进行调试和优化。 - 内存相关操作:在 BSD 系统中,可通过
mmap
把/dev/zero
映射到虚拟地址空间,实现共享内存,也相当于使用一段匿名内存(未关联任何文件)。
/dev/zero
和 /dev/null
都是类 UNIX 系统中的特殊文件,但二者有所区别。/dev/null
被称为空设备,像一个 “黑洞”,写入其中的数据会被丢弃,读取它会立即得到文件结束符(EOF),常被用于丢弃不需要的输出流 ,或作为输入流的空文件;而 /dev/zero
可以作为数据来源,输出零字节数据流。
2.mkfs命令详解
mkfs
是类 UNIX 系统(如 Linux、FreeBSD 等)中的一个命令,用于在设备(如硬盘分区、U 盘等)或文件上创建文件系统,其名称是 “make file system”(创建文件系统)的缩写。主要功能和特点如下:
- 创建不同类型文件系统:能创建多种文件系统,像常见的
ext4
(Linux 系统广泛使用的日志式文件系统)、xfs
(高性能、可扩展,适用于大型存储系统)、fat32
(兼容性好,常用于移动存储设备)、ntfs
(Windows 系统常用文件系统,在 Linux 中也能通过特定驱动支持创建)等。 - 格式化设备:在创建文件系统前,会先对存储设备进行格式化操作,清除原有数据,并初始化文件系统结构,包括创建根目录、分配 inode(索引节点,存储文件元数据)等。
- 指定参数:可搭配不同参数来调整文件系统创建的方式和特性,如
mkfs.ext4 -b 4096 /dev/sdb1
中,-b 4096
表示设置块大小为 4096 字节,/dev/sdb1
是目标设备分区。
在使用 mkfs
命令时需谨慎,因为操作会清除目标设备上的原有数据 。
mkfs [-V] [-t fstype] [fs-options] filesys [blocks]
参数:
- -t fstype:指定要建立何种文件系统,如 ext3,ext4。
- filesys:指定要创建的文件系统对应的设备文件名。
- blocks:指定文件系统的磁盘块数。
- -V:详细显示模式。
- fs-options:传递给具体的文件系统的参数。
将 test.img 分区格式化为 ext4 格式:
【疑问1】ext3 ext4是什么文件系统?
ext3
基本介绍:ext3 是第三代扩展文件系统(The Third Extended Filesystem)的缩写,是 ext2 文件系统的升级版本,它在 ext2 的基础上加入了日志功能,以提高文件系统的可靠性和数据恢复能力。
特点
- 日志功能:ext3 会将文件系统的更改记录在日志中,这样在系统崩溃或意外断电等情况下,可以通过日志快速恢复文件系统的一致性,减少文件系统检查和修复的时间。
- 向后兼容性:它与 ext2 文件系统具有很好的向后兼容性,可以轻松地将 ext2 文件系统升级到 ext3,而无需重新格式化磁盘。
- 数据完整性:通过日志记录,能够确保数据的完整性,即使在系统出现故障时,也能保证文件系统处于一个一致的状态,避免数据丢失或损坏。
ext4
基本介绍:ext4 是第四代扩展文件系统,是 ext3 文件系统的后继者,它在 ext3 的基础上进行了多项改进和优化,以提供更好的性能、更大的容量支持和更灵活的功能。
特点
- 更大的文件和分区支持:ext4 支持更大的文件和分区大小,理论上支持的最大文件大小为 16TB,最大分区大小为 1EB(1024PB),这使得它能够更好地适应现代大容量存储设备的需求。
- 更快的文件系统检查:ext4 采用了更高效的文件系统检查算法,能够更快地完成文件系统的检查和修复工作,特别是在大型文件系统上,这种优势更加明显。
- 延迟分配:ext4 支持延迟分配策略,它会在文件写入时暂时不分配磁盘空间,而是等到文件写入完成后再一次性分配,这样可以更有效地利用磁盘空间,减少磁盘碎片的产生。
- 多块分配:在分配磁盘空间时,ext4 可以一次性分配多个连续的磁盘块,而不是像 ext3 那样每次只分配一个块,这大大提高了文件写入的性能,尤其是对于大文件的写入。
- 日志校验:ext4 对日志进行了校验,以确保日志的完整性和正确性,进一步提高了文件系统的可靠性。
【疑问2】我们日常用的电脑是什么文件系统?
日常使用的电脑根据操作系统的不同,通常会采用不同的文件系统,以下是一些常见的情况:
Windows 系统
- NTFS(New Technology File System):是 Windows 系统主流的文件系统。它支持文件加密、磁盘配额、文件权限管理等功能,能很好地保证系统安全和文件管理效率,还支持大文件和大容量存储设备,目前大多数 Windows 电脑默认使用 NTFS 文件系统。
- FAT32(File Allocation Table 32):兼容性强,被多种操作系统支持,可用于移动存储设备。但它单个文件最大只能支持 4GB,不支持文件权限管理等高级功能,如今在 Windows 电脑的本地磁盘中使用较少,主要用于一些对兼容性要求较高的特殊场景或旧设备。
- exFAT(Extended File Allocation Table):是 FAT32 的升级版,主要用于闪存设备,如 U 盘、存储卡等。它支持更大的文件和分区,单个文件大小可达 16EB,同时支持文件系统日志记录,提高了可靠性和兼容性,在 Windows 和 macOS 系统中都能很好地被识别和使用。
macOS 系统
- APFS(Apple File System):是苹果公司为 macOS 和 iOS 系统开发的文件系统。它具有强大的加密功能、快照功能(可方便地进行系统备份和恢复)、空间共享(能更高效地利用磁盘空间)等特性,还支持对固态硬盘(SSD)的优化,能延长 SSD 的使用寿命,提升系统性能。从 macOS High Sierra 开始,APFS 成为了 Mac 电脑的默认文件系统。
- HFS+(Hierarchical File System Plus):也叫 Mac OS 扩展(日志式),是 APFS 之前 macOS 系统使用的主流文件系统。它支持长文件名、文件权限管理和日志功能等,能保证系统的稳定性和数据的安全性。虽然现在新的 Mac 电脑默认使用 APFS,但在一些旧版本的 macOS 系统或特定情况下,仍可能会使用 HFS+。
Linux 系统
- ext4(Fourth Extended Filesystem):如前面所述,它是 Linux 系统中非常常用的文件系统,具有良好的性能和稳定性,支持大文件和大容量分区,适用于各种类型的 Linux 服务器和桌面系统。
- XFS:这是一种高性能的日志式文件系统,具有优秀的可扩展性和读写性能,特别适合处理大型文件和高并发的 I/O 操作,常用于 Linux 服务器环境,尤其是需要处理大量数据的数据库服务器等。
- Btrfs(B-tree File System):它是一种新兴的 Linux 文件系统,具有许多先进的特性,如支持快照、克隆、数据压缩、RAID 功能等,被设计用于提供更好的数据管理和容错能力,逐渐受到更多用户的关注和使用,但目前尚未成为 Linux 系统的默认文件系统。
此外,日常电脑使用的文件系统还可能根据用户的特殊需求或使用场景进行定制或安装其他文件系统。
3.df命令
df
是 Linux 和类 Unix 系统中的一个命令,用于查看文件系统的磁盘使用情况
df [OPTION]... [FILE]...
常见参数:
-a,–all:显示所有文件系统,包括系统特殊文件系统,如 /proc
、/sys
等,这些文件系统通常不占用实际的磁盘空间,但在系统运行中起着重要作用
-h,–human-readable:使用人类可读的格式(预设值是不加这个选项的…)将容量单位转换为 KB、MB、GB 等,使输出结果更易于理解。
-H,–si:很像 -h,但是用 1000 为单位而不是用 1024。
-t,–type=TYPE:限制列出文件系统的 TYPE。
-T,–print-type:显示文件系统的类型,在输出结果中增加一列用于显示文件系统的格式,如 ext4
、xfs
、ntfs
等
-i:显示文件系统的 inode 使用情况,而不是磁盘块使用情况。inode 是存储文件元数据的结构,通过这个参数可以了解文件系统中 inode 的分配和使用情况,对于排查文件系统中 inode 耗尽等问题很有帮助。
查看磁盘使用情况:
查看特定文件系统类型(如 ext4
)的磁盘使用情况:
查看磁盘的系统类型:
4.mount命令
mount
命令是在 Linux 和类 Unix 系统中用于挂载文件系统的命令,它允许将存储设备(如硬盘分区、光盘、U 盘等)或远程文件系统连接到系统的目录树中,使得这些文件系统能够被系统访问和使用
mount [选项] [设备] [挂载点]
- -t <文件系统类型>:指定要挂载的文件系统类型,如
ext4
ntfs
iso9660
(用于光盘)等。如果不指定,系统会自动检测文件系统类型。 - -o <选项列表>:用于指定挂载文件系统时的一些额外选项,多个选项之间用逗号分隔。常见的选项有:
ro
:以只读方式挂载文件系统。rw
:以读写方式挂载文件系统,这是默认选项。loop
:用来把一个文件当成硬盘分区挂接上系统user
:允许普通用户挂载文件系统。noexec
:禁止在该文件系统上执行可执行文件。nosuid
:禁止文件系统上的 SUID 和 SGID 位生效,增强系统安全性。
- -a:根据
/etc/fstab
文件中的配置信息,挂载所有支持自动挂载的文件系统。
将 /test.img 挂在 ~/testmymount 之下:
【疑问】为什么这里面使用 sudo bash -c 'echo "123" > test.txt'
?
小编一开始使用sudo echo “123” > test.txt,仍然出现权限不允许的情况,原来我使用sudo只是提升了echo的权限,并没有提升 > 的权限
命令失败的原因是当前目录的权限不允许普通用户 wuxu
写入文件,而 sudo echo
只提升了 echo
部分的权限,未提升重定向操作的权限。推荐的解决方法是使用 sudo bash -c
或切换到 root
用户执行命令。如果需要长期解决,可以调整目录的权限或所有者
5.unshare命令详解
unshare
是 Linux 中的一个命令,用于创建新的命名空间(namespace),并将当前进程或子进程放入这些命名空间中运行。命名空间是 Linux 内核提供的一种隔离机制,允许不同的进程拥有独立的系统资源视图(如文件系统、网络、进程 ID 等)。通过 unshare
,用户可以在不启动新容器的情况下,手动创建和管理命名空间。
命名空间类型
Linux 支持以下几种命名空间:
命名空间类型 | 选项 | 隔离内容 |
---|---|---|
Mount Namespace | --mount 或 -m |
文件系统的挂载点,每个命名空间有独立的挂载表 |
UTS Namespace | --uts |
主机名和域名(hostname 和domainname ) |
IPC Namespace | --ipc |
进程间通信(如消息队列、共享内存等) |
PID Namespace | --pid |
进程 ID,每个命名空间有独立的 PID 空间,通常从 1 开始编号 |
Network Namespace | --net |
网络设备、IP 地址、路由表等 |
User Namespace | --user |
用户和组 ID,允许在命名空间内映射用户权限 |
Cgroup Namespace | --cgroup |
控制组(cgroups)的视图 |
unshare
命令的基本用法
unshare [选项] [程序]
[选项]
:指定要创建的命名空间类型。[程序]
:在新命名空间中运行的命令或程序。
如果不指定 [程序]
,unshare
会启动一个交互式 shell。
常用选项
选项 | 描述 |
---|---|
--mount 或 -m |
创建一个新的 Mount Namespace。 |
--uts -u |
创建一个新的 UTS Namespace,允许修改主机名和域名。 |
--ipc -i |
创建一个新的 IPC Namespace。 |
--pid -p |
创建一个新的 PID Namespace。 |
--net -n |
创建一个新的 Network Namespace。 |
--user -U |
创建一个新的 User Namespace。 |
--fork |
在新命名空间中运行子进程,而不是直接进入命名空间。 |
--map-root-user |
将当前用户映射为命名空间中的 root 用户(仅适用于 User Namespace)。 |
验证 UTS 命名空间的隔离效果,并设置一个新的主机名
三、实战操作一(PID隔离)
PID(Process ID)隔离是 Linux 容器技术中的一个重要特性。通过 PID 命名空间的隔离,可以让不同的进程在各自的命名空间中拥有独立的进程 ID 空间。这意味着在一个命名空间中运行的进程不会看到其他命名空间中的进程,从而实现资源隔离
1. 使用 unshare
创建新的 PID 命名空间
unshare
是一个用于创建新命名空间的工具。我们可以通过它创建一个新的 PID 命名空间,并观察隔离效果。
sudo unshare --pid --fork --mount-proc /bin/bash
--pid
:创建一个新的 PID 命名空间。--fork
:确保新命名空间中的进程与父进程完全隔离。--mount-proc
:挂载一个新的/proc
文件系统,以便新命名空间中的进程能够正确查看其 PID 信息。/bin/bash
:启动一个新的 shell。
执行上述命令后,将进入一个新的 shell,该 shell 运行在独立的 PID 命名空间中。
2. 查看当前命名空间中的进程
在新的 PID 命名空间中,运行以下命令查看进程列表:
ps aux
输出分析:
- 会发现,在新的 PID 命名空间中,只有少量进程可见(通常是
bash
和ps
本身)。 - 这是因为新的 PID 命名空间与宿主机的进程空间完全隔离,无法看到宿主机上的其他进程。
3. 验证 PID 隔离
在新命名空间中查看 PID 1:
echo $$
$
是当前 shell 的 PID。- 在新的 PID 命名空间中,这个值通常是
1
,因为它是该命名空间中的第一个进程。
在宿主机上验证:
切换到宿主机(例如打开另一个终端),运行以下命令查看实际的 PID:
ps -ef | grep bash
- 会发现,虽然在新命名空间中该进程的 PID 是
1
,但在宿主机上它的实际 PID 是一个更大的数字。 - 这表明新命名空间中的 PID 与宿主机的 PID 是隔离的。
4. 启动子进程并观察
在新命名空间中启动一些子进程
sleep 1000 &
然后再次运行 ps aux
,会看到这些进程出现在新的 PID 命名空间中,但它们对宿主机是不可见的。
5. 退出命名空间
当完成实验后,可以输入 exit
退出新命名空间的 shell。此时,所有在该命名空间中启动的进程都会被终止。
6. 使用 nsenter
进入已有的命名空间
如果您希望进入一个已经存在的命名空间(例如由 Docker 或其他工具创建的命名空间),可以使用 nsenter
工具。
示例:
假设某个容器的 PID 是 12345
,您可以使用以下命令进入其 PID 命名空间:
sudo nsenter --target 12345 --pid --mount /bin/bash
这将让您进入该容器的 PID 命名空间,并查看其内部的进程。
7.总结
通过以上实验,您可以验证 PID 命名空间的隔离效果:
- 新的 PID 命名空间中的进程与宿主机的进程完全隔离。
- 在新的命名空间中,PID 从
1
开始重新编号。 - 宿主机上的进程无法看到新命名空间中的进程,反之亦然。
这种隔离机制是容器技术(如 Docker)的基础之一,用于实现进程级别的资源隔离和安全性。
四、实战操作二:Mount 隔离
Mount 命名空间是 Linux 容器技术中的另一个重要特性。通过 Mount 命名空间的隔离,可以让不同的进程在各自的命名空间中拥有独立的文件系统挂载点视图。这意味着在一个命名空间中挂载或卸载文件系统不会影响其他命名空间或宿主机。
1. 使用 unshare
创建新的 Mount 命名空间
unshare
是一个用于创建新命名空间的工具。我们可以通过它创建一个新的 Mount 命名空间,并观察隔离效果。
sudo unshare --mount /bin/bash
--mount
:创建一个新的 Mount 命名空间。/bin/bash
:启动一个新的 shell。
效果:
执行上述命令后,您将进入一个新的 shell,该 shell 运行在独立的 Mount 命名空间中
2. 查看当前的挂载点
在新的 Mount 命名空间中,运行以下命令查看当前的挂载点:
mount | grep "on / "
输出分析:
- 您会发现,在新的 Mount 命名空间中,挂载点列表与宿主机的挂载点列表相同。
- 这是因为新的 Mount 命名空间默认继承了宿主机的挂载点。
3. 在新的 Mount 命名空间中挂载文件系统
示例:挂载一个临时文件系统(tmpfs)
在新的 Mount 命名空间中运行以下命令,挂载一个 tmpfs 文件系统到 /mnt
目录:
mkdir -p /mnt
mount -t tmpfs tmpfs /mnt
-t tmpfs
:指定挂载类型为 tmpfs(一种基于内存的临时文件系统)。/mnt
:挂载点目录。
验证挂载:
运行以下命令查看挂载点:
mount | grep /mnt
输出应显示类似以下内容:
tmpfs on /mnt type tmpfs (rw,relatime)
这表明 /mnt
已成功挂载为 tmpfs 文件系统。
4. 在宿主机上验证挂载点
切换到宿主机(例如打开另一个终端),运行以下命令查看宿主机上的挂载点:
mount | grep /mnt
输出分析:
- 您会发现,宿主机上没有任何关于
/mnt
的挂载信息。 - 这表明,新的 Mount 命名空间中的挂载操作对宿主机是不可见的。
5. 在新的 Mount 命名空间中卸载文件系统
在新的 Mount 命名空间中运行以下命令,卸载 /mnt
:
umount /mnt
验证卸载:
再次运行以下命令查看挂载点
mount | grep /mnt
输出应为空,表明 /mnt
已成功卸载。
6. 退出 Mount 命名空间
当完成实验后,可以输入 exit
退出新 Mount 命名空间的 shell。此时,所有在该命名空间中进行的挂载操作都会被撤销。
7. 使用 nsenter
进入已有的 Mount 命名空间
如果您希望进入一个已经存在的 Mount 命名空间(例如由 Docker 或其他工具创建的命名空间),可以使用 nsenter
工具。
示例:
假设某个容器的 PID 是 12345
,您可以使用以下命令进入其 Mount 命名空间:
sudo nsenter --target 12345 --mount /bin/bash
这将让您进入该容器的 Mount 命名空间,并查看其内部的挂载点。
8.总结
通过以上实验,可以验证 Mount 命名空间的隔离效果:
- 新的 Mount 命名空间中的挂载操作与宿主机完全隔离。
- 在新的 Mount 命名空间中挂载或卸载文件系统不会影响宿主机或其他命名空间。
- 宿主机无法看到新 Mount 命名空间中的挂载点。
这种隔离机制是容器技术(如 Docker)的基础之一,用于实现文件系统级别的资源隔离和安全性。