news 2026/4/24 15:49:32

Linux内核 命名空间机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux内核 命名空间机制

Linux Namespace 是内核提供的轻量级资源隔离机制,核心是让不同进程组看到独立的系统资源视图,是容器(Docker、K8s)的底层基石。它隔离的是进程对资源的可见性,而非物理资源本身,因此比虚拟机更轻量化

  • 本质:为全局系统资源(PID、网络、挂载等)划分独立作用域,进程只能访问所属命名空间内的资源,对其他空间不可见。
  • 内核实现:每个进程通过task_struct中的nsproxy指针,关联一组命名空间实例;内核在系统调用与资源访问时,按当前进程的命名空间做过滤与映射。
  • 生命周期:命名空间由引用计数管理,最后一个进程退出时自动销毁;子进程默认继承父进程的所有命名空间。

内核核心数据结构

1. struct nsproxy(命名空间代理)

所有命名空间的统一入口,每个进程的task_struct持有一个nsproxy指针,指向当前所属的命名空间集合:

struct nsproxy { atomic_t count; // 引用计数 struct uts_namespace *uts_ns; // UTS命名空间 struct ipc_namespace *ipc_ns; // IPC命名空间 struct mnt_namespace *mnt_ns; // 挂载命名空间 struct pid_namespace *pid_ns_for_children; // PID命名空间(子进程用) struct net *net_ns; // 网络命名空间 struct cgroup_namespace *cgroup_ns; // Cgroup命名空间 struct user_namespace *user_ns; // 用户命名空间(基础) struct time_namespace *time_ns; // 时间命名空间 };

2. 各类型命名空间结构体

每种隔离资源对应独立内核结构,维护该空间的资源状态与映射:

  • PID:struct pid_namespace(维护 PID 分配、层级、init 进程)
  • Mount:struct mnt_namespace(维护独立挂载树)
  • Net:struct net(独立网络栈、设备、路由)
  • User:struct user_namespace(UID/GID 映射表)
  • IPC:struct ipc_namespace(独立 System V IPC 对象)
  • UTS:struct uts_namespace(独立 hostname/domainname)

关键机制详解

1. PID 命名空间(分层架构)

  • 每个空间有独立 PID 号段,首个进程为PID 1(init),负责回收僵尸进程。
  • 嵌套:子空间进程在父空间有全局 PID,如子空间 PID=1 → 父空间 PID=1234 → 根空间 PID=5678(/proc/[pid]/statusNSpid字段可见)。
  • 销毁:init 进程退出时,内核终止该空间所有进程。

让一组进程看到独立的进程号空间

  • 容器里看到 PID 从 1 开始
  • 宿主机看到容器进程是正常全局 PID
  • 容器内部看不见宿主机其他进程

一句话:给进程套一层 PID 映射表

内核基本结构

每个 PID namespace 在内核里是一个独立结构:

struct pid_namespace { struct kref kref; // 引用计数 struct pidmap pidmap[PIDMAP_ENTRIES];// PID 分配位图 int last_pid; // 上次分配的 PID struct task_struct *child_reaper; // 本空间的 init 进程(PID 1) struct pid_namespace *parent; // 父 namespace // ... };

关键点:

  1. 每个 namespace 有自己的 PID 分配器
  2. 层级关系:子 → 父 → 根 namespace
  3. 有固定的init 进程(PID 1)

PID分配与存储

内核并不只存一个 PID,而是给每个进程在所有祖先 namespace 中各分配一个 PID

结构struct pid保存一个数字,而struct upid保存每个层级的编号:

struct pid { rwlock_t lock; unsigned int level; // 命名空间深度 struct upid numbers[]; // 每个 ns 对应的 PID };

例如:

  • 根 ns:PID = 1234
  • 父 ns:PID = 100
  • 子 ns:PID = 1

内核会完整保存整条链

可见性规则(最重要)

  1. 子 namespace 完全看不见父 / 兄弟
  2. 父 namespace 可以看见子
  3. 看到的 PID 是当前 ns 对应的编号

这就是为什么容器里 ps 只能看到自己,宿主机 ps 能看到容器。

嵌套层级原理

PID namespace 是树状结构

根 NS (level 0) ├─ 容器A NS (level 1) │ └─ 容器A内嵌套容器 (level 2) └─ 容器B NS (level 1)
  • 一个进程在每一层都有一个 PID
  • /proc/[pid]/status里的NSpid字段会列出所有层级 PID

示例:

NSpid: 14528 42 1

表示:

