Linux 内核容器技术:Namespace 隔离机制深度解析(第一部分)

文档信息

  • 系列: Linux 内核容器技术深度解析
  • 第一篇: Namespace 隔离机制
  • 版本: V2.0 (深度优化版)
  • 创建日期: 2026 年 3 月 10 日
  • 修订日期: 2026 年 3 月 10 日
  • 预计阅读时间: 6-8 小时
  • 前置知识: Linux 操作系统、进程管理、文件系统、网络基础、系统编程
  • 适合人群:
    • 容器平台开发工程师
    • 系统架构师
    • DevOps/SRE工程师
    • 对容器底层原理感兴趣的高级开发者

目录

第一部分:基础与原理

  1. 容器技术引入与背景
  2. 容器技术前世今生
  3. Namespace 核心机制详解

第二部分:深度实践

  1. [Linux 网络命名空间深度实践](#linux 网络命名空间深度实践)
  2. [Namespace 隔离机制综合应用](#namespace 隔离机制综合应用)

第三部分:高级主题

  1. 内核源码级解析
  2. 性能基准测试与优化
  3. 生产环境故障排查
  4. 企业级最佳实践

附录


容器技术引入与背景

为什么需要容器技术?

应用部署的三大核心挑战
挑战 1: 环境一致性问题
┌─────────────────────────────────────────┐
│  开发环境    │  测试环境    │  生产环境  │
│  macOS      │  CentOS     │  Ubuntu    │
│  Node 16    │  Node 14    │  Node 12   │
│  Python 3.9 │  Python 2.7 │  Python 3.6│
│  Redis 6.2  │  Redis 3.2  │  Redis 4.0 │
└─────────────────────────────────────────┘

问题表现:
├─ "在我机器上能运行"
├─ 依赖库版本冲突
├─ 系统配置差异
└─ 部署失败率高达 30%

挑战 2: 资源利用率低下
物理机部署时代:
├─ CPU 利用率:5-15%
├─ 内存利用率:20-30%
├─ 磁盘利用率:30-40%
└─ 平均浪费率:70-85%

原因分析:
├─ 为峰值流量预留资源
├─ 应用孤岛无法共享
├─ 静态分配缺乏弹性
└─ 缺乏细粒度隔离

挑战 3: 部署效率低下
传统部署流程 (周级别):
├─ 资源申请:3-5 天
├─ 环境准备:5-7 天
├─ 应用部署:3-5 天
├─ 测试验证:3-5 天
└─ 总周期:2-4 周

业务影响:
├─ Time to Market 慢
├─ 无法快速响应市场
├─ 试错成本高昂
└─ 创新能力受限
虚拟化技术的演进路径
第一次虚拟化革命:硬件虚拟化

VM 方式:
┌─────────────────────────────────────────┐
│  VM1    │  VM2    │  VM3    │  VM4     │
│ GuestOS │ GuestOS │ GuestOS │ GuestOS │
└────┬────┴────────────┬───────────────┘
     │         │         │         │
┌────┴─────────┴─────────┴─────────┴─────┐
│         Hypervisor (VMM)                │
├─────────────────────────────────────────┤
│         Host OS (可选)                   │
├─────────────────────────────────────────┤
│         物理硬件                         │
└─────────────────────────────────────────┘

优势:
├─ 完全隔离:硬件级隔离
├─ 安全可控:独立内核
├─ 兼容性好:支持任意 OS
└─ 技术成熟:VMware/KVM

劣势:
├─ 资源开销大:完整 OS
├─ 启动速度慢:分钟级
├─ 镜像庞大:GB 级别
└─ 性能损失:5-10%

第二次虚拟化革命:操作系统级虚拟化

容器方式:
┌─────────────────────────────────────────┐
│ Container1│ Container2│ Container3     │
│  (PID NS) │  (PID NS) │  (PID NS)      │
└────┬──────┴────┬────────────┬─────────
     │          │              │
┌────┴──────────┴──────────────┴─────────┐
│         共享 Linux 内核                   │
├─────────────────────────────────────────┤
│         Namespace 隔离层                  │
│         (PID/NET/IPC/MNT/UTS/USER)      │
├─────────────────────────────────────────┤
│         物理硬件                         │
└─────────────────────────────────────────┘

优势:
├─ 极致轻量:MB 级别
├─ 秒级启动:<1 秒
├─ 零性能损失:原生执行
└─ 高密度部署:10 倍提升

劣势:
├─ 隔离性较弱:共享内核
├─ 安全风险:内核漏洞
└─ 需要内核兼容

容器技术的本质

容器 = Namespace 隔离 + CGroups 限制 + UnionFS 镜像

Namespace (隔离):
├─ 解决"看不见"问题
├─ 每个容器有自己的视图
├─ 进程、网络、文件系统隔离
└─ 互不干扰

CGroups (限制):
├─ 解决"用多少"问题
├─ CPU、内存、I/O 限制
├─ 防止资源耗尽
└─ QoS 保障

UnionFS (镜像):
├─ 解决"打包"问题
├─ 分层存储
├─ 写时复制
└─ 快速部署

核心技术对比:

特性          Namespace      CGroups      UnionFS
隔离对象      系统视图       资源使用     文件系统
隔离级别      进程级         资源级       文件级
性能开销      几乎为零       几乎为零     极低
启动速度      毫秒级         毫秒级       秒级
安全性        中等           高           高

容器技术前世今生

容器技术发展时间线

1979-2000: 萌芽期

1979: chroot 系统调用
├─ Unix V7 引入
├─ 文件系统隔离
├─ 只能隔离文件路径
└─ 安全性有限

1982: System V IPC
├─ 进程间通信命名空间
├─ 信号量、消息队列、共享内存
└─ 早期隔离尝试

2001-2007: 探索期

2001: Linux-VServer
├─ 第一个容器化方案
├─ 基于 chroot 增强
├─ 虚拟化 OS 概念
└─ 隔离性不完善

2004: Solaris Zones
├─ 生产级容器技术
├─ 完整隔离方案
├─ 资源限制 + 隔离
└─ 商业闭源系统

2005: OpenVZ
├─ 内核补丁方式
├─ 多实例支持
├─ 实时迁移
└─ 需要修改内核

2008-2013: 成熟期

2008: CGroups 主线内核
├─ Linux 2.6.24
├─ 资源限制标准化
├─ 容器技术里程碑
└─ Google 推动

2011: Cloud Foundry + Warden
├─ PaaS 平台兴起
├─ 容器标准化尝试
└─ 推动 Docker 诞生

2013: Docker 诞生
├─ PyCon 大会发布
├─ 开发者体验革命
├─ 镜像分层技术
└─ 生态快速形成

2014-至今:标准化与爆发

2014: OCI 开放容器标准
├─ Docker 捐赠 runtime
├─ 标准化规范
└─ 避免厂商锁定

2015: Kubernetes 崛起
├─ Google 开源编排系统
├─ 容器编排标准
└─ 云原生时代开启

2016: containerd 独立
├─ CNCF 托管
├─ 运行时标准化
└─ 生态多元化

2017: 云原生计算基金会
├─ 容器成为基础设施
├─ Service Mesh 兴起
└─ Serverless 容器

2020+: 新技术方向
├─ WebAssembly 容器
├─ 安全容器 (gVisor/Kata)
├─ 边缘容器
└─ 量子容器概念

容器技术三大流派

流派 1: 应用容器 (Application Containers)

代表:Docker、containerd、CRI-O
特点:
├─ 轻量级:共享内核
├─ 快速启动:秒级
├─ 高密度:单机百个
├─ 标准化:OCI 规范
└─ 生态丰富

适用场景:
├─ 微服务架构
├─ CI/CD流水线
├─ 开发测试环境
└─ 云原生应用

技术栈:
┌─────────────────────────┐
│      应用 A + 依赖        │
├─────────────────────────┤
│   运行时 (runc)         │
├─────────────────────────┤
│   容器引擎 (Docker)     │
├─────────────────────────┤
│   共享 Linux 内核         │
└─────────────────────────┘

流派 2: 系统容器 (System Containers)

代表:LXC/LXD、OpenVZ、Systemd-nspawn
特点:
├─ 完整系统:init 进程
├─ 多服务支持
├─ 接近 VM 体验
├─ 镜像较大 (百 MB-GB)
└─ 启动较慢 (10-30 秒)

适用场景:
├─ 虚拟机替代
├─ 完整 OS 环境
├─ 传统应用迁移
└─ 轻量级 VPS

技术栈:
┌─────────────────────────┐
│   完整用户空间           │
│   (systemd + 服务)       │
├─────────────────────────┤
│   容器初始化系统         │
├─────────────────────────┤
│   共享 Linux 内核         │
└─────────────────────────┘

流派 3: 安全容器 (Secure Containers)

代表:gVisor、Kata Containers、Firecracker
特点:
├─ 强隔离:用户态内核/轻量 VM
├─ 高安全:内核攻击面小
├─ 兼容 OCI 标准
├─ 性能略低 (5-15%)
└─ 启动较快 (1-5 秒)

适用场景:
├─ 多租户环境
├─ 不可信代码
├─ 高安全要求
└─ 公有云容器服务

技术架构对比:

Docker (应用容器):
容器 → runc → Linux 内核

gVisor (安全容器):
容器 → Sentry(用户态内核) → Gofer(文件系统) → 宿主内核

Kata Containers (轻量 VM):
容器 → Shim → Hypervisor → 轻量 VM → 内核 → 硬件

为什么 Docker 能成功?

Docker 成功的五大因素

因素 1: 开发者体验革命
├─ Dockerfile: 声明式镜像定义
├─ docker build: 一键构建
├─ docker run: 简单启动
└─ docker push/pull: 镜像分发

对比前 Docker 时代:
✗ 需要手动安装依赖
✗ 环境配置复杂
✗ 部署文档冗长
✓ Dockerfile 标准化
✓ 镜像可复用
✓ 一处构建处处运行

因素 2: 镜像分层技术
UnionFS 文件系统:
├─ 基础镜像层 (Ubuntu)
├─ 运行时层 (JDK/Python)
├─ 依赖层 (pip/npm 包)
├─ 应用层 (代码)
└─ 写时复制层

优势:
├─ 镜像复用:共享基础层
├─ 快速构建:缓存命中
├─ 增量更新:只传输差异
└─ 版本管理:镜像历史

因素 3: 生态系统建设
├─ Docker Hub: 镜像仓库
├─ Docker Compose: 编排工具
├─ Docker Swarm: 原生编排
├─ Docker Desktop: 开发工具
└─ 丰富文档和社区

因素 4: 标准化推动
├─ 捐赠 libcontainer 成立 OCI
├─ 推动容器运行时标准
├─ 镜像格式标准化
└─ 避免生态分裂

因素 5: 时机把握
├─ 微服务架构兴起
├─ DevOps 文化普及
├─ 云计算成熟
└─ 持续交付需求

Docker 技术架构演进:

Docker 0.1-0.9 (2013):
├─ 基于 LXC
├─ 包装器模式
└─ 功能简单

Docker 0.9-1.0 (2014):
├─ libcontainer 自研
├─ 解耦 LXC 依赖
└─ 生产就绪

Docker 1.0-1.10 (2014-2015):
├─ Docker Hub 上线
├─ Docker Compose
├─ Docker Swarm
└─ 生态爆发

Docker 1.10-17.03 (2016):
├─ containerd 抽离
├─ shim 架构
├─ 插件系统
└─ 企业版发布

Docker 17.03+ (2017+):
├─ Moby 项目
├─ LinuxKit
├─ 企业社区分家
└─ 专注开发者工具

Namespace 核心机制详解

Namespace 是什么?

Namespace 本质:Linux 内核的对象隔离机制

定义:
├─ 内核资源的封装与隔离
├─ 每个 Namespace 有独立的视图
├─ 进程只能看到同 Namespace 的资源
└─ 实现"各看各的,互不干扰"

类比理解:
┌─────────────────────────────────────────┐
│          大楼 (Linux 系统)                │
│  ┌───────────┬───────────┬───────────┐  │
│  │ 房间 A     │ 房间 B     │ 房间 C     │  │
│  │ (NS 1)    │ (NS 2)    │ (NS 3)    │  │
│  │           │           │           │  │
│  │ 住客人 A   │ 住客人 B   │ 住客人 C   │  │
│  │ (进程 A)   │ (进程 B)   │ (进程 C)   │  │
│  │           │           │           │  │
│  │ 只能看到   │ 只能看到   │ 只能看到   │  │
│  │ 房间内物品 │ 房间内物品 │ 房间内物品 │  │
│  └───────────┴───────────┴───────────┘  │
└─────────────────────────────────────────┘

每个房间:
├─ 独立的文件系统 (MNT NS)
├─ 独立的网络设备 (NET NS)
├─ 独立的进程树 (PID NS)
├─ 独立的主机名 (UTS NS)
└─ 互不干扰

Linux 六大 Namespace 详解

1. PID Namespace (进程隔离)
功能:隔离进程 ID 空间

核心特性:
├─ 每个 Namespace 有独立的 PID 编号
├─ 容器内 PID 从 1 开始
├─ 容器外看到全局 PID
└─ 父子关系跨 Namespace

创建方式:

// C 语言系统调用
#include <sched.h>
clone(CLONE_NEWPID, ...);

// unshare 命令
unshare --pid --fork /bin/bash

// Docker
docker run --pid=container:<name>

实际演示:

# 创建新的 PID Namespace
$ sudo unshare --pid --fork --mount-proc /bin/bash

# 在 Namespace 内查看进程
$ ps aux
PID USER     COMMAND
1 root     /bin/bash        # 第一个进程
2 root     ps aux           # 只有 2 个进程

# 在 Namespace 外查看
$ ps aux | grep bash
... 12345 root ... /bin/bash  # 实际 PID 是 12345

进程树结构:

全局 Namespace:
systemd(1) ─┬─ sshd(100)
            ├─ docker(500) ── containerd(510)
            │                └─ runc(520) ── app(1) ← 容器内 PID 1
            │                               └─ worker(2) ← 容器内 PID 2
            └─ ...

容器内 Namespace:
app(1) ── worker(2)
        └─ ...

关键限制:
✗ 不能反向查看:容器内看不到容器外进程
✗ 不能反向控制:容器内不能 kill 容器外进程
✓ 可以正向查看:容器外可以看到容器内进程 (真实 PID)
✓ 可以正向控制:容器外可以 kill 容器内进程

init 进程特殊职责:
容器内 PID 1 进程必须:
├─ 回收僵尸进程
├─ 处理信号 (SIGTERM/SIGKILL)
├─ 等待子进程退出
└─ 否则会导致资源泄漏

Docker 实践:
# 查看容器的 PID Namespace
$ docker inspect <container> | grep Pid

# 进入容器的 PID Namespace
$ nsenter -t <pid> -p /bin/bash

# 容器内运行多个进程
$ docker exec -it <container> /bin/bash
2. NET Namespace (网络隔离)
功能:隔离网络设备、协议栈、端口空间

核心资源:
├─ 网络设备 (eth0, lo, ...)
├─ IP 地址和路由表
├─ 端口号 (1-65535)
├─ 防火墙规则 (iptables)
├─ 套接字 (socket)
└─ /proc/net 目录

创建方式:

// C 语言
clone(CLONE_NEWNET, ...);

// unshare 命令
unshare --net /bin/bash

// Docker
docker run --net=bridge|host|none

网络隔离效果:

容器 A (NET NS 1):
├─ eth0: 172.17.0.2/16
├─ lo: 127.0.0.1
├─ 端口:80, 443
└─ 路由:default via 172.17.0.1

容器 B (NET NS 2):
├─ eth0: 172.17.0.3/16
├─ lo: 127.0.0.1
├─ 端口:80, 443 (可重复使用!)
└─ 路由:default via 172.17.0.1

宿主机:
├─ docker0: 172.17.0.1/16
├─ eth0: 192.168.1.100
└─ 端口:任意 (不与容器冲突)

端口复用演示:

# 宿主机运行 nginx 在 80 端口
$ sudo nginx  # 监听 0.0.0.0:80

# 容器 A 也可以运行 nginx 在 80 端口
$ docker run -d nginx  # 容器内监听 0.0.0.0:80

# 容器 B 同样可以
$ docker run -d nginx  # 容器内监听 0.0.0.0:80

# 三个 80 端口互不冲突!

详细网络命名空间实践见第 4 节
3. MNT Namespace (文件系统隔离)
功能:隔离挂载点视图

核心特性:
├─ 独立的挂载点列表
├─ 独立的文件系统视图
├─ 不影响其他 Namespace
└─ 类似 chroot 但更强

创建方式:

// C 语言
clone(CLONE_NEWNS, ...);

// unshare 命令
unshare --mount /bin/bash

// Docker
docker run -v /host/path:/container/path

挂载隔离演示:

# 宿主机挂载
$ mount /dev/sdb1 /data

# 创建新的 MNT Namespace
$ sudo unshare --mount /bin/bash

# 在 Namespace 内挂载 (不影响外部)
$ mount --bind /tmp /mnt

# Namespace 内查看
$ mount | grep /mnt
/tmp on /mnt type ext4

# Namespace 外查看
$ mount | grep /mnt
# 什么都没有!

Docker 中的应用:

容器文件系统:
├─ 根文件系统:/ (UnionFS)
├─ 只读镜像层
├─ 可写容器层
├─ 挂载卷:/data
└─ 绑定挂载:/host/config:/etc/app

# 容器内只能看到自己的文件系统
$ docker run -it ubuntu /bin/bash
$ ls /
bin  boot  dev  etc  home  ...
$ ls /data  # 除非挂载,否则不存在

propagation 模式:

private (默认):
├─ 挂载事件不传播
├─ 完全隔离
└─ Docker 使用此模式

shared:
├─ 挂载事件传播到副本
├─ 可以共享挂载
└─ 用于特殊场景

slave:
├─ 单向传播
├─ 接收外部挂载
└─ 有限共享
4. UTS Namespace (主机名隔离)
功能:隔离主机名和域名

核心资源:
├─ hostname (主机名)
├─ domainname (域名)
└─ /etc/hostname 文件

创建方式:

// C 语言
clone(CLONE_NEWUTS, ...);

// unshare 命令
unshare --uts /bin/bash

// Docker
docker run --hostname=mycontainer

实际演示:

# 宿主机主机名
$ hostname
myserver.example.com

# 创建 UTS Namespace
$ sudo unshare --uts /bin/bash

# 修改主机名 (只影响当前 Namespace)
$ hostname mycontainer
$ cat /etc/hostname
mycontainer

# Namespace 外不受影响
$ hostname
myserver.example.com

Docker 应用:

# 容器有独立主机名
$ docker run -it --hostname=web01 ubuntu
root@web01:/# hostname
web01

# 默认使用容器 ID
$ docker run -it ubuntu
root@a1b2c3d4e5f6:/# hostname
a1b2c3d4e5f6

# 使用宿主机主机名
$ docker run -it --hostname=host ubuntu
5. IPC Namespace (进程间通信隔离)
功能:隔离 System V IPC 和 POSIX 消息队列

隔离资源:
├─ 信号量 (semaphores)
├─ 消息队列 (message queues)
├─ 共享内存 (shared memory)
└─ POSIX 消息队列

创建方式:

// C 语言
clone(CLONE_NEWIPC, ...);

// unshare 命令
unshare --ipc /bin/bash

// Docker
docker run --ipc=private|host

IPC 对象隔离:

Namespace A:
├─ 信号量 ID: 0, 1, 2
├─ 消息队列 ID: 0, 1
└─ 共享内存 ID: 0

Namespace B:
├─ 信号量 ID: 0, 1  (独立的!)
├─ 消息队列 ID: 0  (独立的!)
└─ 共享内存 ID: 0  (独立的!)

实际演示:

# 创建 IPC Namespace
$ sudo unshare --ipc /bin/bash

# 创建共享内存
$ ipcmk -M 1024
0  # Namespace 内 ID 为 0

# 查看 IPC 对象
$ ipcs -m

# Namespace 外查看
$ ipcs -m
# 看不到 Namespace 内的对象

Docker 应用:

# 默认隔离 IPC
$ docker run -d app

# 共享 IPC (用于高性能场景)
$ docker run --ipc=host app

# 容器间共享 IPC
$ docker run --ipc=container:<name> app
6. USER Namespace (用户权限隔离)
功能:隔离用户和组 ID

核心特性:
├─ 独立的 UID/GID 空间
├─ 容器内 root ≠ 宿主 root
├─ 权限映射机制
└─ 最安全的 Namespace

创建方式:

// C 语言
clone(CLONE_NEWUSER, ...);

// unshare 命令 (需要特权)
unshare --user /bin/bash

// Docker
docker run --userns=host

UID 映射机制:

容器内 UID    映射关系    宿主机 UID
    0        ──────→      100000  (root → nobody)
    1        ──────→      100001
    ...      ──────→      ...
    65535    ──────→      165535

映射配置 (/etc/subuid):
username:100000:65536

实际演示:

# 创建 USER Namespace
$ sudo unshare --user /bin/bash

# 容器内是 root
$ whoami
root

# 但实际权限受限
$ cat /etc/shadow
Permission denied

# 查看真实 UID
$ cat /proc/self/uid_map
        0    100000    65536

Docker 安全增强:

# 默认启用 USER Namespace (可选)
$ docker run --userns=remap app

# 容器内 root 操作
rm -rf /  # 只影响容器

# 实际映射到宿主机的非特权用户
# 无法破坏宿主机系统

优势:
├─ 最小权限原则
├─ 防止提权攻击
├─ 容器逃逸防护
└─ 多租户安全

Namespace 系统调用详解

核心系统调用 (5 个):

1. clone() - 创建时指定 Namespace
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include <sched.h>
int clone(int (*fn)(void *), void *stack, 
          int flags, void *arg, ...);

flags 参数:
├─ CLONE_NEWPID   创建 PID Namespace
├─ CLONE_NEWNET   创建 NET Namespace
├─ CLONE_NEWNS    创建 MNT Namespace
├─ CLONE_NEWUTS   创建 UTS Namespace
├─ CLONE_NEWIPC   创建 IPC Namespace
├─ CLONE_NEWUSER  创建 USER Namespace
└─ 可以组合使用

示例代码:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

#define STACK_SIZE (1024*1024)

static int child_func(void *arg) {
    printf("子进程在 Namespace 中运行\n");
    system("bash");
    return 0;
}

int main() {
    char *stack = malloc(STACK_SIZE);
    
    // 创建 PID + NET + MNT Namespace
    int flags = CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWNS;
    
    pid_t pid = clone(child_func, 
                      stack + STACK_SIZE,
                      flags | SIGCHLD, 
                      NULL);
    
    waitpid(pid, NULL, 0);
    free(stack);
    return 0;
}

2. unshare() - 当前进程脱离 Namespace
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include <sched.h>
int unshare(int flags);

用法:
├─ 当前进程创建新 Namespace
├─ 后续子进程在 Namespace 中
└─ 常用于 shell

示例:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 创建新的 PID Namespace
if (unshare(CLONE_NEWPID) == -1) {
    perror("unshare");
    exit(1);
}

// fork 后第一个进程是 PID 1
if (fork() == 0) {
    execvp("/bin/bash", ...);
}

3. setns() - 加入已有 Namespace
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include <sched.h>
int setns(int fd, int nstype);

参数:
├─ fd: Namespace 文件描述符
├─ nstype: Namespace 类型 (或 0)
└─ 返回:0 成功,-1 失败

使用场景:
├─ 进入容器 Namespace
├─ 进程迁移
└─ 调试工具

示例:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 打开目标 Namespace
int fd = open("/proc/1234/ns/pid", O_RDONLY);

// 加入该 Namespace
if (setns(fd, CLONE_NEWPID) == -1) {
    perror("setns");
}

// 现在可以看到 PID 1234 的进程视图
close(fd);

4. ioctl() - 查询 Namespace
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include <sys/ioctl.h>
#include <sched.h>

ioctl(fd, NS_GET_NSTYPE, &type);
ioctl(fd, NS_GET_OWNER_UID, &uid);
ioctl(fd, NS_GET_USERNS, &userns_fd);

5. pidfd_open() + pidfd_getfd() - Linux 5.6+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 获取进程的 Namespace 文件描述符
int ns_fd = pidfd_getfd(pidfd, PIDFD_GET_NS, 0);

Namespace 文件系统设计

/proc/[pid]/ns/ 目录结构:

每个进程的命名空间信息:
$ ls -la /proc/1234/ns/
total 0
lrwxrwxrwx 1 root root 0 Mar 10 10:00 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Mar 10 10:00 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx 1 root root 0 Mar 10 10:00 mnt -> 'mnt:[4026531840]'
lrwxrwxrwx 1 root root 0 Mar 10 10:00 net -> 'net:[4026531992]'
lrwxrwxrwx 1 root root 0 Mar 10 10:00 pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Mar 10 10:00 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Mar 10 10:00 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Mar 10 10:00 uts -> 'uts:[4026531838]'

格式说明:
├─ 文件名:Namespace 类型
├─ 箭头值:type:[inode_number]
└─ inode 相同 = 同一 Namespace

实战技巧:

1. 查看进程的 Namespace
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ readlink /proc/1234/ns/pid
pid:[4026531836]

# 比较两个进程是否同 Namespace
$ readlink /proc/1234/ns/pid
pid:[4026531836]
$ readlink /proc/5678/ns/pid
pid:[4026531836]  # 相同!

2. 获取 Namespace 文件描述符
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 打开 Namespace 文件
$ ns_fd=$(sudo open /proc/1234/ns/pid)

# 用于 setns() 加入

3. 持久化 Namespace
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 绑定挂载到文件系统
$ mkdir -p /var/run/netns
$ mount --bind /proc/1234/ns/net /var/run/netns/custom

# 现在可以用 ip netns 管理
$ ip netns list
custom

4. Namespace 权限检查
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ ls -la /proc/1234/ns/
# 需要 CAP_SYS_ADMIN 权限才能操作

Linux 网络命名空间深度实践

网络命名空间基础

什么是网络命名空间?

定义:
├─ 独立的网络协议栈
├─ 独立的网络设备
├─ 独立的 IP 地址
├─ 独立的路由表
├─ 独立的端口空间
├─ 独立的防火墙规则
└─ 完全隔离的网络环境

核心价值:
├─ 网络隔离:容器间不可见
├─ 端口复用:多个容器可用相同端口
├─ 虚拟网络:构建复杂网络拓扑
└─ 安全边界:网络策略隔离

创建网络命名空间:

方法 1: ip netns 命令
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 创建命名空间
$ sudo ip netns add ns1
$ sudo ip netns add ns2

# 查看命名空间
$ ip netns list
ns1
ns2

# 删除命名空间
$ sudo ip netns del ns1

方法 2: unshare 命令
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 创建并进入网络命名空间
$ sudo unshare --net /bin/bash

# 验证
$ ip link show
1: lo: <LOOPBACK> link/loopback 00:00:00:00:00:00
# 只有 lo 接口!

方法 3: C 语言
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include <sched.h>
clone(CLONE_NEWNET, ...);

由于篇幅限制,让我创建文档的第二部分,包含网络命名空间的深入实践和综合应用:

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