前言
通过《Linux网络原理》我们已据备了一定的理论知识。k8s是怎么构建网络模型的呢?
基础知识
交换机和路由器都是网络中常见的设备,它们在网络通信中扮演不同的角色。
-
交换机(Switch)是一种用于构建局域网(LAN)的网络设备,它可以将数据包从一个端口复制到另一个端口,以便在局域网上进行通信。交换机通常使用 MAC 地址来识别目标设备,并且在自己的 MAC 地址表中维护每个端口的 MAC 地址和对应的目标端口。交换机通过查找 MAC 地址表来确定数据包的最终目的地,并将其直接发送到该目的地,从而提高了局域网上的通信效率。
-
路由器(Router)是一种用于连接多个网络(WAN/LAN)的网络设备,它可以将数据包从一个网络路由到另一个网络。路由器通常使用 IP 地址来识别目标网络,并且维护一个路由表,用于决定哪些数据包应该被路由到哪个网络。当路由器收到一个数据包时,它会根据目标 IP 地址和路由表将该数据包转发到正确的下一跳路由器或目标网络。
> route -n
Destination Gateway Genmask Flags Metric Ref Use Iface
default 172.30.142.1 0.0.0.0 UG 0 0 0 eth0
172.30.128.0 172.30.142.1 255.255.240.0 UG 0 0 0 eth0
172.30.142.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
根据以上路由表的输出,可以得到以下信息:
- 没有明确的本地网络地址,因此默认路由(Destination 为 default)被设置为 172.30.142.1,并且标志为 UG,表示该路由为默认网关。
- 目标网络 172.30.128.0 和掩码 255.255.240.0 被设置为通过网关 172.30.142.1 访问(路由器)。
- 本地网络 172.30.142.0 和掩码 255.255.255.0 可以直接访问,无需使用网关(交换机)。
- 第二条通过网关走的基本上是路由器, 第三条直连接的是交换机
- 交换机是使用 MAC 地址来识别和转发数据包的。但是,如果要访问连接到交换机的主机,则需要使用 IP 地址来确定目标主机,并在本地网络配置中指定正确的 VLAN(虚拟局域网)或子网。具体来说,当计算机发送一个数据包时,它会将该数据包的目标 IP 地址封装在数据包的 IP 头部中。交换机会查看该数据包的目标 MAC 地址,并根据其 MAC 地址表来确定数据包应转发到哪个端口。当数据包到达目标端口时,目标主机会解开数据包并检查其 IP 头部中的目标 IP 地址。如果该 IP 地址与目标主机的 IP 地址匹配,则目标主机会接受该数据包并进行相应的处理。
- 路由表的构建,可以是手动,或者动态
路由转发模型
常见的路由三种转发模式 :
-
NAT 地址转换模式:
主机维护(私有IP+端口)(公有IP+ 端口)的映射关系,发送和接收数据包的时候转换
通常用于将一个私有网络中的 IP 地址映射到公共网络中的单个公共 IP 地址 -
DR 直接路由模式:
创建一张虚拟网卡,和主机的交换机直接相连接
当虚拟机发送数据包时,它会将源地址设置为虚拟网络适配器的私有 IP 地址,并将目标地址设置为目标计算机的公共 IP 地址。主机上的网络驱动程序将数据包从虚拟网络适配器读取并直接发送到外部网络,而无需进行额外的转发和映射。 -
TUN 隧道模式
在原来的IP数据包上面再根据自己的协议另一个IP数据包, 当送达到目标地址的时候,再解包处理。
此方式安全性较高,相当建立一条点对点的隧道
单机容器网络模型
docker的默认网络模型,即veth pair设备 + 宿主机网桥
- docker0 可是网桥(交换机)
- vether 对设备, 可理解成网线直连接
如图,从Container1发送到Container2的数据包
- 经过Container1中的eth0,到达docker0网桥,
- docker0网桥经过二层转发,将数据包发送到Container2对应的端口
K8S网络模型
K8S有Flannel和Calico两种网络模型。
Flannel 网络模型
Flannel 是一个开源的网络解决方案,旨在为 Kubernetes 集群中的容器提供网络互通。它使用虚拟化技术来创建一个覆盖整个 Kubernetes 集群的扁平化网络,并支持多种后端驱动程序,如 VXLAN、Host-gw 和 UDP。
Flannel-UDP
与单机容器网络相比,这里新增了一个flannel0设备和flanneld进程。flannel0设备是一个TUN设备,它的作用非常简单,就是在系统内核和用户应用程序之间传包;flanneld进程的职责,就是封装和解封装。
- 数据包从Container-1,来到了网桥docker0上,由于数据包的目的地址不属于网桥的网段,所以数据包经由docker0网桥,出现在宿主机上。
- 在宿主机的路由表中,去往100.96.0.0/16网段的包经由flannel0处理。flannel0收到数据包之后,将数据包送到flanneld进程,flanneld进程会对数据包封装成一个UDP数据包,src和dst地址分别为两个容器对应的宿主机的地址。这样,数据包就可以到达Node2了。
- 数据包到达Node2的8285端口,即Node2上的flanneld进程,会被执行解封装操作,之后数据包被发送到TUN设备,即flannel0设备。剩下的事情就简单了,数据包经过docker0网桥到达Container-2。
Flannel-VXLAN
Flannel-UDP效率太低了,因为数据包每次经过flannel0设备,都会经过内核态-用户态-内核态的这一顿折腾。Flannel-VXLAN方案就解决了这个问题。Flannel-VXLAN方案用VXLAN技术替代了flannel0设备,让数据包能够在内核态上实现数据包的封装和解封装。
Flannel-host-gw
Flannel-VXLAN虽然效率提高了,但是还是用到了隧道技术,效率还是会受到影响。接下来我们继续探索Flannel-host-gw网络模型
- 后台有个flanneld进程,一直同步etcd的数据(主机等网络)到路由表中
- 当数据包从Container1到了cni0网桥之后,通过Host网络栈的路由表,发现去Container2的路已经指明,经由eth0,达到Node2(10.168.0.3/24)即可。
- 当数据包到了Node2之后,通过Host网络栈的路由表,找到cni0网桥,Container2自然也就找到了。
Calico模型
Calico 则是一种基于路由的网络模型。它利用 BGP 协议来自动管理节点之间的网络路由,并使用 IP 路由表来进行容器之间的通信。
Calico(非IPIP模式)
实际上Calico网络模型的解决方案,几乎和Flannel-host-gw是一样的。不同的是Flannel-host-gw使用etcd来维护主机的路由表,而Calico则使用BGP(边界网关协议)来维护主机的路由表。除了BGP之外,Calico另外一个不同之处就在于它不需要维护一个网桥
Calico(IPIP模式)
Calico(非IPIP)听着挺强大的,实则和Flannel-host-gw一样,只支持宿主机二层联通的情况。假设Container1和Container3的宿主机在不同的子网,那通过二层网络是无法将数据包传到下一跳的地址的。Calico的IPIP模式解决了上述问题,在每一台宿主机上,都会增加一个tunl0设备
Container1去往Container3的数据包就会经过tunl0设备的处理,tunl0设备会在源IP报头之外新增一个外部IP报头,拿本例来说,这个外部IP报头的src和dst分别为Node1和Node2的IP,这样,数据包就伪装成了从Node1发到Node2的数据包。当数据包到达Node2之后,Node2上的tunl0会把外部IP报头拿掉,从而拿到原始的IP包。
CNI网络插件
CNI(Container Network Interface)顾名思义,是K8S的网络接口。这个接口的作用就是当K8S的 kubelet创建Pod时,dockershim会预先调用Docker API创建并启动Infra容器,执行SetUpPod的方法。
就是当Pod创建时,需要对网络进行一些设置,包括前边的提到的创建对设备,把对设备的一端挂载到网桥上,添加Pod以及主机的Network Namespace的路由规则等
Flannel和Calico各自都有专门的CNI插件
主要参考
《深入剖析kubernetes》
《Linux 命令(120)—— route 命令》
《网络通信原理(三)路由转发模式NAT、DR和TUN》
《二十分钟了解K8S网络模型原理》