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 创建容器时:
ip netns add <container-id>- 创建 veth pair,一端塞进 netns
- 另一端挂到
docker0bridge / CNI 网桥 - 给容器 netns 内的 veth 配 IP / 默认路由
nsenter --net=...在容器 netns 内启进程
docker exec 等价于 nsenter --target $PID --net --pid --mount。
理解了 netns,调试 "我的容器没网络" / "K8s pod 间不通" 等问题
就有了底层视角。
踩过的坑
- 用
ip netns exec X command但command是 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 等。
登录后参与评论。