  • 根 ns:14528
  • 父 ns:42
  • 本 ns:1

内核关键逻辑

内核在遍历进程、分配 PID、发送信号时,都会:

  1. 获取当前进程的task_struct->nsproxy->pid_ns
  2. 用这个 ns 去查找 / 分配 / 展示 PID

本质就是:所有涉及 PID 的内核行为,都以当前进程所在 PID namespace 为基准。

2. User 命名空间(权限隔离核心)

User Namespace(CLONE_NEWUSER)是所有容器隔离的权限基石,是 Linux 安全容器的核心:实现UID/GID 隔离、权限映射、Capability 隔离、安全边界隔离,让容器内root ≠ 宿主机 root

  • 是其他命名空间的基础,允许非特权用户创建命名空间。
  • 通过/proc/[pid]/uid_map/gid_map做内外 UID 映射,如:0 1000 1表示容器内 root (0) 映射到宿主机 uid=1000。
  • 权限:进程在空间内的能力(capabilities)受限于映射后的真实权限。

核心作用

  1. 独立的UID / GID 编号空间
  2. 内外 ID 映射:容器内0(root)→ 宿主机普通非特权用户
  3. Capability 能力隔离:容器内即使是 root,也只拥有受限权限
  4. 允许普通非特权用户创建其他所有命名空间(mnt/pid/net/ipc 等)
  5. 隔离安全 KEY、LSM、资源限额、用户组体系

关键结论:没有 User NS,容器就是弱隔离,容器 root 极易提权击穿宿主机。

进程关联

task_struct └→ nsproxy └→ user_ns // struct user_namespace

每个进程都绑定一个user_namespace,是权限检查的最高上下文

关键结构体

struct user_namespace { struct uid_gid_map uid_map; // UID 映射表 struct uid_gid_map gid_map; // GID 映射表 struct user_namespace *parent;// 父 user ns,树状层级 struct cap_set inheritable; // 权限能力集 // 安全、LSM、proc、cgroup 关联 bool ns_capable_setid; // ... };

映射单元

struct uid_gid_map { u32 nr_extents; struct uid_gid_extent extent[UID_GID_MAP_MAX_EXTENTS]; }; // 一段映射规则 struct uid_gid_extent { u32 first; // 容器内起始ID u32 lower; // 宿主机起始ID u32 count; // 映射数量 };

UID/GID 映射机制(核心)

1. 双向映射
  • From 容器 → 宿主机:内核做ns uid → 全局 uid转换,读写文件、权限检查、磁盘持久化用宿主机真实 ID
  • From 宿主机 → 容器:全局 ID 反向翻译为容器内 ID,psls -n展示容器内编号
2. 映射文件(/proc 接口)
/proc/[pid]/uid_map /proc/[pid]/gid_map

标准容器映射示例:

# uid_map 0 1000 65536

含义:

  • 容器内 UID065535
  • 映射到宿主机 UID10001000+65535

👉 容器里的 root (0),在宿主机上就是普通用户 1000。

3. 无映射 = nobody

如果不配置 map,容器内所有未映射 ID 都会被内核强制映射为65534(nobody),天然防越权。

Capability 权限隔离

Linux 不再靠传统 root/sudo,而是拆分细粒度 Capability。User NS 会裁剪、隔离 Cap

  1. 新 user ns 内的进程
    • 默认不继承父命名空间的高权限 Cap
    • 只被授予一组受限安全 Cap(如 CAP_CHOWN、CAP_SETUID 等)
  2. 容器内 root
    • 当前 user ns 内拥有完整 Cap
    • 对父 user ns / 宿主机资源无任何特权

举例:容器内执行mount只能在自己的 mnt ns 里生效;无法挂载宿主机真实磁盘、无法修改宿主机文件权限。

层级模型(树状)

User NS 天然层级化:

根 User NS(宿主机顶层,真实权限) ├─ 容器A User NS(子级,权限受限) │ └─ 嵌套容器 User NS(孙子级) └─ 容器B User NS

权限规则:

