需求导向的K8S网络原理分析:Kube-proxy、Flannel、Calico的地位和作用

最近发现自己似乎从来没学明白过Kubernetes网络通信方案,特开一贴复习总结一下。

在k8s中,每个 Pod 都拥有一个独立的 IP 地址,而且假定所有 Pod 都在一个可以直接连通的、扁平的网络空间中。所以不管它们是否允许在同一个 Node(宿主机)中,都要求它可以直接通过对方的 IP 进行访问。用户不需要额外考虑如何建立 Pod 之间的连接,也不需要考虑将容器端口映射到主机端口等问题。同时,外界的

省流,K8s网络的目标是为了实现:

  1. pod之间的互联互通
  2. 对外提供服务

为了实现上述功能,需要为每一个pod都维护完整的网络协议栈,同时,维护pod之间的网络路由。

CNI容器网络接口

首先,当你起了一个裸的、没有网络的pod之后,这个pod是没有任何基于TCP/IP手段和外界进行通信的。你可能只能通过crictl的客户端看到自己起了这么一个pod。

为了建立pod和外界的(基于TCP/IP的)通信,并且将不同pod的网络隔离开,需要为每一个pod构建一个网络命名空间。网络命名空间(Network Namespace)是一种内核级别的隔离机制,用于将不同进程组(比如一个pod就是一个被隔离的进程组)的网络环境隔离开来。每个网络命名空间拥有独立的网络栈,实现网络资源的完全隔离。

具体一点,网络命名空间的核心功能及特性是:

  1. 网络隔离
    不同网络命名空间的进程无法直接通信,需通过跨命名空间的网络设备(如 veth 对、网桥)或物理设备连接。例如,pod A 在命名空间ns1,pod B 在命名空间ns2,它们的(虚拟)物理层、数据链路层、网络层、传输层、应用层都实现了相互独立。
  2. 独立网络栈
    每个命名空间可独立配置 IP 地址、子网、网关、DNS 服务器等。
  3. 轻量级隔离
    相比虚拟机,网络命名空间的资源开销极小,适合容器场景。

我们首先实现同一台物理机内pod之间的相互通信。

为了实现不同网络命名空间之间的通信,需要把若干的pod从物理层到网络层连起来。

我们首先实现(虚拟)物理层和数据链路层的相互连接,这基于veth设备对。

你可以把它想象为一根带有两个水晶头的网线,两端(veth1和veth2)分别插在两个pod上。如下图所示:

在有多个pod的情况下,一般会新建一个公用的虚拟交换机(如图所示的bridge),然后所有的pod都接到这个交换机上,也能通过这个交换机实现pod之间的通信。如下图所示:

图里面这个bridge是一个虚拟网络设备,所以具有网络设备的特征,可以配置IP、MAC地址等;其次,bridge是一个虚拟交换机,和物理交换机有类似的功能。

对于普通的网络设备来说,只有两端,从一端进来的数据会从另一端出去,如物理网卡从外面网络中收到的数据会转发给内核协议栈,而从协议栈过来的数据会转发到外面的物理网络中。

而bridge不同,bridge有多个端口,数据可以从任何端口进来,进来之后从哪个口出去和物理交换机的原理差不多,要看数据包指向的终端MAC地址。

进一步地,我们给pod、网桥都配上IP地址,于是我们实现了同一台物理机内pod之间的相互通信。

进一步地,我们需要实现跨不同主机pod之间的通信。

一种简单的想法是,建一个跨多个主机的bridge不就得了?

这种在已有的网络上通过软件构建一个扩展版虚拟网络的方法,被称为:Overlay Network(覆盖网络)。从实现效果来看,就是把若干个节点上的小bridge整合成了一个大bridge。

Calico和Flannel是overlay network的两种实现方案。

Calico和Flannel

为了实现跨节点之间的数据通信,这就需要calico和flannel出场了。

跨节点数据包路由,主要就是两种情形:

  1. 节点和节点之间能够通过IP直连(三层可达)
  2. 节点和节点之间连接复杂(三层不可达)

