🔍搜索⌘K

Linux 网络命名空间(NetNS)完全指南:从基础操作到跨命名空间通信

概述

在 Linux 系统里,命名空间(Namespace) 是实现“资源隔离”的核心技术之一,而 网络命名空间(Network Namespace,简称 NetNS) 专门用来隔离网络资源——每个 NetNS 都有自己独立的网络设备(比如网卡)、IP 地址、路由表、防火墙规则和端口号,就像一个“独立的小网络环境”。

不管是 Docker、Kubernetes 这些容器技术的网络隔离,还是开发环境里“多网络环境模拟”(比如同时测不同网段的服务),都靠 NetNS 撑着。新手经常因为不熟悉 NetNS 的基础操作和跨命名空间通信逻辑,导致隔离环境配不起来。

这篇从“基础操作”一直讲到“实战案例”,系统说说 NetNS 的创建 / 删除 / 查看 / 执行命令这几个核心用法,再用一个“双命名空间跨设备通信”的案例,帮你搞懂 NetNS 隔离与互联的底层逻辑,把 Linux 网络隔离这个关键技能拿下。

一、NetNS 基础操作:4 个核心命令

NetNS 的所有操作都通过 ip netns 命令完成(需要 root 权限,用 sudo 执行),下面是最常用的 4 类操作,每个都配了“命令格式 + 功能说明 + 示例验证”:

1. 创建命名空间(add)

功能:新建一个网络命名空间,初始状态下里面只有一个“回环设备(lo)”,而且 lo 默认是“关闭(DOWN)”状态。

命令格式:

bash sudo ip netns add [命名空间名称]

示例:创建名为 test1 的网络命名空间

# 创建命名空间 test1
sudo ip netns add test1

# 验证创建结果:查看系统中所有 NetNS,若显示 test1 则创建成功
sudo ip netns list
# 预期输出:test1

2. 删除命名空间(del)

功能:删掉一个已经存在、且里面没有正在运行进程的命名空间(如果命名空间里还有进程在跑,得先把进程干掉才能删)。

命令格式:

bash sudo ip netns del [命名空间名称]

示例:删除名为 test1 的网络命名空间

# 删除命名空间 test1
sudo ip netns del test1

# 验证删除结果:再次查看 NetNS,若无 test1 则删除成功
sudo ip netns list
# 预期输出:(空,无任何内容)

注意:如果删除时提示 Cannot delete namespace “test1”: Device or resource busy,说明命名空间里还有进程在跑(比如通过 ip netns exec 启动的 shell),得先用 ps aux | grep test1 找到进程并 kill 掉,再删。

3. 查看命名空间(list)

功能:列出系统里所有已经创建好的网络命名空间,快速确认命名空间在不在。

命令格式:

sudo ip netns list
# 或简写为
sudo ip netns

示例:查看当前系统中的 NetNS

bash
# 先创建两个命名空间 test1、test2
sudo ip netns add test1
sudo ip netns add test2

# 查看所有 NetNS
sudo ip netns list
# 预期输出:
# test2
# test1

4. 在命名空间内执行命令(exec)

功能:在指定的网络命名空间里执行命令(比如查看网络设备、配置 IP、启动服务),这是操作 NetNS 内部网络的核心方式。

命令格式:

sudo ip netns exec [命名空间名称] [待执行命令]

常用场景与示例:

场景 1:查看命名空间内的网络设备

默认新创建的 NetNS 里只有回环设备 lo,而且处于关闭状态:

# 查看 test1 命名空间内的网络设备
sudo ip netns exec test1 ip link
# 预期输出:
# 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
#     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

场景 2:启用命名空间内的回环设备(lo)

回环设备(lo)是给命名空间内部进程之间通信用的(比如本地服务 127.0.0.1),得手动把它启用:

# 启用 test1 命名空间内的 lo 设备
sudo ip netns exec test1 ip link set dev lo up

# 验证启用状态:查看 lo 设备的 state 是否为 UP
sudo ip netns exec test1 ip link show lo
# 预期输出:
# 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
#     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