  1. 子 ns 不能修改父 ns 资源
  2. 父 ns 可以管控、限制子 ns 权限
  3. 权限检查逐级向上校验

3. Network 命名空间

隔离完整网络协议栈,是容器网络、虚拟化网络、多租户网络隔离的底座:

  • 每个 NetNS 拥有独立:网卡、IP、路由、ARP、iptables、TCP/UDP 栈、端口、socket
  • 默认完全隔离,互不监听、互不路由、互不冲突
  • 底层内核协议栈代码全局共用,只是网络资源实例隔离
  • 新空间默认仅含lo 回环接口(DOWN 状态),需手动启用与配置。
  • 跨空间通信:用veth pair(虚拟以太网对)连接两个空间,一端在宿主机、一端在容器空间。

隔离范围(全栈隔离)

  1. 网络设备lo、物理网卡、虚拟网卡(veth、tap、macvlan、ipvlan)
  2. 三层网络IP 地址、路由表、网关、ARP、邻居表
  3. 四层传输TCP/UDP/ICMP 独立端口空间,不同 netns 可重复占用同一端口
  4. 防火墙 / 转发独立 iptables、nftables、netfilter 规则
  5. 网络配置/proc/sys/net内核参数隔离(tcp_tw_reuse、ip_forward 等)
  6. Socket & 连接每个 ns 的 socket 完全隔离,不能直接跨 ns 通信

默认行为

  1. 新建net ns只自动创建独立 lo 设备(默认 DOWN)
  2. 无任何物理网卡、无路由、无防火墙规则
  3. 必须手动:
    • 启用 lo:ip link set lo up
    • 挂载虚拟网卡、配置 IP / 路由
  4. 端口隔离:宿主机 80 端口 和 容器 80 端口 互不冲突

跨 NetNS 通信核心方案

1. veth pair(容器默认)

一对虚拟以太网卡,像一根网线两端:

  • 一端留在宿主机 root netns
  • 一端移入容器 netns实现:容器 ↔ 宿主机 二层互通
2. macvlan / ipvlan

让容器直接复用物理网卡,独立 MAC/IP,直连局域网

3. 网桥 bridge

宿主机创建虚拟网桥,多个容器 veth 接入网桥,实现容器之间互通

4. SDN/Overlay

VXLAN、Geneve,跨主机容器网络

5. 本地 UNIX 域套接字

unix socket不受 netns 隔离,可跨 ns 通信

4. Mount 命名空间

  • 新空间复制父空间挂载树,后续 mount/umount 仅影响当前空间。
  • 挂载传播:支持shared/slave/private/unbindable,控制挂载事件在父子空间的传播。

隔离文件系统挂载视图,核心:

  1. 每个 ns 拥有独立挂载树
  2. 新的mount/umount仅作用于当前 ns,不影响宿主机 / 其他容器;
  3. 是容器隔离根目录、OverlayFS、只读挂载、临时文件系统隔离的底层基础;
  4. 内核标识:CLONE_NEWNS,最早、最基础的命名空间。

进程维度

task_structnsproxymnt_ns

struct nsproxy { struct mnt_namespace *mnt_ns; // 当前进程所属挂载命名空间 // ...其他ns };

挂载命名空间本体

struct mnt_namespace { struct mount *root; // 该ns的根挂载节点 struct list_head list; // 所有挂载项链表 struct mount_event event; unsigned int mount_seq; // 挂载序列,每次mount+1 enum mnt_propagation_type propagation; // 挂载传播默认属性 // 引用计数、用户ns关联、生命周期 };

关键挂载对象

  • struct vfsmount:文件系统挂载实例
  • struct mount:挂载点实体,维护父子挂载层级、挂载传播标记
  • 全局不再只有一棵统一挂载树,每个 mnt_ns 一棵独立挂载树

挂载树复制机制(Copy-on-Write 思想)

通过clone(CLONE_NEWNS)创建新挂载 ns 时:

  1. 复制父进程完整挂载树(初始视图完全一致);
  2. 复制是浅拷贝:底层文件系统、超级块、inode 全局共享;
  3. 后续当前 ns 内执行mount/umount/bind mount只会修改自己这棵树,完全隔离。

区别:物理资源(磁盘、块设备)全局共享;挂载视图、挂载点列表、目录覆盖关系完全隔离。

视图隔离效果