解决方案也很简单,对于三层可达的网络,可以直接配置节点的路由表进行转发。对于三层不可达的网络,搭一个隧道实现网络穿透就可以了。

从这个视角看,Calico和Flannel两个插件虽然名字不太一样,但是实现的功能大同小异。

calico中,主要提供两种跨node包路由的模式:

  • BGP 模式:在三层可达的时候,Calico 在每个节点上运行 BGP 客户端,将 Pod 的 IP 路由信息通过 BGP 协议通告给其他节点。pod间流量直接通过路由规则进行转发。
  • IPIP 模式:当两个节点不在同一子网(三层不可达)时,Calico 将Pod间数据包的外边再包一层IP 头,通过隧道实现传输。

flannel中,也提供两种跨节点包路由的方式:

  • VXLAN模式:VXLAN 是 Linux 内核原生支持的网络虚拟化技术,通过在 IP 包内封装二层以太网帧,实现跨节点的虚拟二层网络。原理和Calico的IPIP模式类似。
  • Host-gateway模式:直接利用节点的物理网络进行路由,无需隧道封装,通过将 Pod 子网的路由直接指向目标节点的物理 IP,实现跨节点通信。

Kube-proxy

在前文中,我们已经通过calico / flannel等技术实现了同一个集群内pod的互联互通。但是仍然有一些比较关键的需求需要解决。

在实际使用集群的过程中,pod启动时的IP是随机分配的,这意味着访问集群内部pod必不能用硬编码方式实现。此外, Pod 实例会动态变化,需要设计动态服务发现和动态负载均衡方案。要在pod不断的变化的IP中追求不变,并且抓住这个不变实现集群内部pod的访问。

K8S的解决方案是service+DNS。Service里记录了pod的标签和端口映射规则(只是一个配置文件)。在用户向集群提交service的配置后,集群会创建和service同名的endpoint对象,用于根据service记录的标签去匹配对应的某些pod。用户在访问某些特定pod的时候,只需要访问service/endpoint的IP即可,由endpoint实现流量的路由和负载均衡。

由于endpoint的IP也在变,所以集群内引入了DNS机制,为每一个service都赋予了一个域名,通过service域名访问对应的pod。

为了实现上述功能,需要不断地监控pod的状态,进而实现路由转发。Kube-proxy提供了这样的解决方案。

kube - proxy 会持续监控 API Server,当 Service 或 Endpoint 资源发生变更时,kube - proxy 会通过list-watch手段获取这些信息。

kube - proxy 根据这些信息更新本地的iptables/ipvs规则,这些规则决定了如何将流量从 Service 的 IP 和端口转发到后端的 Pod。

references

https://segmentfault.com/a/1190000009491002

https://learn.lianglianglee.com

https://zhuanlan.zhihu.com/p/439920165

https://blog.csdn.net/weixin_42587823/article/details/144938902

相关推荐
爱学习的章鱼哥1 小时前
计算机网络|| 路由器和交换机的配置
网络·计算机网络·智能路由器
互联科技报1 小时前
声网对话式AI用于在线辅导,体验超出预期
网络
上天_去_做颗惺星 EVE_BLUE1 小时前
Docker入门教程:常用命令与基础概念
linux·运维·macos·docker·容器·bash
alden_ygq2 小时前
Kubernetes容器运行时:Containerd vs Docker
docker·容器·kubernetes
努力搬砖 ing2 小时前
Docker疑难杂症解决指南
docker·容器·eureka
Hello.Reader3 小时前
ngx_http_limit_conn_module精准连接控制
网络·网络协议·http
qq_386322694 小时前
华为网路设备学习-21 IGP路由专题-路由过滤(filter-policy)
前端·网络·学习
张青贤5 小时前
K8s中的containerPort与port、targetPort、nodePort的关系:
云原生·容器·kubernetes
云攀登者-望正茂7 小时前
AKS 支持 Kata Container容器沙盒 -预览阶段
容器·azure
撸码到无法自拔10 小时前
docker常见命令
java·spring cloud·docker·容器·eureka