Docker 和 Kubernetes 如何将进程隔离在容器中?当你执行 ls -l /proc/self/ns 时,那些神秘文件代表什么?通过生动的比喻和实例,深入理解 Linux Namespaces 的工作原理。
在 Linux 服务器上执行 ls -l /proc/$$/ns,你会看到以下输出:
lrwxrwxrwx ... cgroup -> cgroup:[4026531835]
lrwxrwxrwx ... ipc -> ipc:[4026531839]
lrwxrwxrwx ... mnt -> mnt:[4026531840]
lrwxrwxrwx ... net -> net:[4026531993]
lrwxrwxrwx ... pid -> pid:[4026531836]
lrwxrwxrwx ... user -> user:[4026531837]
lrwxrwxrwx ... uts -> uts:[4026531838]
这些符号链接就是容器技术的基石——Linux Namespaces。下面逐一解析它们的机制。
什么是 Namespace
将 Linux 操作系统比作一栋大楼,所有进程原本共享大厅资源。Namespace 就像在大楼中隔出的独立房间:
- 隔离:房间内的人以为拥有整栋大楼,看不到外部。
- 共享:所有房间仍处于同一内核大楼中。
在云原生技术中,Namespace 是实现容器隔离的核心机制。
七大 Namespace 详解
1. mnt (Mount Namespace) —— 独立文件系统视图
- 作用:隔离文件系统挂载点。
- 比喻:房间装有单向玻璃,内部操作外部不可见。
- 实例:容器内执行
mount -t tmpfs tmpfs /tmp,仅容器内可见,宿主机和其他容器无感知。这使得 Docker 容器拥有独立的 /proc、/sys 目录。
2. net (Network Namespace) —— 独立网络栈
- 作用:隔离网卡、IP、路由表、端口等网络资源。
- 比喻:房间单独拉设网线,配备独立路由器。
- 实例:容器内
eth0 IP 为 10.244.1.2,宿主机 IP 为 192.168.1.100。容器监听 80 端口不影响宿主机同一端口。
3. pid (PID Namespace) —— 独立进程编号
- 作用:隔离进程 ID 分配。
- 比喻:房间内你是“1 号人物”,大楼管理处记录为普通住户。
- 实例:容器内
ps -ef 显示主进程 PID 为 1,宿主机查看同一进程 PID 可能为 45678。这让容器进程误以为自己是系统初始化进程。
4. uts (UTS Namespace) —— 独立主机标识
- 作用:隔离主机名和域名。
- 比喻:房间可命名为“总统套房”,不影响大楼叫“希尔顿”。
- 实例:容器内执行
hostname my-web-app,宿主机 hostname 保持 node-01。
5. ipc (IPC Namespace) —— 独立进程间通信
- 作用:隔离共享内存、信号量、消息队列。
- 比喻:房间内线电话无法拨打隔壁。
- 实例:防止不同容器进程因相同共享内存 Key 冲突或数据泄露。
6. user (User Namespace) —— 独立用户身份
- 作用:隔离用户 ID 和组 ID。
- 比喻:房间内穿“皇帝新衣”为 Root,外出即平民。
- 实例:容器内UID 0(root)拥有最高权限,宿主机映射为普通用户UID 1000。这是 Rootless Container 的安全基础。
7. cgroup (Cgroup Namespace) —— 独立资源视图
- 作用:隔离 Cgroup 根目录视图。
- 比喻:仅能查看自己房间电表,隐藏整栋楼数据。
- 实例:容器内查看
/proc/self/cgroup 路径缩短,屏蔽宿主机复杂层级。
Namespace 标识符解析
文件链接中的数字如 net:[4026531993] 是 Namespace 的 Inode 编号(唯一标识符):
- 判断进程是否同容器:对比 Namespace Inode 值。若
net:[...] 相同,则共享网络栈(如 Kubernetes Pod 中的多容器)。
- 常用命令:
lsns:列出系统所有 Namespace。
nsenter -t <PID> -n:进入目标进程的 Network Namespace(网络调试利器)。
实践示例
以下 Kubernetes Pod 包含两个容器,在节点查看进程:
# Pod 信息
sysops sysops-788dfd5f5c-8lmdm 2/2 Running 0 10d
# 容器进程
...
containers:
- args:
- -c
- python3 manage.py migrate && gunicorn -c sysops/config/gunicorn_conf.py sysops.asgi:application
command:
- sh
image: x.com/ops/sysops:v5.4.25
name: sysops
...
- args:
- -c
- cd ./golang-k8s;./k8s_informer
command:
- sh
image: x.com/ops/sysops:v5.4.25
name: go-informer
...
# 查看两个进程 net namespace inode
ps -ef | grep k8s_informer
ls -l /proc/50299/ns/net # 输出:net -> net:[4026532784]
ps -ef | grep gunicorn_conf.py
ls -l /proc/50266/ns/net # 输出:net -> net:[4026532784]
# 不同 Pod 容器进程
ps -ef | grep argocd
ls -l /proc/59513/ns/net # 输出:net -> net:[4026532962]
同一 Pod 容器 net inode 相同,不同 Pod 则不同,验证了网络栈共享机制。
调试工具:nsenter
nsenter 是 Linux 容器调试的“瑞士军刀”,可进入任意进程的 Namespace:
# 进入容器网络空间查看网络状态
nsenter -t 659030 -n ss -xl | grep php
# 常用维度:
# -n (net):查看 IP、端口、抓包
# 示例:nsenter -t <PID> -n ip addr
# 示例:nsenter -t <PID> -n tcpdump
通过 Linux Namespaces 的七种隔离机制,容器技术为进程构建了完整的虚拟环境。掌握它们,就理解了容器隔离与共享的本质。
|