  • 容器内挂载/tmp/dev/shm、临时磁盘,宿主机看不到;
  • 宿主机挂载硬盘,默认不会自动穿透到容器;
  • 容器内umount /sys不会影响宿主机系统。、

挂载传播(Mount Propagation)—— 重中之重

Mount ns 不是完全隔绝,内核提供挂载传播属性,控制挂载事件跨 ns 传递,是容器、systemd 关键机制。

四种传播类型
类型作用
MS_PRIVATE私有完全隔离,挂载变更不互通(容器默认)
MS_SHARED共享挂载事件双向同步,父子 ns 互相传递
MS_SLAVE从属只能接收父 ns 挂载事件,自身变更不向外扩散
MS_UNBINDABLE不可绑定不允许 bind mount,禁止跨目录挂载
典型场景
  1. 容器默认:private容器内部挂载、卸载完全隔离,是安全隔离基础。
  2. 宿主机 /run/media 等:shared/slave,U 盘插入、自动挂载,能被所有需要的 ns 感知。
  3. bind 挂载、容器目录映射依赖传播属性控制是否泄露宿主机目录。
修改传播属性命令
# 设置目录为私有(容器标准做法) mount --make-private /

挂载层级 & 根目录隔离原理

  1. 新 mnt ns 继承父的/根挂载;
  2. 容器通过pivot_root/chroot结合独立挂载树:
    • 先在私有挂载 ns 内挂载 OverlayFS(读写层 + 镜像只读层);
    • pivot_root切换根目录,替换为容器文件系统;
    • 再挂载独立/proc /sys /dev,实现完整环境隔离。

关键区别

  • chroot:只是目录视图限制,无法隔离挂载、无法隐藏宿主机挂载点;
  • Mount NS + pivot_root:真正隔离完整文件系统挂载拓扑。

生命周期

  1. mnt_namespace基于引用计数管理;
  2. 当所有绑定该 ns 的进程全部退出、无文件句柄引用时,内核自动销毁该挂载树;
  3. 销毁不会卸载全局真实文件系统,仅销毁当前 ns 的挂载拓扑

Mount NS 与其他容器组件配合

  1. + User NS非特权用户也能创建私有挂载、绑定挂载,提升容器安全性。
  2. + PID NS独立进程视图 + 独立 /proc 挂载,彻底隔离进程信息。
  3. + Cgroup隔离视图 + 资源限制,构成完整容器底座。
  4. OverlayFS + Mount NS每层镜像只读挂载 + 容器私有读写层,实现容器镜像分层。

全局挂载树 与 NS 挂载树 关系

1. 初始状态:根命名空间(init_ns)

系统启动后,只有根 Mount NS

  • 全局只有一棵唯一挂载树
  • 所有进程默认共享这棵树
  • 所有/ /home /tmp /sys /proc都在这棵树上
2. 创建新 Mount NS:CLONE_NEWNS
clone(CLONE_NEWNS) / unshare(CLONE_NEWNS)

内核关键动作:

  1. 浅拷贝根 NS / 父 NS 的整棵挂载树
    • 复制所有mount节点的拓扑关系
    • 底层super_block、dentry、inode完全共享,不复制数据
  2. 生成一个全新mnt_namespace
  3. 新进程 / 当前进程绑定到新 mnt_ns
3. 隔离本质
  • ✅ 底层资源:全局共享(磁盘、inode、sb)
  • ✅ 挂载对象:多个 NS 可以引用同一个mount
  • ❌ 挂载操作隔离:新 NS 内执行mount / umount / bind mount只修改当前 NS 自己的挂载树,不影响父 NS、其他容器

挂载树的「覆盖」机制(关键)

Linux 挂载是覆盖式

  1. 原目录存在原有 dentry 与内容
  2. 在该目录执行 mount → 新文件系统覆盖该目录
  3. 上层原目录内容被隐藏,仅在卸载后恢复

结合 NS:

  • 容器内单独挂载/etc覆盖
  • 宿主机同目录完全不受影响
  • 因为二者挂载树拓扑独立

挂载传播:多 NS 挂载树的联动规则

如果完全隔离,U 盘自动挂载、容器挂载宿主机目录会失效;内核引入挂载传播,控制挂载事件是否跨 NS 同步。

四种类型:

