2、Linux网络命名空间基础:创建、删除、配置网络命名空间
网络命名空间(Network Namespace)是 Linux 内核提供的一项轻量级虚拟化技术,它允许在同一个物理主机上创建多个独立的网络栈实例。每个网络命名空间拥有自己独立的网络设备、IP 地址、路由表、防火墙规则(iptables/nftables)、套接字(socket)以及网络协议栈状态。容器技术的核心基石之一正是网络命名空间,它确保了容器之间网络环境的隔离性。
2.1 网络命名空间的核心隔离对象
当创建一个新的网络命名空间时,内核会为该空间复制一套完整的网络资源。下表列出了网络命名空间隔离的关键资源对象:
| 资源对象 | 隔离说明 | 默认初始状态 |
|---|---|---|
| 网络设备 | 物理网卡、虚拟网卡(veth/tun/tap)、网桥等设备只能属于一个命名空间 | 仅有 lo(回环)设备,且默认 DOWN |
| IP 地址 | 每个命名空间独立配置 IPv4/IPv6 地址,互不干扰 | 无 IP 地址 |
| 路由表 | 独立的路由选择策略,包括默认网关、静态路由 | 空路由表 |
| 防火墙规则 | 独立的 iptables/nftables 规则链 | 空规则集 |
| 套接字缓冲区 | TCP/UDP 连接、Unix Domain Socket 完全隔离 | 无监听端口 |
| /proc/net 与 /sys/class/net | 进程看到的网络文件系统视图不同 | 仅包含 lo |
2.2 创建与删除网络命名空间
Linux 提供了 ip netns 命令集来管理网络命名空间。该命令集是 iproute2 工具包的一部分,也是目前最标准的管理方式。
2.2.1 创建命名空间
使用 ip netns add 命令创建一个新的网络命名空间:
# 创建一个名为 ns1 的网络命名空间
sudo ip netns add ns1
# 查看系统中已有的网络命名空间
sudo ip netns list
创建成功后,系统会在 /var/run/netns/ 目录下生成一个同名的挂载点文件,用于绑定该命名空间的生命周期。
2.2.2 删除命名空间
使用 ip netns delete 命令删除一个已存在的网络命名空间:
# 删除名为 ns1 的网络命名空间
sudo ip netns delete ns1
ip netns delete 命令会失败,并提示“无法删除”。此时需要先终止该空间内的所有进程,或使用 ip netns pids 查看并清理。
2.3 在命名空间中执行命令
创建命名空间后,需要进入该空间执行网络配置命令。ip netns exec 是进入指定命名空间执行命令的标准方式:
# 在 ns1 中查看网络设备
sudo ip netns exec ns1 ip link show
# 在 ns1 中查看路由表
sudo ip netns exec ns1 ip route show
# 在 ns1 中启动回环设备
sudo ip netns exec ns1 ip link set lo up
# 在 ns1 中启动一个交互式 Shell
sudo ip netns exec ns1 bash
当使用 bash 进入交互式 Shell 后,后续所有命令都默认在 ns1 命名空间中执行,直到输入 exit 退出。
2.4 配置网络命名空间的基本网络栈
一个刚创建的网络命名空间只有 lo(回环)设备,且处于 DOWN 状态。要让该命名空间具备基本的网络通信能力,需要完成以下配置步骤:
- 启动回环设备:确保本地进程间通信可用。
- 创建 veth 对:将一端放入命名空间,另一端留在根命名空间(默认命名空间)。
- 分配 IP 地址:为 veth 两端配置 IP 地址。
- 启用设备:将 veth 设备状态设置为 UP。
- 配置路由:添加默认网关或静态路由。
以下是一个完整的配置示例,将 ns1 连接到根命名空间:
# 1. 创建 veth 对,一端名为 veth0,另一端名为 veth1
sudo ip link add veth0 type veth peer name veth1
# 2. 将 veth1 移动到 ns1 命名空间
sudo ip link set veth1 netns ns1
# 3. 在根命名空间中配置 veth0
sudo ip addr add 192.168.100.1/24 dev veth0
sudo ip link set veth0 up
# 4. 在 ns1 中配置 veth1
sudo ip netns exec ns1 ip addr add 192.168.100.2/24 dev veth1
sudo ip netns exec ns1 ip link set veth1 up
sudo ip netns exec ns1 ip link set lo up
# 5. 验证连通性
sudo ip netns exec ns1 ping -c 3 192.168.100.1
ping 命令将成功收到来自 192.168.100.1 的回复。这表明 ns1 已经通过 veth 对与根命名空间建立了二层网络连接。
2.5 网络命名空间与 veth 对的结构关系
下图展示了根命名空间与子命名空间通过 veth 对进行连接的典型拓扑结构:
2.6 查看与调试网络命名空间
在实际运维和开发过程中,经常需要查看命名空间的状态信息。以下是一些常用的调试命令:
| 命令 | 功能说明 | 示例输出(部分) |
|---|---|---|
ip netns list |
列出所有网络命名空间 | ns1 (id: 0) |
ip netns identify <PID> |
查看指定进程所属的网络命名空间 | ns1 |
ip netns pids <NAME> |
列出指定命名空间中的所有进程 PID | 12345 |
nsenter -t <PID> -n ip addr |
通过进程 PID 进入其命名空间查看网络 | 显示该命名空间的 IP 地址 |
lsns -t net |
列出所有网络命名空间及其关联进程 | 显示命名空间号、进程数等 |
ip netns exec 进入命名空间后,可以通过 cat /proc/$$/net/dev 查看该空间内的网络设备统计信息。这与在根命名空间中查看 /proc/net/dev 是完全不同的视图。
2.7 网络命名空间的持久化与生命周期
网络命名空间的默认生命周期与 /var/run/netns/<NAME> 文件绑定。只要该文件存在,命名空间就不会被销毁。即使创建该命名空间的进程已经退出,命名空间依然存活。这一特性使得网络命名空间非常适合用于容器场景:
- 持久化:通过
ip netns add创建的命名空间会一直存在,直到显式执行ip netns delete。 - 临时命名空间:使用
unshare -n创建的命名空间,在最后一个进程退出后自动销毁。 - 容器集成:Docker/containerd 等容器运行时在创建容器时,会通过
unshare()系统调用创建新的网络命名空间,并将其持久化到容器生命周期中。