在 Linux 系统中,每个进程的命名空间信息都暴露在 /proc/<PID>/ns/ 目录下
核心底层技术是 Linux 的 Network Namespace(网络命名空间) 和 Pause 容器。
在 Kubernetes 中,一个 Pod 并不是一个单一的实体,而是由一组共享资源的容器组成的。具体实现过程如下:
- Pause 容器(基础设施容器):当你创建一个 Pod 时,K8s 会首先启动一个极其轻量的 pause 容器。这个容器的唯一作用就是占用并维持一个 Network Namespace。
- 共享网络栈:Pod 内的其他业务容器(比如 Nginx、Java 应用等)在启动时,会被加入到这个 pause 容器创建的同一个 Network Namespace 中。
- 效果:因为它们都在同一个网络命名空间里,所以它们看到的网卡(如 eth0)、IP 地址、路由表、端口号都是完全一样的。这就好比几台电脑插在了同一个交换机上,甚至更亲密------它们共用同一个虚拟网卡。
一个 namespace 下可以有多个虚拟网卡吗?
完全可以。
一个 net namespace 就像一台独立的"虚拟主机",拥有自己独立的:
- 网卡列表(lo、eth0、br0、veth 等)
- 路由表
- iptables 规则
- 端口空间
在 Linux 操作系统中,网络栈(Network Stack)指的是操作系统内核处理网络数据的一整套架构。它不仅包含 IP 地址,还包含了以下整套家当:
- 网络接口(网卡/Network Interfaces): 比如宿主机的物理网卡 eth0,或者虚拟网卡。
- 路由表(Routing Table): 决定数据包从哪个网卡发出去,下一步去哪里。
- 防火墙规则(iptables/netfilter): 决定哪些数据包可以放行,哪些要丢弃或转发。
- 协议实现: TCP/UDP 等协议的底层实现。
- 端口(Ports): 0 到 65535 的端口资源,用来区分不同的应用程序。
创建一个独立的网络命名空间 Linux Namespace(网络命名空间)
这是容器技术的基石。Linux 允许你把网络资源隔离开来。每个 Namespace 都有自己独立的网卡、路由表 ,也就是一个命名空间有自己的网络栈。
bash
# 创建一个名为 pod_ns 的网络命名空间
sudo ip netns add pod_ns
# 查看是否创建成功
ip netns list
可以进入这个命名空间,查看网络
bash
ip netns exec pod_ns ip addr
意思是"请让我钻进 pod_ns 这个独立空间里,去执行后面的命令",
你会发现屏幕上极其干净!之前的物理网卡、宿主机 IP 统统消失了。里面只有孤零零的一张 lo(本地环回虚拟网卡),而且状态还是 DOWN(关闭的)。
这就是"网络栈隔离"的铁证! 这个小房间现在是一片绝对的白纸,它不知道外面有 eth0,也没有任何 IP 地址。

bash
ip netns exec pod_ns ip link set lo up
进入到pod_ns 空间,启动lo网卡
bash
ip netns del pod_ns
删除pod_ns 网络命名空间
bash
sudo ip link add br1 type bridge
内核创建了一个名为 br1 的虚拟网卡。但此时它并没有启动,也没有分配 IP,里面也没有插任何网线
bash
ip link show br1

目前还是处于down的状态,还没有通电,还没有ip,暂时不能通信
bash
# 1. 先删掉 br1 上的旧 IP ,可选 如果配置错了,然后重新添加
sudo ip addr del 192.168.100.1/24 dev br1
# 2. 给 br1 添加新 IP(举例改成 192.168.200.1)
sudo ip addr add 192.168.200.1/24 dev br1
查询目前状态
bash
ip addr show br1

接下来启动这个br1
bash
sudo ip link set br1 up

