摘要:namespace 是 Linux 内核提供的资源视野隔离机制,共六种常用类型分别隔离进程表、网络栈、挂载点、主机名、进程间通信与用户身份。本节逐个拆解,并在宿主机上亲手进出容器的命名空间,让"隔离"从口号变成可操作的命令。
一个进程对"世界"的认知来自内核提供的几类信息:有哪些进程、网络接口长什么样、文件系统挂载了什么、主机叫什么名字、我是谁。namespace 的做法是给每类信息提供独立的实例,进程被关联到哪套实例,它看到的就是哪套世界。六种常用类型:
PID namespace:独立的进程编号空间。容器里的进程在自己的空间内从 1 号开始编号,完全看不到宿主机上其他进程。经典误认:以为容器里的 1 号是"先创建的特殊进程"。它只是在子空间里编号为 1 的普通进程,在宿主机上另有真实编号。
NET namespace:独立的网络栈——网卡、IP、路由表、iptables 规则、端口空间各一套。两个容器可以各自监听 80 端口互不冲突,就是因为它。第 4 章整章都在它上面展开。
Mount namespace:独立的挂载点视图。容器进程看到的根目录是 overlay2 拼出来的那份 merged 视图,宿主机在别处挂载的磁盘它一无所知。
UTS namespace:独立的主机名与域名。所以每个容器可以有自己的 hostname,互不干扰。
IPC namespace:独立的信号量、共享内存等进程间通信设施。
User namespace:独立的 UID/GID 映射。容器内的 root 可以映射为宿主机上的普通用户——rootless 容器与第 7 章安全加固的基石。
先起一个容器,然后在宿主机上找它的进程:
docker run -d --name ns-demo nginx:alpine PID=$(docker inspect ns-demo --format '{{.State.Pid}}') echo $PID
这个真实 PID 是所有观测的入口。看它挂了哪些 namespace:
sudo lsns -p $PID
输出形如:
10026 mnt 4096 root / nginx: master process 10026 uts 4096 root / nginx: master process 10026 ipc 4096 root / nginx: master process 10026 pid 4096 root / nginx: master process 10026 net 4096 root / nginx: master process
mnt、uts、ipc、pid、net 各一条,这就是容器进程的全部装备。注意 User namespace 不在列表里——默认模式下 Docker 不启用它,容器内的 root 就是宿主机的 root,这正是默认模式安全性偏弱的根源,第 7 章的安全节会回到这一点。
也可以直接读 /proc:
sudo ls -l /proc/$PID/ns/
每个 namespace 是一个符号链接,链接目标是 xxx:[409657120] 这样的编号。两个进程如果 net 编号相同,它们就共享同一套网络栈——Docker 判断"容器是否同网络"、我们判断"两个进程是否隔离",看的都是这个编号。
docker exec 的本质是进入目标进程的 namespace 再执行命令。理解了这一点,你就获得了一个不依赖 Docker 客户端的排查后门——nsenter:
sudo nsenter -t $PID -m -u -i -n -p sh
这条命令把当前 shell 关联到目标进程的 mount、uts、ipc、net、pid namespace,随后你看到的文件系统、网络、进程表就是容器看到的世界。docker daemon 出问题、exec 失灵时,这招常常是唯一入口。
在容器里验证 PID 映射:
# 容器视角 docker exec ns-demo sh -c 'echo $$; ps'
容器里 nginx master 的编号是 1。而宿主机视角它是 $PID。同一个进程,两套编号,各自在各自的 PID namespace 里成立。ps 在容器里默认只显示当前 namespace 的进程,所以输出干净得像一台独立机器——错觉的每一步都有内核机制背书。

docker run 的 --pid host、--network host、--ipc host 参数就是让容器跳过对应 namespace 的创建、直接加入宿主机的。诊断类容器常这么干:--pid host 加上诊断工具镜像,就能看到宿主机全部进程;--network host 则让容器直接用宿主机网络栈,省去端口映射——第 4 章的 host 网络模式讲的就是它。反过来理解也一样:所谓网络模式、进程共享,本质上就是"要不要新建对应 namespace"这道选择题。
"namespace 提供安全隔离"——方向错了。 namespace 提供的是视野隔离,不是权限隔离。容器内 root 在默认模式下拥有宿主机 root 的部分能力,看清进程与否和能不能伤害它是两回事。安全边界要靠 User namespace、Capabilities 裁剪与 seccomp,第 7 章展开。
"容器里进程少是因为隔离好"——是因为看不见。 宿主机上的真实进程一个不少地跑着,只是容器进程的视野被 PID namespace 滤掉了。资源占用该多少还是多少,cgroup 那边记得设限。
下一节看第二台引擎——cgroup 如何给这份视野配上账本和手铐。