网站首页 文章专栏 Calico 网络通信原理揭秘
Calico 网络通信原理揭秘
编辑时间:2022-08-16 12:56:50 作者:lmc 浏览量:142

Calico 是一个纯三层的数据中心网络方案,而且无缝集成像 OpenStack 这种 Iaas 云架构,能够提供可控的 VM、容器、裸机之间的 IP 通信。为什么说它是纯三层呢?因为所有的数据包都是通过路由的形式找到对应的主机和容器的,然后通过 BGP 协议来将所有路由同步到所有的机器或数据中心,从而完成整个网络的互联。
简单来说,Calico 在主机上创建了一堆的 veth pair,其中一端在主机上,另一端在容器的网络命名空间里,然后在容器和主机中分别设置几条路由,来完成网络的互联。
k8s中的pod的pause容器核心职责:首先,它作为在pod中共享Linux名称空间的基础容器;其次,启用PID(进程ID)名称空间共享后,它将作为每个pod的PID 1进程(根进程),并回收僵尸进程。

calico2.jpg


1. Calico 网络模型揭秘

下面我们通过具体的例子来帮助大家理解 Calico 网络的通信原理。任意选择 k8s 集群中的一个节点作为实验节点,进入容器 A,查看容器 A 的 IP 地址:

image.png


这里容器获取的是 /32 位主机地址,表示将容器 A 作为一个单点的局域网。

瞄一眼容器 A 的默认路由:

image.png

现在问题来了,从路由表可以知道 169.254.1.1 是容器的默认网关,但却找不到任何一张网卡对应这个 IP 地址,这是个什么鬼?

莫慌,先回忆一下,当一个数据包的目的地址不是本机时,就会查询路由表,从路由表中查到网关后,它首先会通过 ARP 获得网关的 MAC 地址,然后在发出的网络数据包中将目标 MAC 改为网关的 MAC,而网关的 IP 地址不会出现在任何网络包头中。也就是说,没有人在乎这个 IP 地址究竟是什么,只要能找到对应的 MAC 地址,能响应 ARP 就行了。

想到这里,我们就可以继续往下进行了,可以通过 ip neigh 命令查看一下本地的 ARP 缓存:

image.png

这个 MAC 地址应该是 Calico 硬塞进去的,而且还能响应 ARP。但它究竟是怎么实现的呢?

我们先来回想一下正常情况,内核会对外发送 ARP 请求,询问整个二层网络中谁拥有 169.254.1.1 这个 IP 地址,拥有这个 IP 地址的设备会将自己的 MAC
地址返回给对方。但现在的情况比较尴尬,容器和主机都没有这个 IP 地址,甚至连主机上的端口 calicba2f87f6bb,MAC 地址也是一个无用的 ee:ee:ee:ee:ee:ee。按道理容器和主机网络根本就无法通信才对呀!所以 Calico 是怎么做到的呢?这里我就不绕弯子了,实际上 Calico 利用了网卡的代理 ARP 功能。代理 ARP 是 ARP 协议的一个变种,当 ARP 请求目标跨网段时,网关设备收到此 ARP 请求,会用自己的 MAC 地址返回给请求者,这便是代理 ARP(Proxy ARP)。举个例子:

image.png

上面这张图中,电脑发送 ARP 请求服务器 8.8.8.8 的 MAC 地址,路由器(网关)收到这个请求时会进行判断,由于目标 8.8.8.8 不属于本网段(即跨网段),此时便返回自己的接口 MAC 地址给 PC,后续电脑访问服务器时,目标 MAC 直接封装为 MAC254。

现在我们知道,Calico 本质上还是利用了代理 ARP 撒了一个“善意的谎言”,下面我们来确认一下。

image.png

查看是否开启代理 ARP:

image.png

如果还不放心,可以通过 tcpdump 抓包验证一下:

image.png

总结:

Calico 通过一个巧妙的方法将 workload 的所有流量引导到一个特殊的网关 169.254.1.1,从而引流到主机的 calixxx 网络设备上,最终将二三层流量全部转换成三层流量来转发
在主机上通过开启代理 ARP 功能来实现 ARP 应答,使得 ARP 广播被抑制在主机上,抑制了广播风暴,也不会有 ARP 表膨胀的问题


