K8s 高性能网络组件详解:Calico 的 IPIP 网络模式

admin 2022年12月10日15:27:16评论39 views字数 7879阅读26分15秒阅读模式

K8s 高性能网络组件详解:Calico 的 IPIP 网络模式

前言

本文主要分析 K8s 中网络组件 calico 的 IPIP网络模式。旨在理解 IPIP 网络模式下产生的 calixxxx,tunl0 等设备以及跨节点网络通信方式。可能看着有点枯燥,但是请花几分钟时间坚持看完,如果看到后面忘了前面,请反复看两遍,这几分钟时间一定你会花的很值。

一、Calico介绍

Calico 是 Kubernetes 生态系统中另一种流行的网络选择。虽然 Flannel 被公认为是最简单的选择,但 Calico 以其性能、灵活性而闻名。Calico 的功能更为全面,不仅提供主机和 Pod 之间的网络连接,还涉及网络安全和管理。Calico CNI 插件在 CNI 框架内封装了 Calico 的功能。
Calico 是一个基于BGP的纯三层的网络方案,与 OpenStack、Kubernetes、AWS、GCE 等云平台都能够良好地集成。Calico 在每个计算节点都利用 Linux Kernel 实现了一个高效的虚拟路由器 vRouter 来负责数据转发。每个 vRouter 都通过 BGP1 协议把在本节点上运行的容器的路由信息向整个 Calico 网络广播,并自动设置到达其他节点的路由转发规则。
Calico 保证所有容器之间的数据流量都是通过IP路由的方式完成互联互通的。Calico节点组网时可以直接利用数据中心的网络结构(L2或者L3),不需要额外的NAT、隧道或者Overlay Network,没有额外的封包解包,能够节约CPU运算,提高网络效率。

此外,Calico 基于 iptables 还提供了丰富的网络策略,实现了 K8s 的 Network Policy策略,提供容器间网络可达性限制的功能。

calico官网:https://www.projectcalico.org/

二、Calico架构及核心组件

架构图如下:

K8s 高性能网络组件详解:Calico 的 IPIP 网络模式

Calico 核心组件:
  • Felix:运行在每个需要运行 workload 的节点上的 agent 进程。主要负责配置路由及 ACLs(访问控制列表)等信息来确保 endpoint 的连通状态,保证跨主机容器的网络互通;

  • etcd:强一致性、高可用的键值存储,持久存储calico数据的存储管理系统。主要负责网络元数据一致性,确保Calico网络状态的准确性;

  • BGP Client(BIRD):读取Felix设置的内核路由状态,在数据中心分发状态。

  • BGP Route Reflector(BIRD):BGP路由反射器,在较大规模部署时使用。如果仅使用BGP Client形成mesh全网互联就会导致规模限制,因为所有BGP client节点之间两两互联,需要建立N^2个连接,拓扑也会变得复杂。因此使用reflector来负责client之间的连接,防止节点两两相连。

三、Calico工作原理

Calico 把每个操作系统的协议栈认为是一个路由器,然后把所有的容器认为是连在这个路由器上的网络终端,在路由器之间跑标准的路由协议——BGP的协议,然后让它们自己去学习这个网络拓扑该如何转发。所以 Calico 方案其实是一个纯三层的方案,也就是说让每台机器的协议栈的三层去确保两个容器,跨主机容器之间的三层连通性。

四、Calico的两种网络方式

1)IPIP
把 IP 层封装到 IP 层的一个 tunnel。它的作用其实基本上就相当于一个基于IP层的网桥!一般来说,普通的网桥是基于mac层的,根本不需 IP,而这个 ipip 则是通过两端的路由做一个 tunnel,把两个本来不通的网络通过点对点连接起来。ipip 的源代码在内核 net/ipv4/ipip.c 中可以找到。
2)BGP
边界网关协议(Border Gateway Protocol, BGP)是互联网上一个核心的去中心化自治路由协议。它通过维护IP路由表或‘前缀’表来实现自治系统(AS)之间的可达性,属于矢量路由协议。BGP不使用传统的内部网关协议(IGP)的指标,而使用基于路径、网络策略或规则集来决定路由。因此,它更适合被称为矢量性协议,而不是路由协议。

