3. 命名空间原理:Linux Namespace 概述
Linux Namespace 是 Docker 实现容器隔离的底层核心机制。它通过将全局系统资源(如进程、网络、文件系统、用户 ID 等)封装到独立的命名空间中,使得容器内的进程只能看到属于自己的资源视图,从而实现进程级隔离。Docker 镜像的多租户隔离,正是依赖这些命名空间将不同租户的容器运行环境彻底隔离开来。
3.1 命名空间的作用与分类
每个命名空间负责隔离一类系统资源。当 Docker 启动一个容器时,会为容器创建一组独立的命名空间,容器内的进程在这些命名空间中运行,仿佛拥有一个独立的操作系统实例。下表列出了 Docker 使用的核心命名空间及其隔离的资源:
| 命名空间 | 隔离的资源 | Docker 默认启用 | 多租户隔离关键性 |
|---|---|---|---|
| PID | 进程 ID 编号 | 是 | 高 |
| Network | 网络设备、IP 地址、端口、路由表 | 是 | 高 |
| Mount | 文件系统挂载点 | 是 | 高 |
| User | 用户 ID 和组 ID | 否(需手动启用) | 极高(安全加固) |
| UTS | 主机名和域名 | 是 | 中 |
| IPC | System V IPC 和 POSIX 消息队列 | 是 | 中 |
| Cgroup | 控制组视图 | 是 | 中 |
3.2 PID Namespace:进程隔离
PID Namespace 让容器内的进程拥有独立的 PID 编号空间。在容器内部,进程的 PID 从 1 开始(通常是 init 进程),而宿主机上该进程的 PID 可能是 12345。这种隔离确保了:
- 容器内的进程无法看到或影响宿主机或其他容器的进程。
- 容器内的 PID 1 进程负责回收孤儿进程,避免僵尸进程堆积。
- 当容器停止时,其 PID Namespace 被销毁,内部所有进程被安全终止。
# 在宿主机查看容器内进程的 PID 映射
docker inspect --format '{{.State.Pid}}' <container_id>
# 输出:12345(宿主机 PID)
# 进入容器后查看 PID
docker exec <container_id> ps aux
# 输出:PID 1 为容器主进程
3.3 Network Namespace:网络隔离
Network Namespace 为每个容器提供独立的网络栈,包括网络接口、IP 地址、路由表、防火墙规则等。Docker 通过 veth pair 将容器网络命名空间连接到宿主机网桥(如 docker0),实现容器间通信和外部访问。
- 每个租户的容器拥有独立的 Network Namespace,默认无法直接通信。
- 通过自定义网络(docker network create)可以将同一租户的容器加入同一网络,实现租户内互通。
- 不同租户的网络完全隔离,除非显式配置网络连接或路由规则。
- 端口映射(-p)只在宿主机层面生效,容器内端口冲突不会影响其他租户。
3.4 Mount Namespace:文件系统隔离
Mount Namespace 让每个容器拥有独立的文件系统挂载点视图。容器启动时,Docker 会为其创建新的 Mount Namespace,并将镜像层和容器层挂载到该命名空间中。这意味着:
- 容器内的
/根文件系统是镜像层 + 容器可写层的联合挂载。 - 容器内的挂载操作(如
mount)不会影响宿主机或其他容器的挂载点。 - 通过
-v或--mount挂载的数据卷,会从宿主机文件系统映射到容器 Mount Namespace 中。
/etc、/var/run/docker.sock)挂载到容器内,会打破 Mount Namespace 隔离,导致租户可以访问宿主机或其他容器的文件系统。务必遵循最小权限原则。
3.5 User Namespace:用户隔离与安全加固
User Namespace 是 Docker 多租户隔离中最重要的安全特性之一。它允许容器内的 root 用户(UID 0)映射到宿主机上的非特权用户(如 UID 1000),从而大幅降低容器逃逸风险。
| 特性 | 未启用 User Namespace | 启用 User Namespace |
|---|---|---|
| 容器内 root 权限 | 宿主机 root 权限(UID 0) | 宿主机非特权用户(如 UID 1000) |
| 容器逃逸风险 | 高(root 权限可操作宿主机资源) | 低(非特权用户无法越权) |
| 文件系统权限 | 容器内 root 可读写宿主机文件 | 受宿主机 UID 映射限制 |
| Docker 默认启用 | 是 | 否(需配置 daemon.json) |
| 多租户推荐 | 不推荐 | 强烈推荐 |
# 启用 User Namespace 的 Docker 配置(/etc/docker/daemon.json)
{
"userns-remap": "default"
}
# 查看 UID 映射关系
cat /etc/subuid
# 输出示例:dockremap:100000:65536
# 表示容器内 UID 0 映射到宿主机 UID 100000
3.6 命名空间组合:多租户隔离的基石
Docker 容器启动时,会同时创建 PID、Network、Mount、UTS、IPC 等多个命名空间,并将它们组合在一起形成容器的隔离环境。对于多租户场景,推荐以下命名空间配置策略:
- 必须启用: PID、Network、Mount、UTS、IPC 命名空间(Docker 默认)。
- 强烈建议启用: User Namespace(通过
userns-remap配置)。 - 安全加固: 结合 Cgroups 限制资源使用,防止 DoS 攻击。
- 网络策略: 使用 Docker 自定义网络隔离不同租户,配合 iptables 或网络策略(如 Calico)实现细粒度访问控制。
- 文件系统: 避免挂载宿主机敏感目录,使用只读根文件系统(
--read-only)增强安全性。