Calico IPIP 配置

Calico集群中存在跨网段节点时,假设集群中包含的节点IP为:

  • Node1:192.168.244.233
  • Node2:192.168.204.100
  • Node3:192.168.205.155

在 192.168.244.233 上查路由信息如下:

1
2
3
4
5
6
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.244.1   0.0.0.0         UG    100    0        0 eth0
30.233.104.0    192.168.204.100 255.255.255.192 UG    0      0        0 tunl0
30.233.135.0    192.168.205.155 255.255.255.192 UG    0      0        0 tunl0
30.233.166.128  0.0.0.0         255.255.255.192 U     0      0        0 *
192.168.244.0   0.0.0.0         255.255.255.0   U     100    0        0 eth0

上述路由表中,有两条路有信息(跨节点Pod访问)使用 192.168.204.100 和 192.168.205.155 作为网关,出口设备为 tunl0 。

值得注意的是这两条路由信息中,Gateway 地址和任意主机ip都不在同一个子网,即二层不可达

Calico在创建路由时使用了onlink参数,并且强制指定了设备参数为tunl0

1
2
ip route add 30.233.104.0/26 via 192.168.204.100 dev tunl0 onlink
ip route add 30.233.135.0/26 via 192.168.205.155 dev tunl0 onlink

根据Linux的规则:配置路由时,内核会检查网关是否二层可达,即网关地址必须和主机IP位于同一子网。通过onlink参数可以跳过该检查

回顾一下Linux的网络通信的基础知识:在物理层和数据链路层,通讯是基于源地址和目的地址的mac地址进行的

当dstIP和主机同网段时,内核会直接查询本地arp缓存,看看是否有dstIP对应的mac地址:

  • MAC存在:直接向链路上发包,包中包括原mac及目标mac
  • MAC不存在:向网络发arp广播,用来查找与dstIP对应的MAC地址,查询成功直接发送数据包

当dstIP和主机不同网段时,上述过程的区别在于:内核查询 GatewayIP 的 Mac 地址,并向其发送数据包(dstmac地址是网关)。

为了让无法获取网关 MAC 的路由信息生效,我们可以进行一些特殊设置:

  • 方式一:打开设备的 ARPPROXY
  • 方式二:将路由信息指向 tunnel 设备

Calico IPIP 模式采用的是方式二。

calico 在 pod 中设置网关地址为 169.254.1.1 则通过 ARPPROXY 方式使容器内的流量能够到达物理机。

当在Calico集群中开启IPIP时,在用户宿主机中会自动创建一个tunl0设备。 查看 tunl0 设备详情如下:

当系统加载 ipip 模块或者创建一个 ipip 设备时,Linux 内核会在每个命名空间中创建一个 tunl0 默认设备,属性为 local=any 和 remote=any。

tunl0 是工作在 one-to-many 模式下的,当系统接收到 ipip 协议数据包时,如果内核找不到 local/remote 属性与数据包中源地址或目标地址更匹配的另一个 ipip 设备,内核会触发回退,将报文转发到 tunl0 。

此时 tunl0 构造一个新的数据包,源地址是本机IP,目的地址是网关IP,从默认路由设备发出。

通过上述方式实现: tunl0 会处理发往不同 node 的 IPIP 数据包。

关于tunl0的描述:https://developers.redhat.com/blog/2019/05/17/an-introduction-to-linux-virtual-interfaces-tunnels#ip6tnl_tunnel

相比 vxlan 模式的优势

calico 同样支持 vxlan 模式,但是相比 ipip 模式,vxlan 模式下有一定性能损失,原因如下:

  • ipip 协议本身比 vxlan 更轻量

附录:手动测试 IPIP 模式

在 SERVER1 和 SERVER2 中创建一个虚拟网络,网段为 192.168.0.0/16。

其中子网分配如下:

  • 192.168.1.0/24 -> SERVER1
  • 192.168.2.0/24 -> SERVER2
1
2
3
# IP 信息
SERVER1_IP=172.24.244.233
SERVER2_IP=172.24.244.100

通过以下命令,我们分别在 SERVER1 和 SERVER2 上创建虚拟网卡 loop1 ,并且分配虚拟网络的 IP

1
2
3
4
# 虚拟设备IP信息
- 192.168.1.10(loop1)-> SERVER1
- 192.168.2.10(loop2) -> SERVER2

SERVER1 上执行:

1
2
3
4
5
6
7
8
modprobe ipip
sudo sysctl net.ipv4.ip_forward=1
# 创建虚拟网卡
sudo ip link add name loop1 type dummy
sudo ip addr add 192.168.1.10 dev loop1
sudo ip link set loop1 up
# 添加路由
sudo ip route add 192.168.2.0/24 dev tunl0 via $SERVER2_IP onlink

SERVER2 上执行:

1
2
3
4
5
6
7
8
modprobe ipip
sudo sysctl net.ipv4.ip_forward=1
# 创建虚拟网卡
sudo ip link add name loop2 type dummy
sudo ip addr add 192.168.2.10 dev loop2
sudo ip link set loop2 up
# 添加路由
sudo ip route add 192.168.1.0/24 dev tunl0 via $SERVER1_IP onlink

连通性测试,在 SERVER1 上执行

1
ping -I 192.168.1.10 192.168.2.10

参考:https://medium.com/@samueldarwin/full-mesh-ipip-tunnels-d16888913e40