五、IPIP网络模式分析

由于个人环境中使用的是IPIP模式,因此接下来这里分析一下这种模式。

# kubectl get po -o wide -n paas | grep hellodemo-hello-perf-d84bffcb8-7fxqj   1/1     Running   0          9d      10.20.105.215   node2.perf  <none>           <none>demo-hello-sit-6d5c9f44bc-ncpql   1/1     Running   0          9d      10.20.42.31     node1.sit   <none>           <none>

进行 Ping 测试

这里在 demo-hello-perf 这个 pod 中 ping demo-hello-sit 这个 pod。

root@demo-hello-perf-d84bffcb8-7fxqj:/# ping 10.20.42.31PING 10.20.42.31 (10.20.42.31) 56(84) bytes of data.64 bytes from 10.20.42.31: icmp_seq=1 ttl=62 time=5.60 ms64 bytes from 10.20.42.31: icmp_seq=2 ttl=62 time=1.66 ms64 bytes from 10.20.42.31: icmp_seq=3 ttl=62 time=1.79 ms^C--- 10.20.42.31 ping statistics ---3 packets transmitted, 3 received, 0% packet loss, time 6msrtt min/avg/max/mdev = 1.662/3.015/5.595/1.825 ms

进入 pod demo-hello-perf 中查看这个 pod 中的路由信息

root@demo-hello-perf-d84bffcb8-7fxqj:/# route -nKernel IP routing tableDestination     Gateway         Genmask         Flags Metric Ref    Use Iface0.0.0.0         169.254.1.1     0.0.0.0         UG    0      0        0 eth0169.254.1.1     0.0.0.0         255.255.255.255 UH    0      0        0 eth0
根据路由信息,ping 10.20.42.31,会匹配到第一条。
第一条路由的意思是:去往任何网段的数据包都发往网关169.254.1.1,然后从eth0网卡发送出去。
demo-hello-perf 所在的 node node2.perf 宿主机上路由信息如下:
# route -nKernel IP routing tableDestination     Gateway         Genmask         Flags Metric Ref    Use Iface0.0.0.0         172.16.36.1     0.0.0.0         UG    100    0        0 eth010.20.42.0      172.16.35.4     255.255.255.192 UG    0      0        0 tunl010.20.105.196   0.0.0.0         255.255.255.255 UH    0      0        0 cali4bb1efe70a2169.254.169.254 172.16.36.2     255.255.255.255 UGH   100    0        0 eth0172.16.36.0     0.0.0.0         255.255.255.0   U     100    0        0 eth0172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0

可以看到一条 Destination 为 10.20.42.0 的路由。

意思是:当 ping 包来到 master 节点上,会匹配到路由 tunl0。该路由的意思是:去往 10.20.42.0/26 的网段的数据包都发往网关172.16.35.4。因为demo-hello-perf的pod在172.16.36.5上,demo-hello-sit的pod在172.16.35.4上。所以数据包就通过设备tunl0发往到node节点上。

demo-hello-sit 所在的 node node1.sit 宿主机上路由信息如下:

# route -nKernel IP routing tableDestination     Gateway         Genmask         Flags Metric Ref    Use Iface0.0.0.0         172.16.35.1     0.0.0.0         UG    100    0        0 eth010.20.15.64     172.16.36.4     255.255.255.192 UG    0      0        0 tunl010.20.42.31     0.0.0.0         255.255.255.255 UH    0      0        0 cali04736ec14ce10.20.105.192   172.16.36.5     255.255.255.192 UG    0      0        0 tunl0
当 node 节点网卡收到数据包之后,发现发往的目的 IP 为 10.20.42.31,于是匹配到 Dst 为 10.20.42.31 的路由。

该路由的意思是:10.20.42.31 是本机直连设备,去往设备的数据包发往cali04736ec14ce

