docker容器技术原理:NameSpace
Docker 是使用 Linux 的 Namespace 技术实现各种资源隔离的。
什么是 Namespace?
下面是 Namespace 的维基百科定义:
Namespace 是 Linux 内核的一项功能,该功能对内核资源进行分区,以使一组进程看到一组资源,而另一组进程看到另一组资源。Namespace 的工作方式通过为一组资源和进程设置相同的 Namespace 而起作用,但是这些 Namespace 引用了不同的资源。资源可能存在于多个 Namespace 中。这些资源可以是进程 ID、主机名、用户 ID、文件名、与网络访问相关的名称和进程间通信。
简单来说,Namespace 是 Linux 内核的一个特性,该特性可以实现在同一主机系统中,对进程 ID、主机名、用户 ID、文件名、网络和进程间通信等资源的隔离。Docker 利用 Linux 内核的 Namespace 特性,实现了每个容器的资源相互隔离,从而保证容器内部只能访问到自己 Namespace 的资源。
Namespace 类型 | 隔离资源 | 内核版本 | Docker 应用场景 |
---|---|---|---|
Mount | 文件系统挂载点 | 2.4.19 | 容器独立文件视图 |
PID | 进程 ID 空间 | 2.6.24 | 容器内 1 号进程 |
Net | 网络设备/IP/端口/路由表 | 2.6.29 | 容器独立网络栈 |
IPC | System V IPC/POSIX 消息队列 | 2.6.19 | 进程间通信隔离 |
UTS | 主机名与域名 | 2.6.19 | 容器自定义 hostname |
User | 用户/组 ID 映射 | 3.8 | 容器 root≠宿主机 root |
Cgroup | Cgroups 根目录 | 4.6 | 容器独立 cgroup 视图 |
Time | 系统时钟 | 5.6 | ⚠️ Docker 暂未支持 |
虽然 Linux 内核提供了8种 Namespace,但是最新版本的 Docker 只使用了其中的前6 种,分别为Mount Namespace、PID Namespace、Net Namespace、IPC Namespace、UTS Namespace、User Namespace。
下面,我们详细了解下 Docker 使用的 6 种 Namespace的作用分别是什么。
各种 Namespace 的作用?
1. Mount Namespace (mnt)
作用:隔离文件系统挂载点,让每个容器拥有独立的文件视图
底层实现原理
- 内核标志:
CLONE_NEWNS
- 进程看到的挂载点由其
/proc/[pid]/mountinfo
决定 - 使用
MS_REC|MS_PRIVATE
防止挂载传播到主机
命令行实践
1 | # 创建新的 Mount Namespace |
2. PID Namespace (pid)
作用:隔离进程 ID,使容器内进程从 1 开始编号
底层实现原理
- 内核标志:
CLONE_NEWPID
- 父 Namespace 能看到所有子 Namespace 的进程
- /proc 文件系统需要重新挂载才能显示正确的 PID 视图
命令行实践
1 | # 创建 PID Namespace 并重挂 /proc |
3. UTS Namespace (uts)
作用:隔离主机名和域名(NIS domain name)
底层实现原理
- 内核标志:
CLONE_NEWUTS
- 修改
struct new_utsname
中的nodename
和domainname
- 容器内设置主机名使用
sethostname()
系统调用
命令行实践
1 | # 创建 UTS Namespace |
查看源码实现
Linux 内核中的 UTS 相关结构:
1 | struct uts_namespace { |
4. IPC Namespace (ipc)
作用:隔离 System V IPC 和 POSIX 消息队列,主要是用来隔离进程间通信的
底层实现原理
- 内核标志:
CLONE_NEWIPC
- 隔离对象:信号量(sem)、消息队列(msg)、共享内存(shm)
- /proc/sysvipc 在容器内只显示本命名空间的资源
命令行实践
1 | # 主机创建原始IPC资源 |
5. User Namespace (user)
作用:隔离用户和组 ID,提供权限映射
底层实现原理
- 内核标志:
CLONE_NEWUSER
- 通过
/proc/[pid]/uid_map
和/proc/[pid]/gid_map
实现 ID 映射 - 允许无特权用户创建容器
命令行实践
1 | # 确保启用用户命名空间 |
6. Network Namespace (net)
作用:隔离网络资源(设备、IP 地址、端口、路由表)
底层实现原理
- 内核标志:
CLONE_NEWNET
- 每个网络命名空间有独立的网络设备列表、路由表、Iptables 规则
- 使用 veth 接口对连接不同 Namespace
命令行实践
1 | # 创建 Network Namespace |
复杂网络实践:创建两个容器互通
1 | # 创建两个命名空间 |
为什么 Docker 需要 Namespace?
- 资源隔离:防止容器间相互影响
- 安全性:通过 User Namespace 减少权限溢出
- 环境一致性:确保容器运行不受主机环境影响
- 进程独立:允许不同容器使用相同的进程 ID
- 网络隔离:避免端口冲突,支持多容器网络拓扑
- 轻量化:比硬件虚拟化更高效(如 KVM)
关键进阶操作:结合多个 Namespace
1 | # 创建完整隔离环境 |
排查 Namespace 问题
1 | # 查看进程所属 Namespace |
生产环境建议
Always enable User Namespace: 减少 root 权限风险
dockerd --userns-remap=default
Mount propagation settings: 使用
:slave
或:private
docker run -v /host-path:/container-path:slave
Limit container capabilities:
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE
Use cgroups v2 with cgroup namespaces (内核 ≥5.2):
docker run --cgroupns=private
通过以上底层实践,可以深入理解 Docker 如何利用 Linux Namespace 实现容器化隔离,这些知识对于容器排错、性能优化和安全加固都至关重要。