使用 Veth Pair 虚拟网卡对不同的网络空间进行通信

Posted whale_life

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用 Veth Pair 虚拟网卡对不同的网络空间进行通信相关的知识,希望对你有一定的参考价值。

使用 Veth Pair 虚拟网卡对不同的网络空间进行通信

解决问题:

由于资源隔离带来的名称空间的网络隔离,解决不同的网络隔离的通信,隔离的目的是为了资源部署,我们诉求是要达到互联互通,不能只隔离,不通信,所以需要使用虚拟网卡对的方式来实现网络的互联互通。

如图是一个传统的同一个 node 节点的,不同的 pod 之间互相通信模型使用

brctl 命令

# 安装命令
~# apt install bridge-utils ethtools -y

# 查看当前服务器 bridge 类型的网卡
~# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242910296ce no

# 查看当前网卡下的 mac 地址
~# brctl showmacs docker0
port no mac addr is local?(是否是本地的mac地址,no表示为非本地的地址) ageing timer
1 12:88:4c:d1:3b:24 yes 0.00
1 12:88:4c:d1:3b:24 yes 0.00

模拟 Linux bridge

我们通过本地创建一个网桥,然后连接不同的网络空间,来达到模拟同一个 node 节点的 pod 通过网桥通信的目的。网桥的本质其实就是一个模拟二层的交换机,通过 MAC 地址来进行数据链路层的通信。

1.创建 br0 网桥

# 添加 br0 bridge 网桥
~# ip link add br0 type bridge

# 启动网桥
~# ip link set br0 up

# 查看 bridge
~# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.000000000000 no
docker0 8000.0242910296ce no veth3ea8f48

2.创建名称空间 ns1 和 ns2

~# ip netns add ns1
~# ip netns add ns2

3.创建 veth 对

~# ip link add veth0 type veth peer br-veth0
~# ip link add veth1 type veth peer br-veth1

# 查看创建的 veth 对,通过查看此时 veth对 在 root名称空间下
~# ip address show
······
6: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether ae:60:62:d9:67:aa brd ff:ff:ff:ff:ff:ff
inet6 fe80::ac60:62ff:fed9:67aa/64 scope link
valid_lft forever preferred_lft forever
7: br-veth0@if8: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 5e:6b:c5:04:47:52 brd ff:ff:ff:ff:ff:ff link-netns ns1
9: br-veth1@if10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 16:b4:3a:d1:88:e6 brd ff:ff:ff:ff:ff:ff link-netns ns2

4.将创建的 veth对 的一端插入到指定的名称空间

~# ip link set veth0 netns ns1
~# ip link set veth1 netns ns2

# 通过进入不同的名称空间查看网卡的一端
~# ip netns exec ns1 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
8: veth0@if7: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 7e:c7:8f:64:79:e0 brd ff:ff:ff:ff:ff:ff link-netnsid 0

~# ip netns exec ns2 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
10: veth1@if9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 36:19:69:64:ab:8c brd ff:ff:ff:ff:ff:ff link-netnsid 0

5.将创建的 veth对 的另一端插入到 br0 的桥接网卡

~# ip link set br-veth0 master br0
~# ip link set br-veth1 master br0

# 查看网卡对 和 绑定情况
~# brctl show br0
bridge name bridge id STP enabled interfaces
br0 8000.16b43ad188e6 no br-veth0
br-veth1

6.启动网卡 veth0 veth1 br-veth0 br-veth1,并配置 ip 地址

~# ip link set br-veth0 up
~# ip link set br-veth1 up

~# ip netns exec ns1 ip link set veth0 up
~# ip netns exec ns2 ip link set veth1 up

~# ip netns exec ns1 ifconfig veth0 192.168.100.10/24
~# ip netns exec ns2 ifconfig veth1 192.168.100.20/24
~# ip netns exec ns1 ifconfig
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

veth0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.100.10 netmask 255.255.255.0 broadcast 192.168.100.255
ether 7e:c7:8f:64:79:e0 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
</sub># ip netns exec ns2 ifconfig
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