为什么这么奇怪会有一个名为 cali04736ec14ce 的设备呢?这是个啥玩意儿呢?
其实这个设备就是 veth pair 的一端。在创建demo-hello-sit 时 calico 会给demo-hello-sit 创建一个 veth pair 设备。一端是demo-hello-sit 的网卡,另一端就是我们看到的 cali04736ec14ce
接着验证一下。我们进入 demo-hello-sit 的 Pod,查看到 4 号设备后面的编号是:122964
root@demo-hello-sit--6d5c9f44bc-ncpql:/# ip a1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000    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 forever2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000    link/ipip 0.0.0.0 brd 0.0.0.04: eth0@if122964: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1380 qdisc noqueue state UP group default     link/ether 9a:7d:b2:26:9b:17 brd ff:ff:ff:ff:ff:ff link-netnsid 0    inet 10.20.42.31/32 brd 10.20.42.31 scope global eth0       valid_lft forever preferred_lft forever

然后我们登录到 demo-hello-sit 这个pod所在的宿主机查看

# ip a | grep -A 5 "cali04736ec14ce"122964: cali04736ec14ce@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1380 qdisc noqueue state UP group default     link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 16    inet6 fe80::ecee:eeff:feee:eeee/64 scope link        valid_lft forever preferred_lft forever120918: calidd1cafcd275@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1380 qdisc noqueue state UP group default     link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 2

发现 pod demo-hello-sit中 的另一端设备编号和这里在 node 上看到的 cali04736ec14ce 编号 122964 是一样的

所以,node上的路由,发送 cali04736ec14ce 网卡设备的数据其实就是发送到了demo-hello-sit 的这个 Pod 中去了。到这里 Ping 包就到了目的地。
注意看 demo-hello-sit 这个 Pod 所在的宿主机的路由,有一条 Destination 为10.20.105.192 的路由
# route -nKernel IP routing tableDestination     Gateway         Genmask         Flags Metric Ref    Use Iface...0.0.0.0         172.16.35.1     0.0.0.0         UG    100    0        0 eth010.20.105.192   172.16.36.5     255.255.255.192 UG    0      0        0 tunl0...
再查看一下demo-hello-sit 的 Pod 中路由信息,和 demo-hello-perf 的 Pod 中是一样的。
所以综合上述例子来看,IPIP 的网络模式就是将IP网络封装了一层。特点就是所有 Pod的数据流量都从隧道 tunl0 发送,并且 tunl0 这里增加了一层传输层的封包操作。

六、抓包分析

在 demo-hello-perf 这个 Pod 中 Ping demo-hello-sit 这个 Pod,接着在 demo-hello-sit 这个 Pod 所在的宿主机进行 tcpdump。
# tcpdump  -i eth0 -nn -w icmp_ping.captcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

在 demo-hello-perf 这个 pod 中进行 ping demo-hello-sit 的操作

root@demo-hello-perf-d84bffcb8-7fxqj:/# ping 10.20.42.31PING 10.20.42.31 (10.20.42.31) 56(84) bytes of data.64 bytes from 10.20.42.31: icmp_seq=1 ttl=62 time=5.66 ms64 bytes from 10.20.42.31: icmp_seq=2 ttl=62 time=1.68 ms64 bytes from 10.20.42.31: icmp_seq=3 ttl=62 time=1.61 ms^C--- 10.20.42.31 ping statistics ---3 packets transmitted, 3 received, 0% packet loss, time 6msrtt min/avg/max/mdev = 1.608/2.983/5.659/1.892 ms
结束抓包后下载 icmp_ping.cap 到本地 windows 进行抓包分析
能看到该数据包一共5层,其中IP(Internet Protocol)所在的网络层有两个,分别是Pod 之间的网络和主机之间的网络封装。

K8s 高性能网络组件详解:Calico 的 IPIP 网络模式

