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 控制组视图 是 中
关键理解: 命名空间是“视图隔离”,而非“资源限制”。它让进程看到不同的资源视图,而资源使用上限由 Cgroups 控制。在多租户场景中,两者必须配合使用。

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)只在宿主机层面生效,容器内端口冲突不会影响其他租户。
Network Namespace 多租户隔离示意图 宿主机网络命名空间(默认) docker0 网桥 租户 A Network Namespace 容器 A1 容器 A2 veth pair 连接 IP: 172.17.0.2/16 IP: 172.17.0.3/16 租户 B Network Namespace 容器 B1 容器 B2 veth pair 连接 IP: 172.17.0.4/16 IP: 172.17.0.5/16 不同租户的容器通过独立的 Network Namespace 实现网络栈隔离,默认无法直接通信

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
User Namespace UID 映射原理 容器 User Namespace root 用户(UID 0) 普通用户(UID 1000) 其他用户(UID 1001-65535) 容器内看到的 UID 空间 宿主机 User Namespace 非特权用户(UID 100000) 非特权用户(UID 101000) 非特权用户(UID 101001-165535) 宿主机上映射的 UID 空间 容器内 UID 0 映射为宿主机非特权用户,即使容器被攻破也无法获得宿主机 root 权限

3.6 命名空间组合:多租户隔离的基石

Docker 容器启动时,会同时创建 PID、Network、Mount、UTS、IPC 等多个命名空间,并将它们组合在一起形成容器的隔离环境。对于多租户场景,推荐以下命名空间配置策略:

多租户命名空间配置清单:
  1. 必须启用: PID、Network、Mount、UTS、IPC 命名空间(Docker 默认)。
  2. 强烈建议启用: User Namespace(通过 userns-remap 配置)。
  3. 安全加固: 结合 Cgroups 限制资源使用,防止 DoS 攻击。
  4. 网络策略: 使用 Docker 自定义网络隔离不同租户,配合 iptables 或网络策略(如 Calico)实现细粒度访问控制。
  5. 文件系统: 避免挂载宿主机敏感目录,使用只读根文件系统(--read-only)增强安全性。