veth1: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.100.20 netmask 255.255.255.0 broadcast 192.168.100.255
ether 36:19:69:64:ab:8c txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0



# 注意:也需要启动网卡 lo,否则 ping 本身的 IP地址不通,没有环回接口,ping 自己是走的 lo网卡
~# ip netns exec ns1 ip link set lo up
~# ip netns exec ns2 ip link set lo up

# 效果展示,我们发现 ping 自己可以通,但是 ping 另一个名称空间的 IP地址不通,通过抓包查看
root@tf:<sub># ip netns exec ns2 ping 192.168.100.20
PING 192.168.100.20 (192.168.100.20) 56(84) bytes of data.
64 bytes from 192.168.100.20: icmp_seq=1 ttl=64 time=0.029 ms
64 bytes from 192.168.100.20: icmp_seq=2 ttl=64 time=0.066 ms
^C
--- 192.168.100.20 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1014ms
rtt min/avg/max/mdev = 0.029/0.047/0.066/0.018 ms
root@tf:</sub># ip netns exec ns2 ping 192.168.100.10
PING 192.168.100.10 (192.168.100.10) 56(84) bytes of data.
From 192.168.100.20 icmp_seq=1 Destination Host Unreachable
From 192.168.100.20 icmp_seq=2 Destination Host Unreachable
From 192.168.100.20 icmp_seq=3 Destination Host Unreachable
^C
--- 192.168.100.10 ping statistics ---
4 packets transmitted, 0 received, +3 errors, 100% packet loss, time 3073ms
pipe 4

7.抓包

# 对 br-veth0 抓包,我们发现地址可达,已经通过 arp 广播正确学习了 MAC 地址
tcpdump -pne -i br-veth0

使用

# 对 ns1 名称空间下的 veth0 进行抓包,看看是否有返回的报文
# 我们发现并没有返回的报文,那么都能正确解析了,却没有返回的报文
ip netns exec ns1 tcpdump -pne -i veth0

使用

# 对 ns2 名称空间下的 veth1 进行抓包,可以正常返回 ARP 报文
ip netns exec ns2 tcpdump -pne -i veth1

使用

通过上边抓包可以判断,我们的配置是没有的问题的,问题应该出在 ​​​ netfilter​​​这个 hook 上,也就是 iptables 的 FORWARD 链


8. iptables FORWARD链开启

这个问题其实是 docker 修改了我们默认的 FORWARD 链的策略,可以查看官方文档的解释

​docker-on-a-router​

# 查看 FORWARD 链是否是 DROP 状态
~# iptables-save | grep DROP
:FORWARD DROP [29:2436]

# 对 br0 网桥开启 FORWARD 转发
~# iptables -A FORWARD -i br0 -j ACCEPT

# 再次进行连通性测试,可以正常转发
~# ip netns exec ns1 ping 192.168.100.20
PING 192.168.100.20 (192.168.100.20) 56(84) bytes of data.
64 bytes from 192.168.100.20: icmp_seq=1 ttl=64 time=0.075 ms
64 bytes from 192.168.100.20: icmp_seq=2 ttl=64 time=0.065 ms
64 bytes from 192.168.100.20: icmp_seq=3 ttl=64 time=0.150 ms
64 bytes from 192.168.100.20: icmp_seq=4 ttl=64 time=0.137 ms

以上是关于使用 Veth Pair 虚拟网卡对不同的网络空间进行通信的主要内容,如果未能解决你的问题,请参考以下文章

华为云技术分享《跟唐老师学习云网络》 - Veth网线

k8s里pod与宿主机的veth-pair匹配关系查找方法

《Kubernetes网络权威指南》读书笔记 | 千呼万唤始出来:veth pair

《Kubernetes网络权威指南》读书笔记 | 千呼万唤始出来:veth pair

网络知识---如何查看docker veth pair与宿主机上网卡的对应关系

docker