Linux Network Namespace:在一台机器上模拟多个网络环境

Network namespace(netns)是 Linux 内核的网络隔离机制。每个 netns
有独立的网卡、路由表、防火墙规则、socket 列表。

container(Docker / podman / K8s pod)的网络隔离底层就是这个。
理解 netns 后调试容器网络就直观了;还能直接用 netns 跑测试 /
模拟复杂拓扑。

1. 创建 netns

sudo ip netns add red
sudo ip netns add blue

ip netns list
# blue
# red

每个 netns 默认只有一个 loopback(甚至没启):

sudo ip netns exec red ip link
# 1: lo: <LOOPBACK> mtu 65536 ... state DOWN

# 启 lo
sudo ip netns exec red ip link set lo up
sudo ip netns exec red ip addr show

2. 在 netns 里执行命令

sudo ip netns exec red bash
# 进了一个新 shell,网络环境完全隔离

ip addr      # 只有 lo
ip route     # 空路由表
curl google.com   # 当然不通

exit

3. 用 veth pair 把两个 netns 连起来

veth 是"虚拟以太网网卡对"——两端一对,一端发送的包另一端立刻收到,
像一根虚拟网线:

# 创建 veth pair
sudo ip link add veth-red type veth peer name veth-red-host
sudo ip link add veth-blue type veth peer name veth-blue-host

# 把一端塞进 netns
sudo ip link set veth-red netns red
sudo ip link set veth-blue netns blue

# host 端启接口
sudo ip link set veth-red-host up
sudo ip link set veth-blue-host up

# netns 内端启接口 + 配 IP
sudo ip netns exec red ip link set veth-red up
sudo ip netns exec red ip addr add 10.10.0.2/24 dev veth-red
sudo ip netns exec red ip route add default via 10.10.0.1

sudo ip netns exec blue ip link set veth-blue up
sudo ip netns exec blue ip addr add 10.10.1.2/24 dev veth-blue
sudo ip netns exec blue ip route add default via 10.10.1.1

4. 用 bridge 让多个 netns 共网段

# host 上建网桥
sudo ip link add br0 type bridge
sudo ip link set br0 up
sudo ip addr add 10.10.0.1/24 dev br0

# veth host 端挂到 bridge
sudo ip link set veth-red-host master br0
sudo ip link set veth-blue-host master br0

bridge 像一个虚拟交换机:red / blue netns 互通。

Docker 默认网络模型就是这套:所有容器 veth 一端在容器 netns,另一端
挂在 docker0 bridge。

5. 让 netns 访问外网

# host 上开 IP forwarding
sudo sysctl -w net.ipv4.ip_forward=1

# 配 NAT:netns 流量从 eth0 出去时做 SNAT
sudo iptables -t nat -A POSTROUTING \
  -s 10.10.0.0/16 -o eth0 -j MASQUERADE

# 测试
sudo ip netns exec red curl ifconfig.me
# 公网 IP(你的 host 的)

6. 给 netns 分配独立 DNS

netns 内的 /etc/resolv.conf 默认还是 host 的。改:

sudo mkdir -p /etc/netns/red
echo 'nameserver 1.1.1.1' | sudo tee /etc/netns/red/resolv.conf

ip netns exec red ... 会自动 bind-mount /etc/netns/red/resolv.conf
/etc/resolv.conf

7. 实战用例:用 VPN 跑某个进程,不影响系统

sudo ip netns add vpn

# WireGuard 接口 wg0 起好之后丢进 netns
sudo ip link set wg0 netns vpn
sudo ip netns exec vpn ip addr add 10.0.0.2/24 dev wg0
sudo ip netns exec vpn ip link set wg0 up
sudo ip netns exec vpn ip route add default via 10.0.0.1

# 跑 firefox(流量走 VPN)
sudo ip netns exec vpn sudo -u $USER firefox

系统的其它进程走正常网络,firefox 走 VPN,零干扰。

8. 删 netns

sudo ip netns del red
# veth 一端跟着 netns 消失,host 端 veth-red-host 自动被删

9. 跨重启持久化

iproute2 不持久化 netns。要持久化用 systemd-networkd 或 NetworkManager
配 dispatcher script。容器项目(Docker、systemd-nspawn)自动管 netns
生命周期。

10. 调试技巧

# 看 netns 内的 socket
sudo ip netns exec red ss -tan

# 看 netns 内的 conntrack
sudo ip netns exec red conntrack -L

# 在 netns 内抓包
sudo ip netns exec red tcpdump -i veth-red -nn

# 从 host 看进程在哪个 netns
sudo lsns -t net
# NS         TYPE NPROCS PID USER  COMMAND
# 4026531992 net  100   1   root  /sbin/init
# 4026532145 net    1   1234 root  /usr/bin/firefox

11. 容器视角

Docker / podman / K8s 创建容器时:

  1. ip netns add <container-id>
  2. 创建 veth pair,一端塞进 netns
  3. 另一端挂到 docker0 bridge / CNI 网桥
  4. 给容器 netns 内的 veth 配 IP / 默认路由
  5. nsenter --net=... 在容器 netns 内启进程

docker exec 等价于 nsenter --target $PID --net --pid --mount

理解了 netns,调试 "我的容器没网络" / "K8s pod 间不通" 等问题
就有了底层视角。

踩过的坑

  • ip netns exec X commandcommand 是 bash 的 builtin(如 cd)——
    不是命令。改成 bash -c "..." 包一下。
  • veth 的 MTU 默认 1500,套 VPN 后 MTU 减小,netns 内 MTU 不调整会
    fragment 频繁。ip link set veth-xxx mtu 1420
  • conntrack:每个 netns 有独立 conntrack 表。host 防火墙规则不自动
    影响 netns。
  • 用 sudo 进 netns 后丢失了原 user 环境变量:ip netns exec X sudo -u $USER bash
    能切回普通用户但要小心 PATH / DISPLAY 等。
精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。