PROXY_ARP在CALICO网络中的应用
一、calico 网络中的proxy_arp
Calico 作为数据中心网络解决方案之一,支持BGP、IPIP、VXLAN 协议等多种协议。无缝集成像 OpenStack 这种 Iaas 云架构,能够提供可控的 VM、容器、裸机之间的 IP 通信。
Calico 利用了网卡的代理 ARP 功能,通过一个巧妙的方法将容器的所有流量引导到一个特殊的网关 1xx.2xx.1.1,从而引流到主机的 calixxx 网络设备上。
简单来说,Calico 在主机上创建了一大堆 veth pair,其中一端在主机上,另一端在容器的网络命名空间里,然后在容器和主机中分别设置路由,来完成网络的互联。容器获取的是 /32 位主机地址,表示将容器作为一个单点的局域网,1xx.2xx.1.1 是容器的默认网关。A容器访问B容器时,发出ARP请求,请求B容器的MAC地址,A容器的eth0网卡与主机的 calixxx 网卡构成一对veth pair,将流量引流到calixxx 网卡上,calixxx 网卡开启proxy_arp功能,代理B响应arp请求。在主机calixxx 网卡上通过开启代理 ARP 功能来实现 ARP 应答,使得 ARP 广播被抑制在主机上,抑制了广播风暴,也不会有 ARP 表膨胀的问题。
二、版本信息
calico:3.18.1
三、pod gw ip:1xx.2xx.1.1
k8s集群中,发现多个pod的网关是1xx.2xx.1.1,
kubectl -n kube-system get pod | egrep 'prometheus|kafka' prometheus-548969f5dd-ndzjg 2/2 Running 0 31d prometheus-kafka-adapter-d47d5477f-g4d8n 1/1 Running 0 36d kubectl -n kube-system exec prometheus-548969f5dd-ndzjg -- ip r s 0.0.0.0/0 default via 1xx.2xx.1.1 dev eth0 [root@vm-paasyy15-129 /]# kubectl -n kube-system exec prometheus-kafka-adapter-d47d5477f-g4d8n -- ip r s 0.0.0.0/0 default via 1xx.2xx.1.1 dev eth0 |
如下图,prometheus、prometheus-kafka-adapter pod内网关都是1xx.2xx.1.1.
接下来再来看我们部署的redis集群,以151上的一主一从redis pod为例,
151上的一主一从redis pod默认网关也都是1xx.2xx.1.1。
四、proxy_arp启停实验
以151上运行的一主一从redis pod为例讲解,各pod内通过ip a 查看到的网络配置信息如下:
从上面截图可以看到,两个pod的内部网卡名均为eth0,对端网卡索引号分别是42、41,知道了索引号,我们在151这台宿主机上通过命令ip link | egrep '^42|^41'查询:
就能查询到这两个redis pod所连接的宿主机对端网卡分别为:cali896770bc8d0、cali58461cd80b0。
最终收集整理信息见下面表格:
pod name | pod ip | 网卡命名 | 网卡 索引值 | 对端 网卡命名 | 对端 网卡索引值 |
tq-redis01-0-5685bc957b-qmp2j | 197.166.49.38/32 | eth0 | 4 | cali896770bc8d0 | 42 |
tq-redis01-3-558c6bf8d5-8nn57 | 197.166.49.37/32 | eth0 | 4 | cali58461cd80b0 | 41 |
kubectl exec -it tq-redis01-0-5685bc957b-qmp2j -n tq -c redis -- sh,进入该pod,在未做实验前,该pod内ping其他redis pod都是通的。
做如下操作后,151上的这两台redis pod到其他pod网络将不可达。
1)查看151上两台redis容器的PID:
docker inspect -f {{.State.Pid}} f2f982722d73
57160
docker inspect -f {{.State.Pid}} d80c9dbf1477
55978
2)用nsenter命令进入151两个redis容器的网络命令空间,清除redis容器 eth0 arp缓存:
nsenter -n -t 57160
ip neigh flush dev eth0
nsenter -n -t 55978
ip neigh flush dev eth0
3)关闭proxy_arp
echo 0 >/proc/sys/net/ipv4/conf/cali896770bc8d0/proxy_arp
echo 0 >/proc/sys/net/ipv4/conf/cali58461cd80b0/proxy_arp
再次测试ping,不通,结果如下:
4)恢复redis pod网络
echo 1 >/proc/sys/net/ipv4/conf/cali896770bc8d0/proxy_arp
echo 1 >/proc/sys/net/ipv4/conf/cali58461cd80b0/proxy_arp
或执行:
sysctl -w net.ipv4.conf.cali896770bc8d0.proxy_arp=1
sysctl -w net.ipv4.conf.cali58461cd80b0.proxy_arp=1
五、总结
最后,通过官方资料和个人实验,我们一起来总结calico网络请求响应arp的过程,得出需具备下面三个条件:
1)The host receives an ARP request on an interface which has proxy-ARP enabled.
2)The host knows how to reach the destination
3)The interface that the host would use to reach the destination is not the same one that it received the ARP request on
翻译过来就是
1) 宿主机的arp代理得打开
2) 宿主机需要有访问目的地址的明确路由
3) 发送arp request的接口与接收arp request的接口不能是相同,即容器中的默认网关不能是calico的虚拟网关
参考链接
https://github.com/projectcalico/calico/issues/4186
https://www.dasblinkenlichten.com/getting-started-with-calico-on-kubernetes/