Cilium Vxlan 跨节点通信过程

Posted whale_life

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Cilium Vxlan 跨节点通信过程相关的知识,希望对你有一定的参考价值。

测试前提

因为 cilium 1.10.6 版本 monitor 存在缺少 HOST NS 封装过程,所以我们使用的是 cilium 1.11.4

进行抓包分析。

具体部署过程请参考 ​​Cilium v1.10.6 安装部署​​,helm pull 的时候选择 1.11.4 即可,其余修改一样的

cilium 1.10.6 报文格式

Cilium

cilium 1.11.4 报文格式

Cilium

跨节点通信特点

分析不同节点Pod之间通信,对应此前我们熟悉的CNI(Calico Flannel)均是使用路由表,FDB表,ARP表等网络知识便可以分析的非常清楚,但是在Cilium中我们发现此种分析思路便"失效"了。究其原因,是由于Cilium的CNI实现结合eBPF技术实现了datapath的"跳跃式"转发。

我们需要结合 Cilium 提供的Tools 来辅助分析

  • cilium monitor -vv
  • pwru
  • iptables TRACE
  • tcpdump 分析

如下图报文发送路线图,

我们需要对 pod1 的 lxc 网卡进行抓包、vxlan 抓包、ens33 抓包

需要对 pod2 的 lxc 网卡进行抓包、vxlan 抓包

Cilium

tcpdump

确定 pod 分布情况

node-1:10.0.0.222 (简称:pod1**)

