Linux Kernel Namespace
namespace
namespace是Linux内核提供的一种资源隔离机制
它允许你把同一台机器的内核资源分成多个“视图”(view),每个进程只看到自己的那一份世界
这意味着两个进程可能:
- 有相同的
/根目录名,但实际上是不同的文件系统 - 各自有自己的PID=1
- 看不到彼此的网络接口
- 有独立的主机名
- 甚至有自己的用户ID映射
每个namespace控制一类资源。Linux通过这些不同类型的namespace拼出“独立宇宙”
namespace的类型
Linux支持几种不同类型的namespaces,每种类型负责隔离不同的资源
- Mount namespace(
mnt)- 用来隔离文件系统的挂载点。每个挂载命名空间都有自己独立的挂载表,这意味着不同的命名空间可以有不同的挂载视图
- 举个例子,一个进程在一个命名空间中挂载的文件系统,并不会影响其他命名空间中的进程
- Process ID namespace(
pid)- 用来隔离进程ID。每个命名空间中的进程有自己的进程ID号,并且在命名空间内看到的进程树是独立的
- 比如,在一个进程ID命名空间中,进程的PID从1开始,这使得容器中的进程与主机的进程互相独立
- Network namespace(
net)- 用来隔离网络资源,每个命名空间都有独立的网络设备、IP地址、路由表等网络配置
- 这样,进程在不同命名空间中可以拥有不同的网络配置,相互之间无法直接通信
- IPC namespace(
ipc)- 用来隔离进程间通信(IPC)资源。每个命名空间拥有独立的消息队列、信号量、共享内存等IPC资源
- 这样,进程在不同命名空间中无法直接使用其他命名空间的IPC资源
- UTS namespace(
uts)- 用来隔离主机名和域名,每个命名空间中的进程可以有自己独立的主机名和域名,而不会影响到其他命名空间
- 这对于容器化应用特别有用,因为它可以让每个容器看起来像是独立的主机
- User namespace(
user)- 用来隔离用户和组ID。每个命名空间中的进程可以有独立的用户ID(UID)和组ID(GID),这使得进程在不同命名空间中可以拥有不同的权限
- 在容器中,进程可以拥有root权限,但仅限于容器内,不会影响主机系统
- Cgroup namespace(
cgroup)- 用来隔离进程的控制组(cgroup)信息。每个命名空间中的进程可以有自己独立的资源限制(如CPU、内存等)
从进程的视角看隔离
每个进程都有自己的namespace集合,内核通过task_struct里的指针指向这些namespace,可以使用lsns或cat /proc/$$/ns/查看当前shell所处的各个命名空间
ipc -> ipc:[4026531839]
mnt -> mnt:[4026531840]
net -> net:[4026531992]
pid -> pid:[4026531836]
user -> user:[4026531837]
uts -> uts:[4026531838]
这些数字是namespace的唯一标识符(实质上是内核对象)
多个进程如果指向同一个namespace,就共享那份“世界观”,如果不同,就各自在不同的宇宙
使用namespace
- 创建命名空间
可以使用
unshare命令或通过编程调用clone()系统调用来创建一个新的命名空间
unshare --net bash
这回启动一个新的shell,运行在一个新的网络命名空间中,意味着它无法访问主机的网络资源
- 查看命名空间
在
/proc/[pid]/ns目录下,可以查看每个进程的命名空间信息。每种类型的命名空间都有对应的文件,如
ls /proc/self/ns
这里可以看到当前进程所属于的各个命名空间