Linux 网络命名空间与虚拟路由深度工程实战
深入理解 Linux 网络栈的隔离机制与虚拟路由原理,从 netns、veth、bridge 到 VRF、策略路由,掌握容器网络、多租户网络隔离的底层实现。
一、为什么需要网络隔离?
现代云计算环境中,一个物理服务器上可能运行数百个容器、数十个租户网络。每个租户都需要独立的路由表、独立的防火墙规则、独立的 IP 地址空间——甚至允许地址重叠(如多个租户都可以使用 192.168.1.0/24)。传统的 IPv4 路由机制无法解决这些需求,网络命名空间(network namespace)正是 Linux 内核给出的答案。
网络命名空间最早由 Linux 2.4.19 引入,经过二十多年的演进,已经成为容器技术(Docker、Kubernetes、Podman 等)的网络基础。
二、网络命名空间核心概念
网络命名空间将网络协议栈从全局共享变为每个命名空间独立拥有。这意味着每个 netns 都拥有:
- 独立的网络设备(网卡)
- 独立的 IP 地址配置
- 独立的路由表
- 独立的 iptables/nftables 规则
- 独立的 socket 和连接
创建和查看网络命名空间:
# 创建新的网络命名空间
ip netns add ns-blue
ip netns add ns-red
# 查看命名空间列表
ip netns list
# 输出:
# ns-red
# ns-blue id 0 if 1
# 在指定命名空间中执行命令
ip netns exec ns-blue ip addr show
使用 /var/run/netns/ 目录持久化管理命名空间:
# 创建一个持久化的命名空间(通过挂载)
ip netns add ns-persist
# 命名空间在没有任何引用时会自动删除
# 可以在 /var/run/netns/ 下绑定挂载保持引用
mkdir -p /var/run/netns
touch /var/run/netns/ns-persist
mount --bind /proc/$(pidof process)/ns/net /var/run/netns/ns-persist
三、veth Pair:命名空间之间的以太网隧道
veth(Virtual Ethernet)设备总是成对出现,类似于管道——一端进入的数据从另一端出来。它是连接不同网络命名空间的"虚拟网线"。
3.1 基本拓扑构建
# 创建 veth pair
ip link add veth-blue type veth peer name veth-red
# 分别放入不同命名空间
ip link set veth-blue netns ns-blue
ip link set veth-red netns ns-red
# 配置 IP 地址
ip netns exec ns-blue ip addr add 10.1.1.1/24 dev veth-blue
ip netns exec ns-red ip addr add 10.1.1.2/24 dev veth-red
# 启用设备
ip netns exec ns-blue ip link set veth-blue up
ip netns exec ns-blue ip link set lo up
ip netns exec ns-red ip link set veth-red up
ip netns exec ns-red ip link set lo up
# 验证连通性
ip netns exec ns-blue ping -c 2 10.1.1.2
通过 ethtool -S veth-blue 可以看到 veth 设备的统计信息,包括 tx_queue_len(默认 1000)、对端 ifindex 等。
3.2 veth 的数据包路径
veth pair 的数据包从一端进入后,会经过以下路径:
- 从发送端网卡的 TX queue 出队
- 通过内部 ring buffer 直接复制到接收端的 RX queue
- 触发软中断(NET_RX_SOFTIRQ),由 NAPI 调度处理
- 单队列设计(默认只有一个 TX/RX queue)
- 默认 MTU 1500(可调整)
- 跨命名空间的上下文切换开销
- netns 提供隔离边界
- veth pair 打通命名空间通信
- Bridge 实现二层交换
- VRF + 策略路由 提供三层多租户隔离
注意:veth 两端的命名空间通信不经过物理网卡,数据在内核空间直接复制。但 veth 的性能受限于:
3.3 veth 性能优化
# 增加 TX 队列长度
ip link set veth-blue txqueuelen 10000
# 启用多队列(Linux 4.x+ 支持)
ip link set eth0 combined 4
在 Kubernetes 的 Flannel host-gw 模式下,每个 pod 通过 veth pair 连接到宿主机网桥,跨节点通信则走主机路由表,overlay 开销极小。
四、Linux Bridge:软件交换机
Linux Bridge 是一个二层虚拟交换机,用于将多个网络接口(包括 veth pair 的末端)桥接在一起。
4.1 基本操作
# 创建网桥
ip link add br0 type bridge
ip link set br0 up
# 添加 veth 末端到网桥
ip link set veth-blue master br0
ip link set veth-red master br0
# 查看网桥端口
bridge link show
# 给网桥配置 IP(使其可被外部路由到达)
ip addr add 10.1.1.254/24 dev br0
# 查看 MAC 地址表
bridge fdb show br br0
4.2 网桥与 iptables 的交互(hairpin mode)
传统上,Linux Bridge 工作在纯二层模式,不经过 iptables。但 Docker/Kubernetes 需要 MASQUERADE 等功能,因此引入 net.bridge.bridge-nf-call-iptables:
# 是否让桥接流量经过 iptables
sysctl net.bridge.bridge-nf-call-iptables=1
sysctl net.bridge.bridge-nf-call-ip6tables=1
当此参数为 1 时,docker0 网桥上的流量也会经过宿主机的 INPUT/FORWARD/OUTPUT 链,这使得 iptables 规则可以控制东西向流量。但这也带来了复杂的交互问题,在某些场景下建议设为 0,配合 eBPF 方案处理策略。
4.3 VLAN 隔离
Linux Bridge 支持 802.1Q VLAN 过滤:
# 启用 VLAN 过滤
ip link set br0 type bridge vlan_filtering 1
# 将端口分配到 VLAN 10
bridge vlan add dev veth-blue vid 10 pvid
bridge vlan add dev veth-red vid 10
# trunk 端口
bridge vlan add dev eth0 vid 10
bridge vlan add dev eth0 vid 20
*注意*:传统的 bridge vlan 命令使用独立的 VLAN 数据库,与 vlan 子接口(eth0.10)不同,需要根据场景选择合适的方案。
五、虚拟路由与转发(VRF)
VRF(Virtual Routing and Forwarding)是 Linux 3.x+ 引入的三层隔离机制。与网络命名空间不同,VRF 在同一网络命名空间内隔离路由表,不需要复制整个协议栈。
5.1 创建 VRF
# 创建 VRF 设备
ip link add vrf-blue type vrf table 100
ip link add vrf-red type vrf table 200
ip link set vrf-blue up
ip link set vrf-red up
# 将网卡绑定到 VRF
ip link set eth1 master vrf-blue
ip link set eth2 master vrf-red
# 查看 VRF 路由表
ip route show table 100
ip route show table 200
5.2 VRF 路由规则
VRF 创建时自动添加策略路由规则:
# 查看自动生成的规则
ip rule show
# 输出:
# 1000: from all lookup [vrf_table] unreachable
# 其含义:来自某 VRF 的流量如果不在本 VRF 路由表中找到,则 unreachable
# 防止"泄漏"到全局表
手动向 VRF 添加路由:
# 设置 VRF 默认路由
ip route add default via 10.1.1.1 table 100
ip route add 10.2.0.0/16 via 10.1.1.2 table 100
# 直接命令在 VRF 内设置
ip netns exec vrf-blue ip route add default via 10.1.1.1
# 注意:带 "netns" 关键字是 VRF-aware 的
5.3 VRF vs 网络命名空间
| 特性 | 网络命名空间 | VRF |
|---|---|---|
| 隔离层级 | 完整协议栈 | 仅路由表 |
|---|---|---|
| 性能开销 | 较高(套接字隔离) | 较低(共享协议栈) |
|---|---|---|
| MAC 隔离 | 独立 | 不隔离 |
|---|---|---|
| L2 隔离 | 独立 | 共享 ARP 表 |
|---|---|---|
| 典型使用场景 | 容器网络 | 多租户 L3VPN |
|---|---|---|
最佳实践:在 MPLS/VPN 场景中常叠加使用:网络命名空间隔离容器,VRF 实现租户路由,两者结合即为 CNI 网桥方案的核心设计。
六、策略路由(Policy Routing)
传统的 Linux 路由只根据目的 IP 查表做出转发决策。策略路由(Policy Routing)允许根据源 IP、DSCP 标记、fwmark 等多种属性选择路由表。
6.1 基本配置
# 规则:源地址为 10.1.1.0/24 的流量查表 100
ip rule add from 10.1.1.0/24 table 100 priority 1000
# 规则:fwmark 0x1 的流量查表 101
ip rule add fwmark 0x1 table 101 priority 1100
# 规则:来自 eth2 的流量查表 102
ip rule add iif eth2 table 102 priority 1200
# 查看规则
ip rule show
# 优先级数值越小优先级越高
规则优先级规则:内核按优先级数值从小到大匹配,第一条匹配的规则生效。特殊表 local(254)、main(253)、default(255)的优先级不可被覆盖。
6.2 结合 iptables MARK 实现复杂策略
# 标记来自特定容器的流量
iptables -t mangle -A PREROUTING -s 172.18.0.5 -j MARK --set-mark 0x10
# 标记的流量走特定路由表
ip rule add fwmark 0x10 table 100
# 在路由表 100 中指定 VPN 网关
ip route add default via 10.8.0.1 dev tun0 table 100
6.3 源地址验证与反向路径过滤
启用策略路由后,默认的严格反向路径过滤(rp_filter)可能导致丢弃:
# 推荐设置:宽松模式
sysctl net.ipv4.conf.all.rp_filter=2
sysctl net.ipv4.conf.default.rp_filter=2
在 VRF 场景中更需注意:不同 VRF 中的流量回包应走相同 VRF,否则连接会挂起。
七、容器网络底层实战
理解上述基础组件后,我们来看看真实容器网络是如何组装的。
7.1 手动搭建 Docker 式网络
# 创建"容器"网络命名空间(以 PID 方式)
# 1. 创建 veth pair
ip link add veth0 type veth peer name veth1
# 2. 创建并配置网桥(宿主机侧)
ip link add cni0 type bridge
ip link set cni0 up
ip addr add 10.244.1.1/24 dev cni0
# 3. 将 veth1 加入网桥
ip link set veth1 master cni0
ip link set veth1 up
# 4. 将 veth0 放入"容器"命名空间(模拟)
PID=$(docker inspect -f '{{.State.Pid}}' mycontainer 2>/dev/null)
if [ -z "$PID" ]; then
# 模拟:用 shell 进程
unshare --net=/var/run/netns/container-ip netns
fi
# 5. 容器内配置
ip netns exec container-ip ip link set veth0 name eth0
ip netns exec container-ip ip addr add 10.244.1.2/24 dev eth0
ip netns exec container-ip ip link set eth0 up
ip netns exec container-ip ip route add default via 10.244.1.1
# 6. 宿主机 NAT
iptables -t nat -A POSTROUTING -s 10.244.1.0/24 ! -o cni0 -j MASQUERADE
iptables -A FORWARD -i cni0 -j ACCEPT
iptables -A FORWARD -o cni0 -j ACCEPT
7.2 Kubernetes CNI 数据包路径
以 Calico(纯三层模式,不使用 overlay)为例:
节点内跨 Pod 通信:
Pod A (eth0) -> vethXXX -> host ns 路由表 -> vethYYY -> Pod B (eth0)
全程在内核态完成,无需 IPIP/VXLAN 封装。
跨节点 Pod 通信:
Pod A -> host ns 路由 -> 物理网卡 eth0 -> 物理网络 -> 节点B eth0 -> 路由转发 -> Pod B
Calico 使用 BGP 协议分发 Pod CIDR 路由,每个 Pod 路由的下一跳是 Pod 所在节点 IP。
7.3 Cilium eBPF 方案
Cilium 绕过 iptables 内核路径,在 Socket 层做负载均衡:
# 查看 Cilium eBPF 程序加载
bpftool prog show
# 查看 Cilium 路由映射
cilium bpf lb list
# 查看 endpoint 映射
cilium endpoint list
Cilium 的核心优化在于:在容器网卡 TC 或 XDP 钩子直接做 DNAT/SNAT,不需要遍历 iptables 链,大幅降低延迟。
八、实战故障排查案例
案例 1:容器无法访问外网
现象:Kubernetes Pod 内无法 ping 通 8.8.8.8,只能 ping 通同节点 Pod。
排查过程:
# 检查宿主机 IP 转发是否开启
sysctl net.ipv4.ip_forward
# 返回 0 -> echo 1 > /proc/sys/net/ipv4/ip_forward
# 检查 iptables 规则是否正确生成
iptables -t nat -L POSTROUTING -n | grep MASQUERADE
# 若无输出 -> kube-proxy 或 CNI 插件异常
# 检查路由表
ip route show table main | grep default
# 检查网桥状态
ip -d link show cni0
# 确认 br0 状态为 UP
案例 2:VRF 内流量不通(回包问题)
现象:VRF 中的 TCP 握手失败,tcpdump 能看到 SYN 但无 SYN-ACK。
根因:服务端在全局命名空间监听,客户端从 VRF 发起连接,服务端回包时 RP 查询全局路由表,但下一跳接口在 VRF 中。
修复:确保回包也走相同 VRF。
# 将服务监听接口绑定到 VRF
ip link set eth0 master vrf-blue
# 或添加策略规则
ip rule add iif eth0 lookup 100
案例 3:veth pair 丢包严重
现象:iperf 测试显示吞吐量远低于预期。
# 检查 ring buffer
ethtool -g veth-blue
# veth 默认 ring buffer 仅 1000/1000
# 检查是否丢包
ethtool -S veth-blue | grep drop
# 调优 TX 队列
ip link set veth-blue txqueuelen 5000
# 检查 NAPI 调度
cat /proc/net/softnet_stat
# 第 2 列表示丢包次数
九、生产级部署 Checklist
在容器平台生产部署中,建议检查以下网络基础配置:
# === 系统参数 ===
# IP 转发(必需)
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
# 桥接流量是否过 iptables(按需)
net.bridge.bridge-nf-call-iptables = 1
# 反向路径过滤(策略路由场景设为 2)
net.ipv4.conf.all.rp_filter = 2
# conntrack 表大小(大规模环境调大)
net.netfilter.nf_conntrack_max = 524288
# === 资源限制 ===
# 每个 Pod 的 veth 占用一对网络资源
# 建议 max_pod_per_node <= 250(IP 充足时)
# === 监控指标 ===
# 丢包率 - ethtool 统计
# veth 带宽 - /proc/<pid>/net/dev
# conntrack 使用率 - /proc/sys/net/netfilter/nf_conntrack_count vs max
# 网卡 ERROR - ip -s link show
# === 高可用 ===
# 多网卡 bonding(mode 802.3ad 或 active-backup)
# 节点多路由 - BGP/ECMP
十、总结与展望
Linux 网络命名空间与虚拟路由是现代云原生基础设施的基石。从最基础的手动配置到 CNI 插件的自动化管理,核心始终是:
随着 eBPF 技术的发展,Cilium 等项目正在重新定义容器网络:绕过 conntrack、集成 XDP、在 Socket 层做负载均衡。未来的趋势是"内核级 SDN"——网络策略直接编译为 eBPF 字节码加载到内核,实现接近物理网卡的转发性能。
理解这些底层机制,有助于我们在生产环境中更高效地排查网络问题,设计更合理的网络架构,以及在 CNI 选型时做出正确决策。
*参考资料:iproute2 源码、Linux 内核文档 Documentation/networking/vrf.txt、Calico/Cilium 官方文档*

发表评论 取消回复