node-2:10.0.1.208 (简称:pod2

root@master:~# kubectl get pod -o wide 
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cni-test-76d79dfb85-28bpq 1/1 Running 0 19m 10.0.0.222 node-1.whale.com <none> <none>
cni-test-76d79dfb85-tjhdp 1/1 Running 0 19m 10.0.1.208 node-2.whale.com <none> <none>

pod1 对应网卡 lxc91ffd83cbb3e

root@master:<sub># kubectl exec -it cni-test-76d79dfb85-28bpq  -- ethtool -S eth0 
NIC statistics:
peer_ifindex: 30

# node-1 节点
root@node-1:</sub># ip link show | grep ^30
30: lxc91ffd83cbb3e@if29: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000

pod 2 对应网卡 lxc978830fe1a23

root@master:<sub># kubectl exec -it cni-test-76d79dfb85-tjhdp  -- ethtool -S eth0 
NIC statistics:
peer_ifindex: 22

# node-2 节点
root@node-2:</sub># ip link show | grep ^22
22: lxc978830fe1a23@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000

node-1 抓包

tcpdump -pne -i lxc91ffd83cbb3e -w lxc_pod1.cap
tcpdump -pne -i cilium_vxlan -w cilium_vxlan_pod1.cap
tcpdump -pne -i ens33 -w ens33_pod1.cap

node-2 抓包

tcpdump -pne -i lxc978830fe1a23 -w lxc_pod2.cap
tcpdump -pne -i cilium_vxlan -w cilium_vxlan_pod2.cap

ping 测试

kubectl exec -it cni-test-76d79dfb85-28bpq -- ping -c 1 10.0.1.208

lxc_pod1.cap

Cilium

cilium_vxlan_pod1.cap

Cilium

ens33_pod1.cap

Cilium

lxc_pod2.cap

Cilium

cilium_vxlan_pod2.cap

Cilium

通过上述抓包,我们验证了场景:

跨节点通信的时候,pod 的报文需要pod内部封装一次,然后通过 HOST NS(宿主机)vxlan 在进行封装,然后通过宿主机的物理网卡传到对端 宿主机,在经过 vxlan 解封装后 直接 redict 到pod 内部,而不需要经过它对应的 lxc 网卡,我们就可以论证下图的通信流程图。

Cilium

cilium monitor

确定 pod 分布情况

node-1:10.0.0.222 (简称:pod1**)

node-2:10.0.1.208 (简称:pod2

root@master:~# kubectl get pod -o wide 
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cni-test-76d79dfb85-28bpq 1/1 Running 0 19m 10.0.0.222 node-1.whale.com <none> <none>
cni-test-76d79dfb85-tjhdp 1/1 Running 0 19m 10.0.1.208 node-2.whale.com <none> <none>

在对应节点分布的 cilium pod 查看他们的网卡信息

圈出来的意思,就是 pod 的 eth0 网卡和

Cilium

# node-1
root@master:<sub># kubectl -n kube-system exec -it cilium-xnmfw -- cilium bpf endpoint list
Defaulted container "cilium-agent" out of: cilium-agent, mount-cgroup (init), clean-cilium-state (init)
IP ADDRESS LOCAL ENDPOINT INFO
10.0.0.112:0 id=415 flags=0x0000 ifindex=24 mac=EA:CF:FE:E8:E7:26 nodemac=BE:12:EB:4E:E9:30
192.168.0.120:0 (localhost)
10.0.0.215:0 (localhost)
10.0.0.222:0 id=2164 flags=0x0000 ifindex=30 mac=32:30:9C:CA:09:8E nodemac=2E:3C:E3:61:26:45

# node-2
root@master:</sub># kubectl -n kube-system exec -it cilium-jztvj -- cilium bpf endpoint list
Defaulted container "cilium-agent" out of: cilium-agent, mount-cgroup (init), clean-cilium-state (init)
IP ADDRESS LOCAL ENDPOINT INFO
10.0.1.208:0 id=969 flags=0x0000 ifindex=22 mac=DA:97:53:7E:9A:CA nodemac=62:57:5C:C9:D6:0C
192.168.0.130:0 (localhost)
10.0.1.249:0 id=2940 flags=0x0000 ifindex=16 mac=02:55:31:EC:28:60 nodemac=32:FD:46:2F:CB:8A
10.0.1.10:0 (localhost)

node1 抓包

使用 pod1 ping pod2,同时在 pod1 所在节点的 cilium 进行抓包

root@master:~# kubectl exec -it cni-test-76d79dfb85-28bpq -- ping -c 1 10.0.1.208
PING 10.0.1.208 (10.0.1.208): 56 data bytes
64 bytes from 10.0.1.208: seq=0 ttl=63 time=0.790 ms

--- 10.0.1.208 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.790/0.790/0.790 ms

cilium monitor 抓包分析

root@master:~# kubectl -n kube-system exec -it cilium-xnmfw -- cilium monitor -vv >monitor.yaml

关键部分

  1. 第一个 Conntrack lookup ,是指定 pod 内部数据出来经过iptables 的过程

node 3232235650 (0xc0a80082)

0x 表示 16进制
c0-a8-00-82 --> 192.168.0.130
这个是 16 进制的 ip 地址,意思就是对端 node 的 ip地址

------------------------------------------------------------------------------

CPU 02: MARK 0x0 FROM 2164 DEBUG: Conntrack lookup 1/2: src=10.0.0.222:4864 dst=10.0.1.208:0
CPU 02: MARK 0x0 FROM 2164 DEBUG: Conntrack lookup 2/2: nexthdr=1 flags=1
CPU 02: MARK 0x0 FROM 2164 DEBUG: CT verdict: New, revnat=0
CPU 02: MARK 0x0 FROM 2164 DEBUG: Successfully mapped addr=10.0.1.208 to identity=3352
CPU 02: MARK 0x0 FROM 2164 DEBUG: Conntrack create: proxy-port=0 revnat=0 src-identity=3352 lb=0.0.0.0
CPU 02: MARK 0x0 FROM 2164 DEBUG: Encapsulating to node 3232235650 (0xc0a80082) from seclabel 3352
  1. 第二个 Conntrack lookup 是 HOST NS 中的 iptables 的处理逻辑,我们可以看源和目的地址都是 宿主机的 ip 地址
------------------------------------------------------------------------------

CPU 02: MARK 0x0 FROM 3 DEBUG: Conntrack lookup 1/2: src=192.168.0.120:56435 dst=192.168.0.130:8472
CPU 02: MARK 0x0 FROM 3 DEBUG: Conntrack lookup 2/2: nexthdr=17 flags=1
CPU 02: MARK 0x0 FROM 3 DEBUG: CT entry found lifetime=16823678, revnat=0
CPU 02: MARK 0x0 FROM 3 DEBUG: CT verdict: Established, revnat=0
  1. 第三个 Conntrack lookup 是返回的 reply 报文,但是并没有 HOST NS 部分的处理。

可以参考下图,我们发现 NodePort Remote Endpoint 的时候是具有 redict 的能力的

Cilium

CPU 03: MARK 0x0 FROM 0 DEBUG: Tunnel decap: id=3352 flowlabel=0
CPU 03: MARK 0x0 FROM 0 DEBUG: Attempting local delivery for container id 2164 from seclabel 3352
CPU 03: MARK 0x0 FROM 2164 DEBUG: Conntrack lookup 1/2: src=10.0.1.208:0 dst=10.0.0.222:4864
CPU 03: MARK 0x0 FROM 2164 DEBUG: Conntrack lookup 2/2: nexthdr=1 flags=0
CPU 03: MARK 0x0 FROM 2164 DEBUG: CT entry found lifetime=16823776, revnat=0
CPU 03: MARK 0x0 FROM 2164 DEBUG: CT verdict: Reply, revnat=0

node2 抓包

进入 node2 的 cilium 进行 monitor 抓包

root@master:~# kubectl -n kube-system exec -it cilium-jztvj -- cilium monitor -vv >monitor2.yaml

查看报文关键部分

  1. 这里看到数据被decap,此时便发到cilium_vxlan接口,第一个 Conntrack lookup 直接在 pod 内部的进行 iptables 的处理。
CPU 03: MARK 0x0 FROM 0 DEBUG: Tunnel decap: id=3352 flowlabel=0
CPU 03: MARK 0x0 FROM 0 DEBUG: Attempting local delivery for container id 969 from seclabel 3352
  1. 此时数据从cilium_vxlan送到bpf2上的pod中的eth0网卡.(此时也是通过tcpdump抓包可得)
CPU 03: MARK 0x0 FROM 969 DEBUG: Conntrack lookup 1/2: src=10.0.0.222:7936 dst=10.0.1.208:0
CPU 03: MARK 0x0 FROM 969 DEBUG: Conntrack lookup 2/2: nexthdr=1 flags=0
CPU 03: MARK 0x0 FROM 969 DEBUG: CT verdict: New, revnat=0
CPU 03: MARK 0x0 FROM 969 DEBUG: Conntrack create: proxy-port=0 revnat=0 src-identity=3352 lb=0.0.0.0
  1. 这里我们又看到数据包被 iptables 处理了,但是此时 src 和 dst 发生了变化,也就是一个 ICMP 的reply 报文,然后需要送到 vxlan 的接口
CPU 03: MARK 0x0 FROM 969 from-endpoint: 98 bytes (98 captured), state new, , identity 3352->unknown, orig-ip 0.0.0.0
CPU 03: MARK 0x0 FROM 969 DEBUG: Conntrack lookup 1/2: src=10.0.1.208:0 dst=10.0.0.222:7936
CPU 03: MARK 0x0 FROM 969 DEBUG: Conntrack lookup 2/2: nexthdr=1 flags=1
CPU 03: MARK 0x0 FROM 969 DEBUG: CT entry found lifetime=16826421, revnat=0
CPU 03: MARK 0x0 FROM 969 DEBUG: CT verdict: Reply, revnat=0
CPU 03: MARK 0x0 FROM 969 DEBUG: Successfully mapped addr=10.

以上是关于Cilium Vxlan 跨节点通信过程的主要内容,如果未能解决你的问题,请参考以下文章

Flannel Vxlan 跨节点通信

使用Linux Bridge 搭建vxlan 实现 虚拟机跨物理机通信

Flannel IPIP 跨节点通信

k8s calico flannel cilium 网络性能测试

Flannel HOST-GW 跨节点通信

Docker网络跨主机通讯vxlan和vlan