场景 3:在命名空间内启动 shell(方便多命令操作)

要是需要在 NetNS 里执行多条命令,可以直接起一个 bash 或 sh 终端,省得每次都重复敲 ip netns exec:

# 在 test1 命名空间内启动 bash 终端
sudo ip netns exec test1 bash

# 进入终端后,所有命令都在 test1 命名空间内执行
# 示例:查看 IP 地址(此时 lo 设备已启用,但无 IP)
ip addr show lo
# 预期输出:
# 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
#     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
#     inet 127.0.0.1/8 scope host lo
#        valid_lft forever preferred_lft forever
#     inet6 ::1/128 scope host
#        valid_lft forever preferred_lft forever

# 退出命名空间终端:执行 exit
exit

二、实战案例:跨命名空间通信(VETH 设备对)

NetNS 的核心价值是“隔离”,但实际场景中经常又需要“隔离环境之间能通信”(比如容器 A 访问容器 B 的服务)。实现跨 NetNS 通信最常用的方法就是 VETH 设备对(Virtual Ethernet Pair)——它就像一根“虚拟网线”,两端分别接两个命名空间,数据就能互通了。

下面通过“创建 test1 和 test2 两个命名空间,用 VETH 设备对实现跨命名空间 ping 通”这个案例,把完整配置流程走一遍:

步骤 1:创建两个网络命名空间

先把 test1 和 test2 这两个命名空间建好,作为通信的两端:

sudo ip netns add test1
sudo ip netns add test2

步骤 2:创建 VETH 设备对

创建一对 VETH 设备(命名为 veth-test1 和 veth-test2),它们就相当于“虚拟网线”的两端:

# 创建 VETH 设备对:veth-test1 和 veth-test2
sudo ip link add veth-test1 type veth peer name veth-test2

# 验证 VETH 设备创建:查看主机网络设备,应包含这两个设备
sudo ip link show | grep veth
# 预期输出:
# 6: veth-test2@veth-test1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
# 7: veth-test1@veth-test2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  • 注:VETH 设备对的命名格式为 设备 A@设备 B,表示两者是成对关系。

步骤 3:将 VETH 设备分别移入两个命名空间

把 veth-test1 移进 test1 命名空间,veth-test2 移进 test2 命名空间,相当于“把虚拟网线的两端分别插进两个隔离环境”:

# 将 veth-test1 移入 test1 命名空间
sudo ip link set veth-test1 netns test1

# 将 veth-test2 移入 test2 命名空间
sudo ip link set veth-test2 netns test2

# 验证设备移入结果:主机网络设备中已无这两个 VETH 设备(已移入命名空间)
sudo ip link show | grep veth
# 预期输出:(空,无结果)

# 分别查看两个命名空间内的设备,确认 VETH 已移入
sudo ip netns exec test1 ip link show veth-test1
sudo ip netns exec test2 ip link show veth-test2
# 预期输出:均能看到对应 VETH 设备,状态为 DOWN

步骤 4:为 VETH 设备配置 IP 地址

给两个命名空间里的 VETH 设备配上同一网段的 IP(比如 192.168.1.1/24 和 192.168.1.2/24),保证路由可达:

# 为 test1 中的 veth-test1 配置 IP:192.168.1.1/24
sudo ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1

# 为 test2 中的 veth-test2 配置 IP:192.168.1.2/24
sudo ip netns exec test2 ip addr add 192.168.1.2/24 dev veth-test2

# 验证 IP 配置:查看两个命名空间内 VETH 设备的 IP
sudo ip netns exec test1 ip addr show veth-test1
sudo ip netns exec test2 ip addr show veth-test2
# 预期输出:均能看到配置的 IP 地址

步骤 5:启用 VETH 设备

VETH 设备默认是 DOWN 状态,得手动启用(同时把回环设备也启用了,免得影响网络状态):

