K8s网络实战分析之Calico-ipip模式
Kubernetes为每个Pod都分配了唯一的IP地址,一个Pod里的多个容器共享PodIp地址。Kubernetes要求底层网络支持集群内任意两个Pod间的TCP/IP直接通信。Kubernetes的跨主机任意Pod访问方式主要是遵循CNI容器网络规范,目前已经有多个开源组件支持CNI,包括Flannel、Open VSwitch、Calico等。本文主要介绍在Calico的ipip模式下,K8s的Pod间访问原理。
Calico容器网络简介
Calico是一个基于BGP的纯三层网络方案,其会为每个容器(pod)分配一个可路由的IP,在通信时不需要解包和拆包,因此网络性能损耗小,易于排查和水平扩展。
标题Calico架构
Calico网络模型主要工作组件:
-
Felix:Calico Agent,运行在每一台 Host 的 agent 进程,主要负责网络接口管理和监听、路由、ARP 管理、ACL 管理和同步、状态上报等,保证跨主机容器的网络互通。
-
etcd:Calico的后端存储,主要负责网络元数据一致性,确保Calico网络状态的准确性,可以与kubernetes共用;
-
BGP Client(BIRD):Calico 为每一台 Host 部署一个 BGP Client,使用 BIRD 实现,BIRD 是一个单独的持续发展的项目,实现了众多动态路由协议比如 BGP、OSPF、RIP 等。负责将Felix 在各Node上的设置通过BGP协议广播到Calico网络,从而实现网络互通。
-
BGP Route Reflector:在大型网络规模中,如果仅仅使用 BGP client 形成 mesh 全网互联的方案就会导致规模限制,因为所有节点之间俩俩互联,需要 N^2 个连接,为了解决这个规模问题,可以采用 BGP 的 Router Reflector 的方法,使所有 BGP Client 仅与特定 RR 节点互联并做路由同步,从而大大减少连接数。
IPIP模式简介
Calico中的IP Pool可以使用两种模式:BGP或者IPIP。本文使用的是IPIP模式,是一种将各Node的路由之间做一个tunnel,再把网络连接起来的模式:
从字面上说,就是将一个IP数据包套在另一个IP包里,使用到了Linux提供的隧道技术。可以理解为一个基于IP层的网桥,将两个本不通的网络通过点对点连接起来。
K8s-Calico-IPIP网络实战分析
下面我们就进行基于Calico-IPIP模式下的K8s容器互联网络分析。
##实验准备
准备了1master 2slaver的K8s集群,设置为Calico-IPIP网络。每个slaver内(node1,node2)分别部署了一个Pod容器,结构示意图如下:
网络结构解析
pod网络
首先通过指令 kubectl exec -it pod1 /bin/bash</font color=grey> 进入pod1容器中,再使用指令 ip addr</font color=grey> 查看pod1内的网络设备。
ip addr
1: 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 forever
4: eth0@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1440 qdisc noqueue state UP group default
link/ether ce:83:2b:89:af:9e brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.100.15.150/32 scope global eth0
valid_lft forever preferred_lft forever
可以看到,pod只有普通的loopback和eth0。
node网络
先查看node网络设备。
ip addr
...省略部分
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:16:3e:02:03:5c brd ff:ff:ff:ff:ff:ff
inet 172.31.112.2/20 brd 172.31.127.255 scope global dynamic eth0
valid_lft 311927346sec preferred_lft 311927346sec
4: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1440 qdisc noqueue state UNKNOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
inet 10.100.15.128/32 brd 10.100.15.128 scope global tunl0
valid_lft forever preferred_lft forever
26: cali3ef8aad4b4e@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1440 qdisc noqueue state UP group default
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 1
node中除了eth0外,多了tunl0和cali3ef8aad4b4e(下面简称为cali.4e),结合之前的Calico简介,大家肯定可以猜到,tunl0就是Calico在IPIP模式下的隧道名称 ,而cali.4e是啥子类,注意到,该设备的编号为26。让我们回到pod1中,查看pod1内的ip link:
$ip link show eth0
4: eth0@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1440 qdisc noqueue state UP mode DEFAULT group default
link/ether ce:83:2b:89:af:9e brd ff:ff:ff:ff:ff:ff link-netnsid 0
eth0@if26,这里eth0连接的设备号也是26!其实这个设备就是veth pair,K8s在创建Pod的时候,会创建一个veth pair设备。设备的一端是pod2的网卡,另一端就是我们在node中看见的cali.4e了。是不是清楚了很多☺node2与之类似。
下面我们将node节点的route规则也贴上,后面会用到。
node1
route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.31.127.253 0.0.0.0 UG 0 0 0 eth0
10.100.6.128 172.31.112.1 255.255.255.192 UG 0 0 0 tunl0
10.100.9.192 172.31.127.252 255.255.255.192 UG 0 0 0 tunl0
10.100.15.128 0.0.0.0 255.255.255.192 U 0 0 0 *
10.100.15.129 0.0.0.0 255.255.255.255 UH 0 0 0 cali386c6dca3ac
10.100.15.150 0.0.0.0 255.255.255.255 UH 0 0 0 cali3ef8aad4b4e
169.254.0.0 0.0.0.0 255.255.0.0 U 1002 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.31.112.0 0.0.0.0 255.255.240.0 U 0 0 0 eth0
node2
route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.31.127.253 0.0.0.0 UG 0 0 0 eth0
10.100.6.128 172.31.112.1 255.255.255.192 UG 0 0 0 tunl0
10.100.9.192 0.0.0.0 255.255.255.192 U 0 0 0 *
10.100.9.193 0.0.0.0 255.255.255.255 UH 0 0 0 cali4360a48538f
10.100.9.206 0.0.0.0 255.255.255.255 UH 0 0 0 cali2d771657bc2
10.100.9.207 0.0.0.0 255.255.255.255 UH 0 0 0 cali7116f2b12fa
10.100.15.128 172.31.112.2 255.255.255.192 UG 0 0 0 tunl0
169.254.0.0 0.0.0.0 255.255.0.0 U 1002 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.31.112.0 0.0.0.0 255.255.240.0 U 0 0 0 eth0
网络结构小结
根据上节的信息,绘出当前实验网络的主要设备图。后面将进行网络连接实战。
网络连接实战
node间连接
很容易的,我们先猜测一个从pod2发往pod1的ip数据流向。
下面让我们一起来验证我们的猜测吧!使用的工具就是tcpdump啦~
分别在两个node的Cali.c2、tunl0、eth0出进行抓包分析,结果如下图所示,其中Cali.c2与tunl0的ip完全一致,因此合并输出。
按照标志的①、②、③、④来依次分析:
①:上节已经说了,pod2中的eth0(即图中的vthe0)与Cali.c2是一对veth pair,因此,Cali.c2接收到的ip流向一定与vthe0相同,为 10.100.9.206->10.100.15.150</font color=grey>。查看之前的node2 route表,发现有一条 :
Destination Gateway Genmask Flags Metric Ref Use Iface
10.100.15.128 172.31.112.2 255.255.255.192 UG 0 0 0 tunl0
所有发往10.100.15.128/255.255.255.192的ip报都需要通过tunl0,经过172.31.112.2作为gateway发送。因此,cali.c2的ip报会发往tunl0。
②:经过tunl0的ip报会被再封上一层ip。通过node2 的route规则,会发往eth0,因此我们在eth0处的抓包结果为 172.31.127.252 > 172.31.112.2: IP 10.100.9.206 > 10.100.15.150</font color=grey>
Destination Gateway Genmask Flags Metric Ref Use Iface
172.31.112.0 0.0.0.0 255.255.240.0 U 0 0 0 eth0
③、④:三和四其实就是①、②的逆过程,检查node1的route表即可知道流向。etho0将ipip拆封后,将流量发给tunl0,tunl0再转发给cali.4e。
Destination Gateway Genmask Flags Metric Ref Use Iface
10.100.15.150 0.0.0.0 255.255.255.255 UH 0 0 0 cali3ef8aad4b4e
node内连接
如果是同一个node内的两个pod进行访问,那么还会走tunl0进行ipip封装吗?
其实很容易回答这个问题,通过上节的route规则就可以知道,Calico会为每一个node分配一小段网络,同时会Wie每个pod创建一个“入”的ip route规则。如下图所示,当从pod2访问pod3时,Cali.c2是直接发出10.100.9.206-> 10.100.9.207</font color=grey>流量的,在node2的ip route中,发往10.100.9.207的ip报直接会被转发到cali.fa,不会用到tunl0,只有在node间访问的时候才会使用tunl0进行ipip封装!
Destination Gateway Genmask Flags Metric Ref Use Iface
10.100.9.207 0.0.0.0 255.255.255.255 UH 0 0 0 cali7116f2b12fa
总结
通过上节的实战与分析,相信大家一定对Calico-ipip网络有了比较清晰的印象,文章最后做个小结:
- IPIP模式下,node间的Pod访问会使用IPIP技术对出node的ip报进行隧道封装
- node内的Pod访问不会用到ipip隧道封装。
- Pod的ip都是由calico-node设置的IP地址池进行分配的,docker0对kubernetes设置的Pod的IP地址将不再起作用。
下一篇我会基于本文的实战基础,对kubernetes service的网络调用进行实战分析。
更多推荐
所有评论(0)