namespace及相关命令

发布于:2025-04-05 ⋅ 阅读:(9) ⋅ 点赞:(0)

namespace及相关命令

1. namspace

1.1 namespace介绍

namespace 是 Linux 的一种用于实现进程隔离的机制,是 Linux 内核容器化技术(如 Docker 和 Kubernetes)的核心组件之一。它允许系统将资源划分为彼此隔离的单元,通过 namespace 可以让一些进程只看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,使得不同的进程组可以独立操作这些资源,而互不干扰

namespace 是对全局系统资源的一种封装机制,处于不同 namespace 的进程拥有独立的全局系统资源,且改变一个 namespace 中的系统资源只会影响当前 namespace 里的进程,对其他 namespace 中的进程没有影响。

1.2 namespace属性

namespace 中有许多进程和系统相关的属性,Linux 也提供了一些 API 来操作操作 namespace:

属性 系统调用参数 被隔离的全局系统资源 引入内核版本
UTS CLONE_NEWUTS 主机名和域名 2.6.19
IPC CLONE_NEWIPC 信号量、消息队列和共享内存 2.6.19
PID CLONE_NEWPID 进程编号 2.6.24
Network CLONE_NEWNET 网络设备、网络栈、端口等 2.6.29
Mount CLONE_NEWNS 文件系统挂载点 2.4.19
User CLONE_NEWUSER 用户和用户组 3.8

UTS: 每个容器都能看到自己的 hostname ,拥有独立的主机名和域名。

IPC: 同一个 IPC 的 namespace 的进程之间可以互相通信,不同的 IPC namespace 之间不能通信。

PID: 每个 PID 的 namespace 中的进程可以有独立的 PID ,每个容器可以有 PID 为 1 的 root 进程。

Network: 每个容器有独立的网络设备、IP 地址、IP 路由表、/proc/net 目录、端口号。

mount: 每个容器可以看到不同的文件系统层次结构。

User: 每个容器可以有不同的 user 和 group id。

2. 常用命令

注意,namespace 的隔离能力不是由 docker 提供的,而是 Linux 操作系统内核提供的基本能力。

2.1 dd命令

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

dd [option]

选项:

选项 含义
if=filename 源文件的文件名,即输入的文件。(默认 stdin)
of=filename 目的文件的文件名,即输出的文件。(默认 stdout)
ibs=bytes 一次读取 bytes \text{bytes} bytes 个字节,即指定一个块,大小为 bytes \text{bytes} bytes 个字节。
obs=bytes 一次输出 bytes \text{bytes} bytes 个字节,即指定一个块,大小为 bytes \text{bytes} bytes 个字节。
bs=bytes 同时设置读入/输出的块大小为 bytes \text{bytes} bytes 个字节。
cbs=bytes 一次转换 bytes \text{bytes} bytes 个字节,即指定转换缓冲区大小。
skip=blocks 从输入文件开头跳过 blocks \text{blocks} blocks 个块后再开始复制。
seek=blocks 从输出文件开头跳过 blocks \text{blocks} blocks 个块后再开始复制。
count=blocks 仅拷贝 blocks \text{blocks} blocks 个块,块大小等于 ibs 指定的字节数。
–help 显示帮助信息。
–version 显示版本信息。
conv=[关键字] 这个选项用于转换数据内容,详细看下表。

conv 关键字:

关键字 含义 关键字 含义
conversion 用指定的参数转换文件。 lcase 把大写字符转换为小写字符。
ascii 将 ebcdic 转换为 ascii。 ucase 把小写字符转换为大写字符。
ebcdic 将 ascii 转换为 ebcdic。 swap 交换输入的每对字节。
ibm 将 ascii 转换为 alternate ebcdic。 noerror 出错时不停止。
block 将输入的 \n 转换为固定长度的空格填充记录。 notrunc 不截断输出文件,即写入新信息不清空原内容(但新内容仍会从偏移量开始向后覆盖)。
unblock 将输入的固定长度记录转换为 \n 结尾的记录。 sync 将每个输入块填充到 ibs 个字节,不足的部分用空(NUL)字符填充。

block 和 unblock 用于控制文件每行的显示,只是方法不同。假如指定每行内容为 80 80 80 字节(cbs=80)。block 表示每行内容被调整为 80 80 80 字节宽,不足的部分用空格填充;unblock 表示删除 block 设置的空格,并在每 80 80 80 字节长度的记录尾部添加换行符(\n),转换为普通文本。

使用:

创建一个镜像文件。

dd if=/dev/zero of=test.img bs=8k count=10240

/dev/zero 是一个特殊设备文件,提供源源不断的零值字节。

这段命令的意思是,拷贝无限制的 0 到 test.img 文件中,每个块大小 8   K B 8\,\rm KB 8KB,共 10240 10240 10240 个块,文件总大小为 8   K B × 1024 = 80   M B 8\,\rm KB \times{1024}=80\,\rm MB 8KB×1024=80MB

namespace1

2.2 mkfs命令

mkfs 用于在设备上创建 Linux 文件系统,即格式化。