已经启动了 目前是21号设备 如上图编号。
现在网桥创建好了,接下来就是把虚拟网线(veth pair)插上去
创建veth pair
bash
sudo ip link add veth_host type veth peer name veth_ns
如果已经存在,同一个名称会报错,
具体效果与原因: 系统会返回类似 RTNETLINK answers: File exists 的错误提示5。这是因为 veth_host 这个网络接口名称在你的系统中已经存在。在 Linux 网络命名空间中,网络接口(网卡)的名称必须是唯一的,系统不允许创建同名接口
我们可以先删除,在重建
bash
sudo ip link delete veth_host
p link show veth_host 确保不存在
[root@test64 _data]# ip link show veth_host
Device "veth_host" does not exist.
sudo ip link add veth_host type veth peer name veth_ns
执行 ip addr 会有一对吗?
perl
22: veth_ns@veth_host: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether ca:0e:10:13:fe:37 brd ff:ff:ff:ff:ff:ff
23: veth_host@veth_ns: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 5e:55:f9:5f:ab:10 brd ff:ff:ff:ff:ff:ff
@ 符号的关联:
veth_ns@veth_host 表示 veth_ns 的配对端是 veth_host。
veth_host@veth_ns 表示 veth_host 的配对端是 veth_ns。
这种相互指向正是 veth(Virtual Ethernet)设备对的典型特征,它们就像一根虚拟网线的两端
把网线一头插进命名空间,一头插上网桥
把 veth_ns 塞进 pod_ns 命名空间: veth_ns 移到一个网络命名空间里
bash
sudo ip link set veth_ns netns pod_ns
执行完毕后 通过ip addr观察,成对的消失了:变成了 veth_host@if22
perl
23: veth_host@if22: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 5e:55:f9:5f:ab:10 brd ff:ff:ff:ff:ff:ff link-netnsid 0
-
if22:这里的 22 是 veth_ns 在目标命名空间里的接口索引号(Index)。因为 veth_host 还在宿主机,为了让你知道它的配对端在哪,内核加上了这个后缀。
-
link-netnsid 0:这表示配对端所在的命名空间在当前视角下的 ID。
插一段:
bash
ip netns exec pod_ns bash
这个命令可以进入对应的网络空间执行bash命令。
接下来 把 veth_host 这头插到我们的网桥 br1 上,将 veth_host 这个虚拟网卡接入(挂载)到名为 br1的虚拟网桥(Bridge)上
bash
sudo ip link set veth_host master br1
如何解除绑定 如果你想把 veth_host 从网桥上拔下来,可以使用 nomaster 参数:
bash
sudo ip link set veth_host nomaster
进入到 pod_ns网络空间,给veth_ns 分配 IP,注意要和网桥是同一个网段
bash
# 给 veth_ns 分配 IP
sudo ip netns exec pod_ns ip addr add 192.168.200.2/24 dev veth_ns
sudo ip netns exec pod_ns ip link set veth_ns up
可以发现 ip netns exec pod_ns ip addr,veth_ns网卡状态已经是up
bash
[root@test64 _data]# ip netns exec pod_ns ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
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
22: veth_ns@if23: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether ca:0e:10:13:fe:37 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.200.2/24 scope global veth_ns
valid_lft forever preferred_lft forever
inet6 fe80::c80e:10ff:fe13:fe37/64 scope link
valid_lft forever preferred_lft forever
路由表
当给网桥分配IP的时候,内核会自动内核自动生成直连路由
bash
[root@test64 _data]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.10.30.254 0.0.0.0 UG 100 0 0 eth0
10.10.30.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.100.0 0.0.0.0 255.255.255.0 U 0 0 0 br0
192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 virbr0
192.168.200.0 0.0.0.0 255.255.255.0 U 0 0 0 br1
在 route -n 的输出中,0.0.0.0 代表"无网关"。这说明 192.168.200.0/24 这个网段是直接连接在 br1 上的。内核不需要把数据包交给任何外部路由器,直接通过 br1 这个接口就能送达
验证
宿主机网桥 (192.168.200.1) <--- veth pair ---> 命名空间容器 (192.168.200.2)
1.从宿主机 ping 容器:
bash
ping 192.168.200.2

2.从容器 ping 宿主机网关:
bash
sudo ip netns exec pod_ns ping 192.168.200.1

3.在容器里启动一个 Web 服务,宿主机访问:
bash
sudo ip netns exec pod_ns python2 -m SimpleHTTPServer 8080
# 终端2:在宿主机访问
curl http://192.168.200.2:8080
发现能正常访问服务。至此我们的网络已经通了。