一、Kubernetes网络基础
1、kubernetes的网络层级
- 节点网络:集群宿主机节点间的网络通信,并且负责打通与集群外部的通讯。
- pod网络:为集群上的pod提供网络,通过CNI网络插件来完成,如Fannel、Calico、Cilium等。
- service网络:部署集群时指定网段,service从这里面分配。service对象的IP地址存在于相关的ipvs、iptables规则中,k8s集群自行管理
2、kubernetes集群中的流量
Kubernetes网络中主要存在四种流量
- 同一pod内的容器间通讯
- pod间的通讯
- pod与service的通讯
- 集群外部流量与service间的通讯
3、CNI插件条件
pod网络插件,需要满足的功能要求
- 所有pod间直接通信而不需要通过NAT机制
- 所有节点与pod间直接通讯而不需要通过NAT机制
- 所有pod对象都位于同一平面网络内
4、CNI插件的类型
网络插件:负责将pod连接到网络中
IPAM:(IP地址管理),负责分配pod IP地址
5、CNI插件的网络模型
overlay:覆盖网络,基于数据包的二次加密进行通讯。
缺点:对性能有轻微影响,封装数据包的过程需要占用少量的CPU,由于数据包中需要额外的字节来对封装进行编码,(添加VXLAN或者IP-in-IP头),从而减少了可发送的内部数据包的最大大小,意味着相同的数据需要发送更多次。
route:路由网络,基于路由条目进行通信。
二、Flannel网络插件
1、Flannel支持三种后端实现
VXLAN:经典模式
host-gw:
UDP:已经弃用,性能较低
2、VXLAN模式
1.概述
cni0:他同docker网络模式不同的是,docker默认会创建一个名为docker0的网桥,而flannel会通过一个cni0来替换docker0。
overlay:(覆盖网络),在现有的三层网络之下,"覆盖一层"虚拟的,由内核VXLAN模块负责维护的二层网络,使得在连接在这个VXLAN二层网络的pod之间,可以像在同一个局域网里一样,自由通讯。
VXLAN:(虚拟可扩展局域网),是linux内核本身就支持的一种网络虚拟化技术。VXLAN完全就可以在内核实现封装和解封装的行为。
架构图
VTEP:(VXLAN Tunnel End Point 虚拟隧道端点),是宿主机上的特殊的网络设备,它既有IP地址,也有MAC地址;可以封装和解封装二层数据帧;这个行为都在内核中完成。
2.工作流详解
根据下图来进行一系列的分析
如上图所示,假设我们给pod配置的子网范围(CIDR)是10.244.0.0./16(在kube-controller-manager中配置),假设container-1要访问container-2,这个源地址为10.0244.0.2,目标地址为10.244.1.3的IP包,会先到cni0的网桥上,然后被路由到flannel.1上进行处理封装,查看Node1上的路由表如下
$ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
...
10.244.0.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0
10.244.1.0 10.244.1.0 255.255.255.0 UG 0 0 0 flannel.1
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
因为目标pod的地址为10.244.1.3,根据路由的最长匹配原则,匹配到第二条。也就是下面这条,这条路由信息是由每台宿主机上的flanneld进程维护的,比如当一个新node节点启动并且加入到Flannel网络之后,在所有的node节点就会出现这么一条路由规则。
10.244.1.0 10.244.1.0 255.255.255.0 UG 0 0 0 flannel.1
这条指定了目标网段为10.244.1.0的数据包,都交由flannel.1设备进行处理,网关是10.244.1.0,正是隧道的另一端VTEP设备,也就是宿主机node2的flannel.1设备。
注:下面会将Node1、Node2的VETP设备称为源VETP设备和目标VETP设备,数据包称为原始数据包
由于flannel的目的是通过VETP设备将集群变为一个虚拟二层网络。即通过mac地址进行通讯,通过路由表已知目标设备的IP,我们再通过APR协议来获得目标VTEP的 Mac地址。
这时flannel.1设备将原始数据包的包头进行了二层封包,将目的VTEP设备的mac地址封到了头部,但是,我们并不能知道,目标容器在哪一个宿主机,我们还要想办法知道对面宿主机的IP和mac地址,把我们的这个数据包还要再次进行封装;
为了让对端接收到数据帧的时候,知道这是一个VXLAN的数据帧,所以我们在前面封装一个特殊的VXLAN头VNI,VNI是一个32位的标识符,用于区分不同的VXLAN隧道,来表示这是一个VXLAN专用数据帧。
然后linux内核会把他封装成一个普通的UDP包(默认4789端口)发出去,(因为UDP的简单性和高性能等特点,所有封装UDP数据包),这时内部的数据包已经封装完成,就差获取目标容器的宿主机的IP地址;flannel会维护一个FDB(Forwarding Database)转发数据库,里面有其他Node节点IP地址与其VTEP的MAC地址的对应关系,来获取目标Node节点的IP地址,以及Mac地址,最终完成数据包的封装,通过低层网络发出去。FDB如下
# 在Node 1上,使用"目的VTEP设备"的MAC地址进行查询
$ bridge fdb show flannel.1 | grep 5e:f8:4f:00:e3:37
5e:f8:4f:00:e3:37 dev flannel.1 dst 10.168.0.3 self permanent
这时候,完整的数据帧就出来了,如下图所示
这个帧会经过宿主机网络来到 Node 2 的 eth0 网卡。这时候,Node 2 的内核网络栈会发现这个数据帧里有 VXLAN Header,并且 VNI=1。所以 Linux 内核会对它进行拆包,拿到里面的内部数据帧,然后根据 VNI 的值,把它交给 Node 2 上的 flannel.1 设备。而 flannel.1 设备则会进一步拆包,取出"原始 IP 包"。最终,IP 包就进入到了 container-2 容器的 Network Namespace 里。以上,就是 Flannel VXLAN 模式的具体工作原理了
3.VXLAN模式简单概述
在Flannel的VXLAN模式下,数据包的流程如下:
-
源容器发送数据包:源容器(例如Container-1)生成一个IP数据包,并将其发送到本地的cni0设备。
-
数据包到达本地节点:数据包通过本地节点的cni0设备进入Linux内核。
-
封装数据包:Linux内核根据路由表中的信息,将数据包封装在VXLAN头部中。VXLAN头部包含了目标VTEP设备的MAC地址和IP地址,以及VNI(VXLAN Network Identifier)标识。
-
发送封装后的数据包:封装后的数据包通过UDP协议的4789端口发送到目标节点。
-
目标节点接收数据包:目标节点的Linux内核接收到UDP数据包。
-
解封装数据包:目标节点的Linux内核根据VXLAN头部中的VNI标识,将数据包解封装,并将其发送到目标VTEP设备(例如flannel.1)。
-
转发数据包:目标VTEP设备将数据包转发给目标容器(例如Container-2)。
-
目标容器接收数据包:目标容器接收到数据包,并进行相应的处理。
3、host-gw模式
1.概述
host-gw模式为三层解决方案;不存在flannel.1的设备,因为不需要进行加密,
工作原理:将Flannel子网的下一跳配置成宿主机的IP地址,主机充当网关;flannel 子网和主机都保存到etcd中,flanneld需要watch这些键值的变化,实时更新路由表即可。
host-gw模式必须要求宿主机二层互通。
2.工作流详解
根据下图进行分析
假设Node 1上的infra-container-1要访问Node 2 上的infra-container-2,当你新增node节点时,flannel会在每个节点上创建一条如下的规则,
$ ip route
...
10.244.1.0/24 via 10.168.0.3 dev eth0
表示为,如果目标IP地址的网段是10.244.1.0,则发往eth0网卡,下一跳的IP地址为10.168.0.3,也就是Node 2的网卡。
当IP包从网络层进入到数据链路层进行封装的时候,就会将下一跳的地址作为Mac地址,作为目的mac地址,显然这个mac地址就是node 2的地址,这样就可以通过二层网络进入到node 2上。
当node 2拿到数据包后,发现目标的IP地址为infra-container-2的IP地址,这时根据路由表,再发给cni0网桥,进入infra-container-2中。
3.限制
要求集群宿主机之间是二层联通的
三、Calico网络插件
1、BGP协议
1.概念
AS:autonomous system,当路由发生变化时,进行路由通告的范围。
IGP:Interior Gateway Protocol,只在AS内部进行更新的路由协议,比如RIP(距离矢量路由洗衣)、OSPF(链路状态路由协议)、IS-IS等。
BGP:Border Gateway Protocol,在AS与AS之间同步路由协议。
BGP AS号:2字节长度AS号范围是1-65535,共有AS的范围是1-64511,私有AS范围是64512-65534
BGP邻居:
- 使用TCP传递信息,端口号为179。
- BGP不会主动发现BGP邻居,邻居需要手动配置;必须双方都指定邻居,互发数据包才行。
- 一个AS内可能有多个边界路由器,同一个AS内的边界路由器建立的邻居关系为Internal BGP(iBGP),不同AS邻居关系为External BGP(eBGP);
- BGP要求eBGP必须直连;
- 只有BGP形成邻居后,才开始交换路由信息,之后就是增量更新
BGP TTL:BGP可能会经过多个AS,防止环路,经过的每一个AS都打上AS号,当出现相同的AS号时,判断为出现环路,丢弃路由;BGP强制在AS内部只传一跳。
BGP 路由表:在边界路由器中:BGP得到的路由与普通路由分开存放,边界路由器会有两张路由表。
2.简述
在每个自治系统上的边界网关路由器,又运行一个程序,他会将本自治系统的路由信息,通过TCP发给其他自治系统的边界网关的179端口,而其他边界网关的这个程序对这些路由信息进行分析,再将自己需要的写到自己的自治系统中的边界路由器中,这样所有的自治系统内都有其他自治系统的路由信息了,可以通过边界网关路由器互相访问了
2、Node-to-Node模式
1.架构组成
CNI插件:与k8s对接
Felix:以Daemonset的形式部署在每一台宿主机上,负责在宿主机上插入路由规则,以及维护Calico所需的网络设备。
BIRD:BGP的客户端,负责在集群中分发路由规则信息
2.工作流详解
架构如下图
Calico的CNI插件会为每一个容器创建一个Veth Pair设备,把一端直接放到宿主机上(名字以cali开头);与flannel host-gw模式不同的是,不再创建网桥设备。CNI插件的作用是,需要为每个虚拟网卡配置条路由规则。如下
10.233.2.3 dev cali5863f3 scope link
即发往10.233.2.3的数据包应发给cali5863f3设备。
BGP的作用是,在源宿主机上配置路由规则,路由规则里指明了,目标网段的下一跳,就是目标的宿主机网卡;到达目标宿主机的网卡后,再根据CNI插件创建的路由规则,转发到对应的虚拟网卡上,这样就完成了,一次数据包发送。
3.限制
要求宿主机二层网络连通
3、IP-in-IP模式
1.为什么使用IP-in-IP模式
用于宿主机节点不在同一二层网络内,XVLAN是基于mac地址工作,工作在二层;IPIP是基于IP地址工作,工作在三层。
2.工作流
IP-in-IP示意图
IP-in-IP模式会在每个宿主机上创建一个tunl0的虚拟网卡,所有pod网段的路由也有指定到这个网卡上面。如下
10.233.2.0/24 via 192.168.2.2 tunl0
规则表示,下一跳没有改变,将数据包发出的设备,变成了tunl0,tunl0是一个IP隧道设备;当数据包进入到tunl0时,IPIP驱动会将这个数据包直接封装在宿主机的IP包中,经过封装后的IP包的目的地址正是Node2的地址,这样原本是Container 1到Node 2的数据包,就变成了一个从Node 1发往Node 2的数据包。由于宿主机之前是三层连通的,所以会转发到Node 2的网卡上,,Node 2的网络内核栈会使用IPIP驱动进行解包,从而拿到原始包,再通过路由规则发送给容器Container 4。
3.IP-in-IP模式的三种类型
Never:绝不使用IP-in-IP模式;适用于低层网络工作在同一个子网下。
CrossSubnet:混合模式;适用于集群存在于不同网络中,在同一子网内不使用IPIP进行加密,在不同子网中,使用IPIP进行封装。
Always:始终使用IP-in-IP进行封装。在公有云场景下,自建集群可以使用。
4.MTU配置
MTU:(最大传输单元),增大MTU可以提高性能,减小可以解决MTU过高时的丢包问题。
当配置为IPIP模式时,由于使用了覆盖标头,所以将calico的MTU配置为,网卡的默认MTU减去覆盖标头的大小,(IP in IP 使用 20 字节标头,IPv4 VXLAN 使用 50 字节标头,IPv6 VXLAN 使用 70 字节标头,IPv4 WireGuard 使用 60 字节标头,IPv6 WireGuard 使用 80 字节标头)
查看默认的MTU
[root@iZbp1igh8gtzjj9sgk4cykZ jws2]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.185.245 netmask 255.255.240.0 broadcast 172.16.191.255
inet6 fe80::216:3eff:fe0c:cb2b prefixlen 64 scopeid 0x20<link>
ether 00:16:3e:0c:cb:2b txqueuelen 1000 (Ethernet)
RX packets 2162482167 bytes 356805441901 (332.3 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2145825982 bytes 387956365773 (361.3 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
查看calico的MTU
[root@iZbp1igh8gtzjj9sgk4cykZ jws2]# ifconfig
tunl0: flags=193<UP,RUNNING,NOARP> mtu 1480
inet 172.20.93.64 netmask 255.255.255.255
tunnel txqueuelen 1000 (IPIP Tunnel)
RX packets 7129777 bytes 4936439040 (4.5 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8200734 bytes 2071010638 (1.9 GiB)
TX errors 0 dropped 4 overruns 0 carrier 0 collisions 0
4、Router Reflector模式
1.为什么使用Router Reflector模式
Node-to-Node的模式,在小规模节点上是没有问题的,但是当集群的节点大于100;
因为每台Node节点都要与其他节点进行通讯进行路由信息交换,随着节点数增加,连接数会以指数的形式上升,从而给集群网络带来压力。
所以需要用到Route Reflector模式,Calico会指定专门的节点,他们负责和所有节点建立BGP连接,从而学习到所有的路由规则,这样,所有节点在从这几个节点交换路由规则,就会极大的减少tcp连接数
5、Felix组件
Felix是Calico的核心组件之一,它是一个代理程序,负责在每个节点上管理网络和安全策略。
Felix的功能和使用场景如下:
-
网络管理:Felix负责在每个节点上配置和管理网络连接。它使用Linux内核的网络命名空间和网络设备,为每个容器创建虚拟以太网接口(veth pair),并将其连接到主机网络。Felix还负责为容器分配IP地址,并处理网络流量的转发和路由。
-
安全策略:Felix实现了Calico的网络安全功能,包括网络策略和入口/出口规则。它根据定义的策略规则,过滤和控制容器之间的网络通信。Felix会监视Kubernetes API服务器上的网络策略变化,并相应地更新节点上的iptables规则,以确保策略的一致性和正确性。
-
路由管理:Felix负责管理节点上的路由表,确保容器之间的网络流量能够正确地转发。它会监视网络拓扑的变化,并相应地更新路由表,以确保容器之间的通信能够顺利进行。
-
故障恢复:Felix具有自动故障恢复的能力。它会监视节点上的网络连接和服务的状态,并在发现故障时采取相应的措施。例如,如果一个容器或节点失去连接,Felix会尝试重新建立连接或重新启动容器,以确保网络的连通性和可靠性。
总之,Felix是Calico的关键组件之一,负责在Kubernetes集群中提供高性能的容器网络和网络安全功能。它管理网络连接、实施安全策略、管理路由和处理故障恢复,以确保容器之间的通信能够安全、可靠和高效地进行。
参考:
为什么很少看到基于tcp的隧道?-->https://www.jianshu.com/p/5118192ca414
容器网络-->https://www.jianshu.com/p/5468928d31e5
吃透BGP--->https://zhuanlan.zhihu.com/p/665266069
BGP协议介绍总结--->https://blog.csdn.net/weixin_63832692/article/details/130677022