一、容器技术的崛起

自 Docker 将容器推向大众以来,"一次构建,到处运行"的愿景已成为云计算的基石。容器本质上是一种轻量级虚拟化技术,它不模拟完整的操作系统,而是通过 Linux 内核的 Namespace 和 Cgroup 机制实现进程级别的资源隔离与限制。本文聚焦于 Namespace 这一核心机制,揭示容器如何实现"以为自己独占整个世界"的幻觉。

二、Namespace 的本质

Namespace 是 Linux 内核提供的一种资源分区机制,它让一组进程看到的资源与另一组进程不同。每个 Namespace 实例维护自己的资源标识符,不同 Namespace 中的进程可以有相同的 PID、相同的挂载点列表或相同的网络接口,但彼此互不干扰。

相关系统调用包括:

  • clone():创建新进程时可指定 Namespace 标志位
  • unshare():将当前进程从共享的 Namespace 中"分离"出来
  • setns():通过文件描述符"加入"已存在的 Namespace

三、八种 Namespace 类型详解

3.1 Mount Namespace(mnt)

Mount Namespace 隔离文件系统挂载点。容器内的 mount 和 umount 操作不会影响宿主机的挂载状态。这是容器拥有独立文件系统的基础。

3.2 PID Namespace(pid)

PID Namespace 隔离进程 ID 编号空间。在新建的 PID Namespace 中,第一个进程会被分配 PID 1。当容器内的 PID 1 退出,整个 Namespace 会被销毁,其下的孤儿进程也会被内核回收。

$ docker run --rm -it ubuntu:22.04 ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   4624  3200 pts/0    Ss   12:00   0:00 /bin/bash

3.3 Network Namespace(net)

Network Namespace 隔离网络设备、协议栈、路由表和防火墙规则。每个 Network Namespace 拥有独立的 lo 回环设备,需要虚拟网卡对(veth pair)与宿主机通信。

3.4 IPC Namespace(ipc)

IPC Namespace 隔离 System V IPC 对象和 POSIX 消息队列。不同 Namespace 中的进程不能通过共享内存段通信。

3.5 UTS Namespace(uts)

UTS Namespace 隔离主机名和域名,让每个容器可以拥有独立的 hostname。

$ hostname
docker-host

$ docker run --rm -it --hostname mycontainer ubuntu:22.04 hostname
mycontainer

3.6 User Namespace(user)

User Namespace 隔离用户和组 ID 映射。容器内的 root 可以映射到宿主机的非特权用户,这是容器安全加固的基石。

$ cat /proc/self/uid_map
0     1000          1
1  100000        65536

3.7 Cgroup Namespace(cgroup)

Cgroup Namespace 隔离 cgroup 的可见视图。容器内看到的 /proc/self/cgroup 被虚拟化。

3.8 Time Namespace(time)

Linux 5.6 引入的时间 Namespace,允许不同进程看到不同的系统时钟。

四、Namespace 的实现原理

每个进程通过 /proc/[pid]/ns/ 目录下的符号链接描述文件来引用其加入的 Namespace。内核为每类 Namespace 维护内部结构体,struct nsproxy 封装所有 Namespace 指针。

4.1 标识与引用计数

每个 Namespace 拥有唯一的 inode 号。当 Namespace 中最后一个进程退出或 detach 时,内核销毁该 Namespace 占用的所有资源。

4.2 层次关系

某些 Namespace 存在层级嵌套。子 Namespace 中的所有系统调用必须遵守父 Namespace 的可见性约束。

五、容器运行时如何使用 Namespace

5.1 runC 的执行流程

Docker 底层使用 containerd → runC 的标准 OCI 容器运行时流程:

  1. containerd-shim 创建容器配置指定需要启用的 Namespace 列表
  2. runC 调用 clone() 在新建 Namespace 中启动容器进程
  3. 根据 spec 配置网络、挂载和 cgroup 参数

5.2 Kubernetes Pod 共享 Namespace

在 K8s 中,同一个 Pod 内的容器共享 NET、IPC 和 UTS Namespace。pause 容器持有 Network Namespace。

六、安全加固

  • 启用 User Namespace + rootless 模式
  • 配置 Seccomp BPF 过滤危险系统调用
  • 使用 AppArmor/SELinux 强制访问控制
  • 定期更新内核与容器运行时

七、总结

Namespace 通过虚拟化资源视图让每个进程拥有"独立的幻觉"。从 Mount、PID、Network 到 User、Time,每种 Namespace 负责隔离一类系统资源,它们协同工作构成了容器技术的底层安全边界。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部