mkfs [option] filesys [blocks]

选项:

选项 含义
-t fstype 指定要建立何种文件系统,如 ext3,ext4 。
filesys 指定要创建的文件系统对应的设备文件名。
blocks 指定文件系统的磁盘块数。
-V 详细显示模式。
fs-option 传递给具体的文件系统的参数。

使用:

将镜像文件 test.img 格式化为 ext4 文件系统。

mkfs -t ext4 ./test.img

namespace2

2.3 df命令

df 用于显示在 Linux 系统上的文件系统磁盘使用情况。

df [option] [file]

选项:

选项 含义
-a,-all 显示所有文件系统,包括 0 Blocks 的。
-h,–human-readable 使用人类可读的格式,即把单位都换算成 KB、MB 等。
-H,–si 与 -h 类似,但进制为 1000 而不是 1024。
-t,–type=TYPE 限制列出文件系统的 TYPE。
-T,–print-type 显示文件系统的形式。

2.4 mount命令

mount 用于加载文件系统到指定的加载点。挂载的实质就是为磁盘添加入口(挂载点)。Linux 系统下不同目录可以挂载不同分区和磁盘设备,它的目录和磁盘分区是分离的,可以自由组合,不同的目录数据可以跨越不同的磁盘分区或者不同的磁盘设备。

此命令也常用于挂载光盘(U 盘),使我们可以访问光盘中的数据。因为在 Linux 中,将光盘插入光驱后,系统不会自动挂载,必须使用 mount 命令手动完成挂载。

#常见用法
mount -l
mount [-o option] [device] dir

选项:

选项 含义
-l 显示已经加载的文件系统列表。
-t 加载文件系统类型,支持常见系统类型如 ext3、ext4、ios9660、tmpfs、xfs 等。大部分情况下不需要指定,mount 可以自己识别。
-o option 主要用于描述设备或档案的挂载方式,选项看下表。
device 要挂载(mount)的设备。
dir 挂载点的目录。

-o选项:

选项 含义
loop 用于把一个文件当成磁盘分区挂接上系统。
ro 采用只读方式挂接设备。
rw 采用读写方式挂接设备。

使用:

mount ./test.img ./mnt/testext4

如果挂载点不存在(即目录不存在)会报错:

namespace3

2.5 unshare命令

unshare 主要用于使用与父进程不共享的 namespace 运行程序。

unshare [option] 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 优先挂载过去。

–mount-proc 的存在主要是因为,每一个进程里都有一个对应的 /proc/PID 目录,该目录包含大量的有关当前进程的信息。如果我们不使用这个选项,fork 一个 bash 进程到新的 namespace 里,就会将原先 bash 进程里所有的子进程信息都复制了过来,相当于新的 namespace 还是能看见全局的进程信息。通过这个选项,我们才能实现进程信息隔离。

3. PID隔离

新建一个 PID namespace 完成进程 PID 的隔离,具体表现为执行 ps -ef 命令看不到全局的进程信息。

使用 unshare 命令启动 bash 将 PID 隔离:

unshare -p /bin/bash

执行后,文件会报如下错误:

namespace4

原因是,在启动 unshare 进程时,新的 namespace 会使用 unshare 的 PID 作为新的空间的父进程,但这个 unshare 进程并不在新的 namespace 中,所以会报 Cannot allocate memory 这个错误。

解决方法是,创建一个子进程,子进程在这个 namespace 中就可以了:

unshare -pf /bin/bash

执行后,使用 ps -ef 命令可以看到进程信息有很多,而且 1 号进程并不是 /bin/bash

namespace5

原因是 /bin/bash 进程中的 /proc/PID 目录包含的所有进程信息也被子进程拷贝到了新的 namespace 里,使用 ps -ef 命令时,将这些信息全都打印出来了,所以还是没有实现 PID 的隔离。

解决方法是,使用 --mount-proc 选项:

unshare -pf --mount-proc /bin/bash

执行后,使用 ps -ef 命令可以看到进程信息只有两条,且 1 号进程是 /bin/bash 说明 PID 隔离成功:

namespace6

4. Mount隔离

Mount 隔离的表现是,在外部使用 df -h 查看主机默认命名空间的磁盘挂载情况时,看不到被隔离的文件系统挂载情况,且在外部无法访问到被隔离的文件。

在执行 Mount 隔离之前,执行 df -h ,可以看到在外部是能看到 testext4 的挂载情况的:

namespace7


使用 unshare 命令执行 Mount 隔离:

unshare -mf /bin/bash

在被隔离的文件系统中添加一个文本文件:

echo "hello world" > ./test.txt

可以看到在文件系统内部是可以正常访问该文本文件的:

namespace8


在外部执行 df -h 命令,可以看到在外部看不到该文件系统挂载情况:

namespace9

注意不要直接使用上一个 PID 的例子直接做该测试,否则还是会显示文件挂载情况。

在外部使用 cat 命令也无法查看到该文本文件:

namespace10

说明 Mount 隔离已经成功完成。