2. 模拟组网

既然我们已经掌握了 Calico 的组网原理,接下来就可以手动模拟验证了。架构如图所示:

image.png

先在 Host0 上执行以下命令

ip link add veth0 type veth peer name eth0 #添加网卡
ip link show type veth #查看veth
ip link del veth0 type veth peer name eth0
ip netns add ns0
ip netns ls
ip link set eth0 netns ns0 #将eth0设置到ns0网络命名空间
ip netns exec ns0 ip a add 10.20.1.2/24 dev eth0#设置网卡ip
ip netns exec ns0 ip link set eth0 up #开启网卡
//进入命名空间查看
ip netns exec ns0 ifconfig
ip netns exec ns0 ip route list
ip netns exec ns0 route -n
//添加路由
ip netns exec ns0 ip route add 169.254.1.1 dev eth0 scope link #添加容器内路由,目的地址169.
ip netns exec ns0 ip route add default via 169.254.1.1 dev eth0
//开启veth0(宿主机上,容器内的也叫eth0)
ip link set veth0 up
ip route add 10.20.1.2 dev veth0 scope link #配置宿主机veth0的路由
ip route add 10.20.1.3 via 192.168.1.16 dev ens192 #配置路由,到Host1(10.20.1.3)通过ens192网口
etho 1 > /proc/sys/net/ipv4/conf/veth0/proxy_arp #开启ARP(地址解析协议)代理


再在 Host1 上执行以下命令

ip link add veth0 type veth peer name eth0 #添加网卡
ip link show type veth #查看veth
ip link del veth0 type veth peer name eth0
ip netns add ns0
ip netns ls
ip link set eth0 netns ns0 #将eth0设置到ns0网络命名空间
ip netns exec ns0 ip a add 10.20.1.3/24 dev eth0#设置网卡ip
ip netns exec ns0 ip link set eth0 up #开启网卡
//进入命名空间查看
ip netns exec ns0 ifconfig
ip netns exec ns0 ip route list
ip netns exec ns0 route -n
//添加路由
ip netns exec ns0 ip route add 169.254.1.1 dev eth0 scope link #添加容器内路由,目的地址169.
ip netns exec ns0 ip route add default via 169.254.1.1 dev eth0
//开启veth0(宿主机上,容器内的也叫eth0)
ip link set veth0 up
ip route add 10.20.1.3 dev veth0 scope link #配置宿主机veth0的路由
ip route add 10.20.1.2 via 192.168.1.16 dev ens192 #配置路由,到Host0(10.20.1.2)通过ens192网口
etho 1 > /proc/sys/net/ipv4/conf/veth0/proxy_arp #开启ARP(地址解析协议)代理


网络连通性测试:

image.png

实验成功!

具体的转发过程如下:

  • ns0 网络空间的所有数据包都转发到一个虚拟的 IP 地址 169.254.1.1,发送 ARP 请求。

  • Host0 的 veth 端收到 ARP 请求时通过开启网卡的代理 ARP 功能直接把自己的 MAC 地址返回给 ns0。

  • ns0 发送目的地址为 ns0(Host1) 的 IP 数据包。

  • 因为使用了 169.254.1.1 这样的地址,Host 判断为三层路由转发,查询本地路由 10.20.1.3 via 192.168.1.16 dev ens192 发送给对端 Host1,如果配置了 BGP,这里就会看到 proto 协议为 BIRD。

  • 当 Host1 收到 10.20.1.3 的数据包时,匹配本地的路由表 10.20.1.3 dev veth0 scope link,将数据包转发到对应的 veth0 端,从而到达 ns1。

  • 回程类似。

       通过这个实验,我们可以很清晰地掌握 Calico 网络的数据转发流程,首先需要给所有的 ns 配置一条特殊的路由,并利用 veth 的代理 ARP 功能让 ns 出来的所有转发都变成三层路由转发,然后再利用主机的路由进行转发。这种方式不仅实现了同主机的二三层转发,也能实现跨主机的转发。


来说两句吧
最新评论