2. Linux 网络命名空间基础:理解 Network Namespace 概念,使用 ip netns 命令创建、删除、管理命名空间,实现基本的网络隔离。
2.1 什么是 Network Namespace?
Network Namespace(网络命名空间)是 Linux 内核提供的一项轻量级虚拟化技术,用于实现网络栈的隔离。每个 Network Namespace 拥有独立的网络设备、IP 地址、路由表、防火墙规则(iptables/ip6tables)、网络栈状态以及套接字(socket)实例。简单来说,一个 Network Namespace 就是一个独立的“网络沙箱”。
在默认情况下,Linux 系统启动后所有进程共享同一个网络命名空间(称为 root namespace 或 default namespace)。通过创建新的 Network Namespace,我们可以让进程“看到”完全不同的网络环境,从而实现多租户隔离、容器网络、测试环境模拟等高级功能。
2.2 Network Namespace 隔离了什么?
下表列出了 Network Namespace 隔离的关键网络资源,以及它们在不同命名空间之间的独立性:
| 资源类型 | 隔离内容 | 是否独立 | 典型用途 |
|---|---|---|---|
| 网络设备 | eth0, lo, veth, bridge, tun/tap 等 | 完全独立 | 每个命名空间拥有自己的网卡和回环接口 |
| IP 地址 | IPv4/IPv6 地址配置 | 完全独立 | 不同命名空间可使用相同 IP 段而不冲突 |
| 路由表 | FIB (Forwarding Information Base) | 完全独立 | 每个命名空间可定义独立的路由策略 |
| 防火墙规则 | iptables, ip6tables, nftables 规则集 | 完全独立 | 隔离的网络安全策略 |
| 套接字 | TCP/UDP/RAW socket 监听与连接 | 完全独立 | 同一端口可在不同命名空间被不同进程使用 |
| /proc/net | /proc/net/dev, /proc/net/tcp 等 | 完全独立 | 每个命名空间看到自己的网络统计 |
| sysctl 网络参数 | net.ipv4.ip_forward, net.core.somaxconn 等 | 部分独立 | 部分参数可独立配置,部分继承自 root namespace |
2.3 Network Namespace 的层级关系与生命周期
Network Namespace 在 Linux 内核中通过 struct net 结构体表示,所有命名空间形成一个树形结构,但实际访问时通过文件系统路径 /var/run/netns/ 或 /proc/PID/ns/net 来引用。下图展示了命名空间之间的典型关系:
ip netns exec 或通过 mount --bind /var/run/netns/<name> 方式保持引用。
2.4 使用 ip netns 命令管理命名空间
ip netns 是 iproute2 工具包中专门用于管理 Network Namespace 的命令行工具。它提供了创建、删除、列出、执行命令等完整操作。以下是核心命令及其功能:
| 命令 | 功能描述 | 示例 |
|---|---|---|
ip netns add <name> |
创建一个新的 Network Namespace | ip netns add red |
ip netns delete <name> |
删除指定的 Network Namespace | ip netns delete red |
ip netns list |
列出系统中所有 Network Namespace | ip netns list |
ip netns exec <name> <cmd> |
在指定命名空间中执行命令 | ip netns exec red ip addr |
ip netns identify <PID> |
查看指定进程所属的命名空间名称 | ip netns identify 1234 |
ip netns pids <name> |
列出指定命名空间中的所有进程 PID | ip netns pids red |
ip netns monitor |
监控命名空间的创建和删除事件 | ip netns monitor |
2.5 实战:创建与管理命名空间
下面通过一个完整的操作序列,演示如何创建、查看、进入和删除 Network Namespace。请以 root 权限执行以下命令:
步骤 1:创建两个命名空间
# 创建名为 red 和 blue 的两个网络命名空间
ip netns add red
ip netns add blue
# 验证创建结果
ip netns list
输出示例:
red
blue
步骤 2:查看命名空间中的网络设备
# 查看默认命名空间的网络设备(包含所有物理和虚拟设备)
ip link list
# 查看 red 命名空间的网络设备(只有 lo 设备)
ip netns exec red ip link list
# 查看 blue 命名空间的网络设备
ip netns exec blue ip link list
lo(回环)设备,且状态为 DOWN。这意味着该命名空间目前无法进行任何网络通信,包括本机回环通信。
步骤 3:启动回环接口
# 在 red 命名空间中启用 lo 接口
ip netns exec red ip link set lo up
# 验证 lo 接口状态
ip netns exec red ip link show lo
# 测试回环通信
ip netns exec red ping 127.0.0.1 -c 2
步骤 4:在命名空间中执行任意命令
# 在 red 命名空间中启动一个 bash shell
ip netns exec red bash
# 此时 shell 提示符可能不变,但网络环境已隔离
# 查看当前命名空间的网络栈
cat /proc/net/dev
ip route show
iptables -L -n
# 退出命名空间
exit
ip netns exec <name> bash 可以“进入”一个命名空间,后续所有命令都在该命名空间中执行。退出 bash 后,命名空间中的进程结束,但命名空间本身仍然存在(因为 ip netns 通过 bind mount 持久化了它)。
步骤 5:删除命名空间
# 删除 red 命名空间
ip netns delete red
# 验证删除
ip netns list
# 清理 blue 命名空间
ip netns delete blue
2.6 命名空间之间的通信:veth 对的基本原理
默认情况下,不同 Network Namespace 之间是完全隔离的,无法直接通信。要实现跨命名空间通信,最常用的方法是使用 veth(Virtual Ethernet)对。veth 是一对虚拟网卡,像一根“网线”的两端:一端放入一个命名空间,另一端放入另一个命名空间(或 root namespace),数据包从一端进入就会从另一端出来。
- 成对出现: 创建 veth 对时,内核同时生成两个端点,分别称为 veth0 和 veth1(或自定义名称)。
- 数据直通: 从一端发出的数据包,内核直接将其注入到另一端的接收队列,不经过物理网络。
- 命名空间可迁移: 创建后,可以将 veth 的一端移动到另一个命名空间,实现跨命名空间连接。
- 无广播域隔离: veth 对是点对点连接,不传递广播帧(除非通过 bridge 桥接)。
2.7 实战:使用 veth 对连接两个命名空间
以下命令序列演示如何创建 veth 对,并将其两端分别放入 red 和 blue 命名空间,实现两个隔离网络之间的通信:
# 1. 创建两个命名空间
ip netns add red
ip netns add blue
# 2. 创建 veth 对(两端默认在 root namespace 中)
ip link add veth-red type veth peer name veth-blue
# 3. 将 veth 两端分别移入命名空间
ip link set veth-red netns red
ip link set veth-blue netns blue
# 4. 为 veth 接口配置 IP 地址并启用
ip netns exec red ip addr add 10.0.1.1/24 dev veth-red
ip netns exec red ip link set veth-red up
ip netns exec red ip link set lo up
ip netns exec blue ip addr add 10.0.1.2/24 dev veth-blue
ip netns exec blue ip link set veth-blue up
ip netns exec blue ip link set lo up
# 5. 测试连通性
ip netns exec red ping 10.0.1.2 -c 3
# 6. 查看路由表确认
ip netns exec red ip route
ip netns exec blue ip route
# 7. 清理
ip netns delete red
ip netns delete blue
预期输出(ping 部分):
PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.
64 bytes from 10.0.1.2: icmp_seq=1 ttl=64 time=0.089 ms
64 bytes from 10.0.1.2: icmp_seq=2 ttl=64 time=0.072 ms
64 bytes from 10.0.1.2: icmp_seq=3 ttl=64 time=0.068 ms
--- 10.0.1.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2042ms
- ping 不通: 检查 veth 接口是否已 up(
ip netns exec <name> ip link show),以及 IP 地址是否配置正确。 - RTNETLINK answers: File exists: 表示命名空间或 veth 对已存在,先删除再创建。
- Cannot find device "veth-red": 确认 veth 对已创建且未被移入其他命名空间。
- 操作权限: 所有
ip netns和ip link操作需要 root 权限。
2.8 命名空间的持久化与文件系统视图
Network Namespace 在 Linux 中通过 /proc/PID/ns/net 文件表示。每个进程的 /proc/PID/ns/net 是一个符号链接,指向内核中该命名空间的唯一标识符。通过比较这些链接的 inode 号,可以判断两个进程是否在同一个命名空间中。
# 查看当前 shell 的命名空间标识
ls -l /proc/$$/ns/net
# 在 red 命名空间中查看标识
ip netns exec red ls -l /proc/$$/ns/net
# 比较两个命名空间的 inode 号
stat -L /proc/$$/ns/net
ip netns exec red stat -L /proc/$$/ns/net
ip netns 命令通过 /var/run/netns/ 目录下的 bind mount 来持久化命名空间。当你执行 ip netns add red 时,系统会:
- 创建一个新的 Network Namespace。
- 在
/var/run/netns/下创建一个名为red的文件。 - 通过
mount --bind /proc/PID/ns/net /var/run/netns/red将命名空间绑定挂载到该文件。
这样,即使命名空间中的所有进程退出,由于 bind mount 的存在,内核不会销毁该命名空间。
2.9 本章小结与知识图谱
通过本章的学习,你已经掌握了 Network Namespace 的核心概念和基本操作。以下是本章的知识结构总结:
| 知识点 | 核心内容 | 掌握程度 |
|---|---|---|
| Network Namespace 概念 | 独立的网络栈、设备、路由、防火墙、套接字 | 理解 |
| 隔离资源清单 | 网卡、IP、路由表、iptables、socket、/proc/net | 记忆 |
| ip netns 命令 | add, delete, list, exec, identify, pids | 熟练使用 |
| veth 对原理 | 成对出现、数据直通、跨命名空间迁移 | 理解 |
| 跨命名空间通信 | 创建 veth 对、分配 IP、启用接口、ping 测试 | 熟练操作 |
| 命名空间生命周期 | 进程退出销毁、bind mount 持久化、/var/run/netns/ | 理解 |