  1. MS_PRIVATE 私有(容器默认)挂载树完全隔离,双向不通,容器安全基础。
  2. MS_SHARED 共享父子 NS 挂载树双向同步,一方 mount,另一方自动看到。
  3. MS_SLAVE 从属只能继承父 NS 挂载,自身修改不会往外扩散。
  4. MS_UNBINDABLE禁止 bind 挂载,防止目录穿透泄露。
典型流程

宿主机/media设为shared

→ U 盘插入自动挂载到/media/usb

→ 所有 shared/slave 的子 NS 自动看到该挂载

→ 私有容器看不到,隔离生效

多 Mount NS 整体架构图示

[根Mount NS 挂载树] 全局原始挂载拓扑 │ ├─ 复制生成 → [容器A mnt_ns 挂载树](私有) └─ 复制生成 → [容器B mnt_ns 挂载树](私有) 底层:super_block / inode / dentry 全局共用 上层:每棵挂载树 挂载点、覆盖关系、卸载、新增挂载 完全独立

内核关键执行逻辑(用户访问文件)

当进程 open ("/tmp/file"):

  1. 取当前进程 →nsproxy->mnt_ns
  2. 当前 NS 的挂载树为基准做路径解析
  3. 逐级匹配挂载点,应用挂载覆盖规则
  4. 最终找到对应 super_block + inode

核心结论:路径解析、挂载可见性,全部绑定在当前进程的 Mount 命名空间上

创建与管理的三大系统调用

1. clone ()(创建新进程 + 新命名空间)

创建子进程并指定新命名空间,是容器启动的核心调用:

// 创建新UTS+PID命名空间的子进程 pid = clone(child_func, stack, CLONE_NEWUTS | CLONE_NEWPID | SIGCHLD, arg);

2. unshare ()(当前进程脱离旧空间,创建新空间)

不创建新进程,直接为当前进程切换到新命名空间(unshare命令底层):

unshare(CLONE_NEWNET | CLONE_NEWNS); // 脱离当前网络与挂载空间

3. setns ()(加入已存在的命名空间)

通过命名空间文件描述符(/proc/[pid]/ns/xxx),将进程加入指定空间(nsenter命令底层):

int fd = open("/proc/1234/ns/net", O_RDONLY); setns(fd, CLONE_NEWNET); // 加入PID=1234的网络空间
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/24 15:49:31

告别Weston:深入OpenHarmony RenderService新框架,看它如何为3D应用铺路

告别Weston:深入OpenHarmony RenderService新框架,看它如何为3D应用铺路 当开发者第一次在OpenHarmony设备上运行3D游戏时,或许不会意识到背后是一场持续两年的图形架构革命。从Weston到RenderService的切换,不仅是框架名称的更替…

作者头像 李华
网站建设 2026/4/24 15:49:11

Windows上安装Android应用的终极解决方案:APK Installer完全指南

Windows上安装Android应用的终极解决方案:APK Installer完全指南 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否曾想过在Windows电脑上直接运行手机…

作者头像 李华
网站建设 2026/4/24 15:49:09

从网红Wi-Fi天线到PCB八木:聊聊那些低成本、高增益的天线DIY方案

从网红Wi-Fi天线到PCB八木:低成本高增益天线DIY全攻略 在无线通信领域,天线性能往往决定着整个系统的成败。无论是极客们的DIY项目,还是物联网设备的原型开发,寻找既经济实惠又具备出色性能的天线解决方案一直是工程师和爱好者们关…

作者头像 李华
网站建设 2026/4/24 15:45:39

QFT工具:为技术爱好者打造的超快速P2P UDP文件传输方案

QFT工具:为技术爱好者打造的超快速P2P UDP文件传输方案 【免费下载链接】qft Quick Peer-To-Peer UDP file transfer 项目地址: https://gitcode.com/gh_mirrors/qf/qft 想象一下这样的场景:你需要将一个10GB的视频文件发送给远在另一个城市的朋友…

作者头像 李华
网站建设 2026/4/24 15:45:10

2025年MLOps必备的10个Python库解析

1. 为什么2025年的MLOps需要这10个Python库?三年前部署一个机器学习模型还需要手动编写数百行部署脚本,现在MLOps工具链的成熟度已经让模型部署变得像调用API一样简单。作为经历过完整MLOps演进周期的从业者,我亲历了从手工运维到自动化管道的…

作者头像 李华