当前位置: 首页 > article >正文

需求导向的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 头,通过隧道实现传输。

IPIP模式的示意图

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

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

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


http://www.kler.cn/a/611080.html

相关文章:

  • 浏览器存储 IndexedDB
  • CentOS 8 安装 Redis 全流程指南:从基础部署到远程安全配置
  • 无线安灯按钮盒汽车零部件工厂的故障告警与人员调度专家
  • 创建一个服务器启动自动执行的脚本,设置默认路由
  • 【MinIO】可靠的分布式MinIO集群部署
  • 基于深度学习的相位调制算法步骤
  • Android UI 组件系列(三):ImageView 使用技巧与图像加载
  • Unity游戏开发如何优化移动端的延迟渲染管线?
  • python笔记之判断月份有多少天
  • Rust从入门到精通之精通篇:24.高级异步编程
  • 做一个有天有地的css及html画的旋转阴阳鱼
  • Leetcode 188 买卖股票的最佳时机 Ⅳ
  • 【计算机网络】DHCP工作原理
  • Postman 如何发送 XML 格式的 API 请求?
  • 【redis】主从复制:单点问题、配置详解、特点详解
  • 使用 Vite 提升前端开发体验:入门与配置指南
  • 【云馨AI-大模型】自动化部署Dify 1.1.2,无需科学上网,Linux环境轻松实现,附Docker离线安装等
  • JVM类文件结构详解
  • 六级词汇量积累(day12)
  • 使用请求调用本地部署的stable-diffusion接口