第 3 章 网络与通信原理
网络是任何分布式系统的干道,离开这些干道,系统将被分裂成一个个互不相关的孤岛。云原生操作系统 Kubernetes 是典型的分布式系统,所以网络的重要性对其来说不言而喻。
阿里云 Kubernetes 集群网络基于云上专有网络 VPC 而建。集群网络目前有两种实现方案,分别是 Flannel 和 Terway。Terway 和 Flannel 的不同之处在于,Terway 支持 Pod 使用 ENI(弹性网卡),并支持 Network Policy 特性。
在这一章中,我们以 Flannel 网络方案为例,深入分析阿里云 Kubernetes 集群网络的实现方法。具体的分析过程我们会从两个逻辑角度展开,一个是网络搭建过程,另一个是集群网络通信。
核心视角
本章采用 网络搭建过程 和 集群网络通信 两个逻辑角度分析 Flannel 方案。
3.1 背景
在 Kubernetes 集群里,容器可以运行在不同的节点上,也可以运行在同一节点的不同网络命名空间中。这样,容器之间就产生了“距离”。Kubernetes 集群的网络系统要解决的核心问题,是不同“距离”的容器之间的通信问题。
根据容器之间“距离”的长短,我们可以把容器之间的通信问题划分为三个子问题:
- 本地容器之间的通信(相同网络命名空间内容器之间的通信)
- 不同网络命名空间中容器之间的通信
- 跨节点容器之间的通信
本地容器之间的通信 是这三个子问题中最基础的一个。通信容器双方的特别之处在于,它们之间虽然有进程、文件系统等方面的隔离,但是它们共享同一个网络命名空间,即使用同一个网络协议栈。本地通信使用的是 Loopback 虚拟网络接口。
Loopback 通信比喻
这种方式非常特别,好比两个人,每人有一部手机,但这两部手机使用着完全一样的 SIM 卡,当有来电的时候,这两个人会同时接到电话,当然他们都有自主性,可以选择接或不接。
不同网络命名空间中容器之间的通信 以及 跨节点容器之间的通信 这两个子问题相对比较难解决,原因就在于通信双方分别使用完全独立的网络协议栈,这就涉及到网络包跨网络命名空间,甚至跨集群节点的转发。
这两个子问题的解决,依赖于 Kubernetes 和第三方一起实现的网络组件。利用这些网络组件,集群可以搭建出较为复杂的容器集群网络。本章剩余部分会带大家深入理解这些内容。
3.2 阿里云 Kubernetes 集群网络大图
总体上来说,阿里云 Kubernetes 集群网络搭建完成之后,包括集群的 CIDR、VPC 路由表、节点网络、节点的 podCIDR、节点上的虚拟网桥 Cni0、连接 Pod 和网桥的 Veth 组 等部分,如图 3-1 所示。
图 3-1 阿里云 Kubernetes 集群网络大图
(架构示意图:包含 VPC、路由表、ECS 节点、Cni0 网桥、Pod 等组件)
类似的架构图大家可能在很多文章中都看过。相关配置可以说相当复杂,也非常不易理解。
实际上,我们可以从集群创建的过程来归纳总结这些配置。我们可以把这些配置按集群创建的阶段分类,初始阶段之后,可以分为集群阶段、节点阶段和 Pod 阶段等三个阶段,如图 3-2 所示。
图 3-2 理解阿里云 Kubernetes 集群网络的思路
(三阶段分类示意图:集群阶段 → 节点阶段 → Pod 阶段)
与这三种情况对应的,其实是对集群网络 IP 地址段的三次划分。三次划分分别是:
- 分配集群 CIDR
- 在集群 CIDR 里划分节点 podCIDR
- 在节点 podCIDR 网段里分配 Pod 的地址
3.3 集群网络搭建
3.3.1 初始阶段
集群的创建是基于专有网络 VPC 和云服务器 ECS 的。在创建完 VPC 和 ECS 之后,我们基本上可以得到图 3-3 所示的资源配置。
我们会得到一个网段为 192.168.0.0/16 的 VPC 实例,和若干从 VPC 网段里分配到 IP 地址的 ECS 实例。
图 3-3 初始阶段集群网络架构
(VPC 网段 192.168.0.0/16,其下挂载多个 ECS 实例)
初始产出物
- VPC:
192.168.0.0/16- ECS 实例:从 VPC 网段分配 IP
3.3.2 集群阶段
在初始阶段的基础上,集群创建阶段会为集群指定 CIDR,如图 3-4 所示。这个值会以参数的形式传递给集群节点初始化脚本,并被脚本传递给集群节点配置工具 Kubeadm。之后 Kubeadm 会把这个参数固化到控制器管理器的编排文件里。
图 3-4 集群创建阶段网络架构
(集群 CIDR 指定为 172.16.0.0/16;控制器管理器获取此参数)
当控制器管理器有了这个参数之后,如果有新节点通过 Kubelet 注册到集群,节点控制器就会为这个新节点划分一个子网段,而这个子网段就是节点的 podCIDR。
如图 3-4 所示,节点 B 的子网段是 172.16.8.128/25,而节点 A 的子网段是 172.16.0.128/25,这些配置会被记录到对应节点的 podCIDR 数据项里。
子网划分示例
- 节点 A podCIDR:
172.16.0.128/25- 节点 B podCIDR:
172.16.8.128/25
(注意:子网划分基于集群 CIDR172.16.0.0/16)
3.3.3 节点阶段
经过以上阶段,Kubernetes 就有了集群 CIDR,以及为每个节点划分的 podCIDR。
在此基础上,集群会把 Flanneld 部署到每个节点上,进一步为节点搭建 Pod 使用的网络主干道。这里主要有两个操作,可参考图 3-5。
图 3-5 节点增加阶段网络架构
(操作1:通过 CCM 配置 VPC 路由;操作2:Flanneld 创建 Cni0 网桥及主机路由)
-
第一个:通过 Cloud Controller Manager 给每个节点配置一个 VPC 路由项。路由项的作用是,如果 VPC 收到的数据包的目标地址属于某个节点的 podCIDR 子网段,那么 VPC 会把这个数据包转发到对应的节点上。
-
第二个:Flanneld 创建虚拟网桥 Cni0,以及 Cni0 相关的主机路由。这些主机路由的作用是,从节点外部进来的网络包,如果其目标地址属于 podCIDR,则该网络包会被主机路由转发到 Cni0 虚拟局域网内。
逻辑时序
这里要注意的是,Cni0 其实是在第一个 Pod 被调度到节点上的时候创建的,但是从逻辑上来说,Cni0 属于节点网络,不属于 Pod 网络,所以在此讲解。
3.3.4 Pod 阶段
经过前面三个阶段,集群实际上已经为 Pod 搭建了网络通信的主干道。
这个时候,如果集群把一个 Pod 调度到节点上,Kubelet 会调用 Flannel CNI 插件,为这个 Pod 创建网络命名空间和 Veth 设备组。其中一个 Veth 设备会被加入 Cni0 虚拟网桥,而另一个 Veth 设备则被安装到 Pod 上。这样一来,Pod 就和网络主干道连接在了一起,如图 3-6 所示。
图 3-6 容器部署阶段网络架构
(Pod 通过 Veth 对连接到 Cni0 网桥,进而接入网络)
Flanneld vs Flannel CNI
这里需要强调的是,前一节的 Flanneld 和这一节的 Flannel CNI 完全是两个组件。
- Flanneld:是 DaemonSet 下发到每个节点的 Pod,它的作用是搭建网络主干道。
- Flannel CNI:是节点创建的时候,通过
kubernetes-cni这个 RPM 包安装的 CNI 插件,其作用是,被 Kubelet 调用为具体的 Pod 创建网络分支。
理解这两者的区别,有助于我们理解 Flanneld 和 Flannel CNI 相关的配置文件的用途。比如:
/run/flannel/subnet.env:是 Flanneld 创建的为 Flannel CNI 提供输入的一个环境变量文件。/etc/cni/net.d/10-flannel.conf:是 Flanneld 拷贝到节点目录给 Flannel CNI 使用的子网配置文件。
配置文件路径
- 环境变量:
/run/flannel/subnet.env- CNI 配置:
/etc/cni/net.d/10-flannel.conf
3.4 通信原理
集群网络搭建的四个阶段,为 Pod 创建了网络通信干道。基于这个网络干道,Pod 可以完成图 3-7 所示的四种通信,分别是:
- 本地通信
- 同节点 Pod 通信
- 跨节点 Pod 通信
- Pod 与 Pod 之外网络实体的通信
图 3-6 容器部署阶段网络架构(重复标注,原文如此,但图3-7应是通信原理架构图)
图 3-7 集群通信原理架构
(四种通信路由示意图:Loopback、Cni0 内部、VPC 路由、NAT)
3.4.1 本地通信
本地通信说的是 Pod 内部不同容器之间的通信。因为 Pod 内网容器共享同一个网络协议栈,所以它们之间的通信可以通过 Loopback 设备完成。
3.4.2 同节点 Pod 通信
同节点 Pod 之间的通信,是 Cni0 虚拟网桥内部的通信,相当于一个二层局域网内部设备通信。
3.4.3 跨节点 Pod 通信
跨节点 Pod 通信略微复杂一点,但也很直观:
- 发送端数据包通过 Cni0 网桥的网关流转到节点上。
- 然后经过节点 eth0 发送给 VPC 路由。不会经过任何封包操作。
- 当 VPC 路由收到数据包时,它通过查询路由表,确认数据包目的地,并把数据包发送给对应的 ECS 节点。
- 进入节点之后,因为 Flanneld 在节点上创建了 Cni0 的路由,所以数据包会被发送到目的地的 Cni0 局域网,再到目的地 Pod。
3.4.4 Pod 与外部网络实体通信
最后一种情况,Pod 与非 Pod 网络的实体通信,需要经过节点上的 iptables 规则做 源地址转换(SNAT),而此规则就是 Flanneld 依据命令行 --ip-masq 选项做的配置。
SNAT 作用
使 Pod 的源 IP 地址被替换为节点 IP,以便与外部网络通信。
3.5 总结
本章我们从 集群网络搭建 和 通信原理 两个角度,分析了阿里云 Kubernetes 集群网络的实现。
其中集群网络搭建的过程可以拆分成四个阶段:
- 初始阶段
- 集群阶段
- 节点阶段
- Pod 阶段
这样的分类有助于我们理解复杂的集群网络配置。
在理解了网络配置之后,再理解包括四种通信方式的集群通信原理,就变得相当简单了。
四种通信方式一览
通信类型 网络路径 本地通信 Pod 内 Loopback 设备 同节点 Pod 通信 Cni0 虚拟网桥二层交换 跨节点 Pod 通信 → VPC 路由 → 目标节点 Cni0 Pod 与外部通信 iptables SNAT → 节点 eth0