# 启用 test1 中的 veth-test1 和 lo 设备
sudo ip netns exec test1 ip link set dev veth-test1 up
sudo ip netns exec test1 ip link set dev lo up

# 启用 test2 中的 veth-test2 和 lo 设备
sudo ip netns exec test2 ip link set dev veth-test2 up
sudo ip netns exec test2 ip link set dev lo up

# 验证设备状态:查看 VETH 设备的 state 是否为 UP
sudo ip netns exec test1 ip link show veth-test1
# 预期输出:state 为 UP

步骤 6:测试跨命名空间通信

用 ping 命令测一下两个命名空间能不能互通,能 ping 通就说明跨命名空间通信配成功了:

# 在 test1 中 ping test2 的 VETH IP(192.168.1.2)
sudo ip netns exec test1 ping -c 3 192.168.1.2
# 预期输出:3 个 ping 包均成功(0% packet loss)

# 在 test2 中 ping test1 的 VETH IP(192.168.1.1)
sudo ip netns exec test2 ping -c 3 192.168.1.1
# 预期输出:3 个 ping 包均成功

案例总结

跨命名空间通信的核心逻辑就是:用 VETH 设备对搭一条“隔离环境之间的物理通道”,再给通道两端配上同一网段的 IP,数据就能互通了。这个逻辑其实也是 Docker 里“容器间通信”“容器与主机通信”的底层原理(Docker 会自动创建 VETH 设备对和网桥,把配置简化掉)。

三、常见问题与解决方案

1. 问题 1:命名空间内 ping 回环设备(lo)失败

  • 原因:新创建的 NetNS 里,lo 设备默认是 DOWN 状态,没启用。
  • 解决方案:执行 sudo ip netns exec [命名空间名] ip link set dev lo up 把 lo 设备启用,之后 ping 127.0.0.1 就能成功了。

2. 问题 2:跨命名空间 ping 失败(VETH 已配置)

  • 常见原因:
  1. VETH 设备没启用(state 为 DOWN);
  2. 两个 VETH 设备的 IP 不在同一网段(比如一个是 192.168.1.1/24,另一个是 192.168.2.1/24);
  3. 命名空间内的路由表缺失(可以用 sudo ip netns exec [命名空间名] ip route 查看,得包含目标网段的路由)。
  • 解决方案:
  1. 确保 VETH 设备已启用(执行 ip link set dev [VETH 名] up);
  2. 重新配 IP,保证两者在同一网段;
  3. 路由要是缺了,手动加一条(比如 sudo ip netns exec test1 ip route add 192.168.1.0/24 dev veth-test1)。

3. 问题 3:删除命名空间时提示 “Device or resource busy”

  • 原因:命名空间里还有正在运行的进程(比如通过 ip netns exec [命名空间名] bash 启动的终端,或者在命名空间里跑着的服务)。
  • 解决方案:
  1. 找出命名空间里的进程:
# 查看所有与 test1 命名空间相关的进程(NSpid 列包含命名空间 ID)
ps aux | grep -E 'ip netns exec test1|test1'
  1. 终止进程(把 [进程 ID] 换成实际的 ID):
sudo kill -9 [进程ID]
  1. 再次删除命名空间:
sudo ip netns del test1

四、总结

NetNS 是 Linux 网络隔离的基石,核心价值就在于“把一个物理网络环境拆成多个互相独立的虚拟网络环境”,而且各环境之间互不干扰。这篇通过“基础操作 + 实战案例”,把 NetNS 的核心用法都覆盖到了:

  1. 基础操作:用 ip netns add/del/list/exec 完成命名空间的创建、删除、查看和命令执行;
  2. 跨域通信:用 VETH 设备对搭一根“虚拟网线”,实现两个命名空间互通,顺便理解容器通信的底层原理;
  3. 问题排查:针对常见的“ping 不通”“删不掉”等问题,给出了明确的原因和解决办法。

掌握 NetNS 之后,你不仅能手动配网络隔离环境,还能更深层地理解 Docker、Kubernetes 这些容器技术的网络模型,为后面学容器编排打基础。