红色框选的是两个 Pod 所在的宿主机,蓝色框选的是两个 Pod 的 IP,src 表示发起 ping 操作的 Pod 所在的宿主机 ip 以及发起 ping 操作的 pod 的ip,dst 表示被ping的pod 所在的宿主机 ip 及被 ping 的 pod 的 ip。
根据数据包的封装顺序,应该是在 demo-hello-perf ping demo-hello-sit 的 ICMP 包外面多封装了一层主机之间的数据包。

K8s 高性能网络组件详解:Calico 的 IPIP 网络模式

可以看到每个数据报文共有两个IP网络层,内层是 Pod 容器之间的 IP 网络报文,外层是宿主机节点的网络报文(2个node节点)。之所以要这样做是因为 tunl0 是一个隧道端点设备,在数据到达时要加上一层封装,便于发送到对端隧道设备中。
两层封包的具体内容如下:

K8s 高性能网络组件详解:Calico 的 IPIP 网络模式

Pod 间的通信经由 IPIP 的三层隧道转发,相比较 VxLAN 的二层隧道来说,IPIP 隧道的开销较小,但其安全性也更差一些。

七、Pod 到 SVC 的访问

查看 Service

# kubectl get svc -o wide -n paas | grep hellodemo-hello-perf              ClusterIP   10.10.255.18    <none>        8080/TCP              10d    appEnv=perf,appName=demo-hellodemo-hello-sit               ClusterIP   10.10.48.254    <none>        8080/TCP              10d    appEnv=sit,appName=demo-hello

在 Pod demo-hello-sit 的宿主机上抓包

# tcpdump -i eth0 -nn -w svc.captcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

测试访问,在demo-hello-sit中curl demo-hello-perf的svc的地址和端口

root@demo-hello-perf-d84bffcb8-7fxqj:/# curl -I http://10.10.48.254:8080/actuator/healthHTTP/1.1 200Content-Type: application/vnd.spring-boot.actuator.v3+jsonTransfer-Encoding: chunkedDate: Fri, 30 Apr 2021 01:42:56 GMT
root@demo-hello-perf-d84bffcb8-7fxqj:/# curl -I http://10.10.48.254:8080/actuator/healthHTTP/1.1 200Content-Type: application/vnd.spring-boot.actuator.v3+jsonTransfer-Encoding: chunkedDate: Fri, 30 Apr 2021 01:42:58 GMT
root@demo-hello-perf-d84bffcb8-7fxqj:/# curl -I http://10.10.48.254:8080/actuator/healthHTTP/1.1 200Content-Type: application/vnd.spring-boot.actuator.v3+jsonTransfer-Encoding: chunkedDate: Fri, 30 Apr 2021 01:42:58 GMT

结束抓包,下载svc.cap文件放到wireshark中打开查看

K8s 高性能网络组件详解:Calico 的 IPIP 网络模式

可以看到wireshark中Src和Dst的结果。任然是和上面pod中访问pod的ip地址一样。这里Src和Dst任然是两个pod的宿主机的内网ip和两个pod自己的ip地址。是用ipip的方式进行通信的。
通过以上例子演示,应该就看明白了IPIP网络模式的通信方式了吧!
来源:本文转自公众号运维开发技术,点击查看原文
12月22日,全球下一代软件工程线上峰会,DevOps、AIOps、研发效能等精彩话题,应有尽有,等你来~
K8s 高性能网络组件详解:Calico 的 IPIP 网络模式
近期好文:

史上最简明的 Tcpdump 入门指南,看这一篇就够了

Linux Shell 脚本的 10 个有用的“面试问题和解答”

“高效运维”公众号诚邀广大技术人员投稿
投稿邮箱:[email protected],或添加联系人微信:greatops1118。
K8s 高性能网络组件详解:Calico 的 IPIP 网络模式
点个“在看”,一年不宕机

原文始发于微信公众号(高效运维):K8s 高性能网络组件详解:Calico 的 IPIP 网络模式

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年12月10日15:27:16
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   K8s 高性能网络组件详解:Calico 的 IPIP 网络模式http://cn-sec.com/archives/1453418.html

发表评论

匿名网友 填写信息