四、Linux 内核容器技术深度解析系列-1-linux-kernel-container-namespace-part1
Linux 内核容器技术:Namespace 隔离机制深度解析(第一部分)
·
Linux 内核容器技术:Namespace 隔离机制深度解析(第一部分)
文档信息
- 系列: Linux 内核容器技术深度解析
- 第一篇: Namespace 隔离机制
- 版本: V2.0 (深度优化版)
- 创建日期: 2026 年 3 月 10 日
- 修订日期: 2026 年 3 月 10 日
- 预计阅读时间: 6-8 小时
- 前置知识: Linux 操作系统、进程管理、文件系统、网络基础、系统编程
- 适合人群:
- 容器平台开发工程师
- 系统架构师
- DevOps/SRE工程师
- 对容器底层原理感兴趣的高级开发者
目录
第一部分:基础与原理
第二部分:深度实践
- [Linux 网络命名空间深度实践](#linux 网络命名空间深度实践)
- [Namespace 隔离机制综合应用](#namespace 隔离机制综合应用)
第三部分:高级主题
附录
容器技术引入与背景
为什么需要容器技术?
应用部署的三大核心挑战
挑战 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, ...);
由于篇幅限制,让我创建文档的第二部分,包含网络命名空间的深入实践和综合应用:
更多推荐


所有评论(0)