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 1.11.4 报文格式
跨节点通信特点
分析不同节点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 抓包
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_vxlan_pod1.cap
ens33_pod1.cap
lxc_pod2.cap
cilium_vxlan_pod2.cap
通过上述抓包,我们验证了场景:
跨节点通信的时候,pod 的报文需要pod内部封装一次,然后通过 HOST NS(宿主机)vxlan 在进行封装,然后通过宿主机的物理网卡传到对端 宿主机,在经过 vxlan 解封装后 直接 redict 到pod 内部,而不需要经过它对应的 lxc 网卡,我们就可以论证下图的通信流程图。
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 网卡和
# 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
关键部分
- 第一个 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.2080
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
- 第二个 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.1308472
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
- 第三个 Conntrack lookup 是返回的 reply 报文,但是并没有 HOST NS 部分的处理。
可以参考下图,我们发现 NodePort Remote Endpoint 的时候是具有 redict 的能力的
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.2224864
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
查看报文关键部分
- 这里看到数据被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
- 此时数据从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.2080
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
- 这里我们又看到数据包被 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.2227936
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 跨节点通信过程的主要内容,如果未能解决你的问题,请参考以下文章
使用Linux Bridge 搭建vxlan 实现 虚拟机跨物理机通信