Kubernetes 作为容器编排工具的代表,已经成为了云原生时代的核心技术之一。而其中最基础的网络组件 Flannel,也是 Kubernetes 中最重要的一部分。本文将深入分析 Flannel 的原理和源码实现,以及如何在实际应用中使用。
Flannel 简介
Flannel 是一个基于 VXLAN 和 UDP 的网络覆盖方案,可以为 Kubernetes 集群提供 IP 地址管理和通信功能,是 Kubernetes 网络模型中 CNI 的一种实现。Flannel 可以动态为 Pod 分配 IP,并提供网络层隔离和跨主机通信,为整个集群提供了内部通信的支持。
Flannel 的实现依赖于 etcd 存储,可以使用 etcd 存储 IP 地址和其他一些配置信息,这些信息可以动态地根据集群的情况进行调整,保证了整个集群内部的通信效率。
Flannel 的原理
Flannel 的核心原理是将不同主机上的 Pod 所属的虚拟子网(VPC)映射到相同的网络中,并通过 VXLAN 进行通信。Flannel 的工作流程如下图所示:
Flannel 中每个主机对应一个 flanneld 进程,flanneld 进程有两个主要功能:
作为网络命名空间(NetNS)的 Master,创建并管理虚拟网卡(Veth pair)
作为 VXLAN 隧道的 Endpoint,接收并处理来自其他节点的数据包
Flannel 在启动时,会默认创建一个 flannel.1
的虚拟子网,并将其分配给当前节点。节点之间通过 VXLAN 隧道来通信,每个 VXLAN Tunnel 使用一个不同的 VNI(Virtual Network Identifier)来区分不同的虚拟网络,这样不同的虚拟网络就可以在同一个物理网络中独立运行,避免混淆。
当一个 Pod 启动时,首先会向 Flannel 发起请求,Flannel 会从 etcd 中获取可用的 IP 地址,并将其分配给 Pod。Pod 包装成数据包后通过节点上的 veth0
接口发送到 Flannel,Flannel 通过 vxlan0 接口封装数据,在 VXLAN 层加上 VNI 和远端节点的 IP 地址信息,发往接收方所在节点的 flanneld 进程进行解封装,最终将数据包交给接收方的 veth0 接口。
Flannel 的源码实现
Flannel 的源码托管在 Github 上,可以克隆代码库进行学习和研究。代码库的主要结构如下:
-- -------------------- ---- ------- ------- --- --------- --- --- --- ------ --- ----- --- ------ --- --- --- ------- --- ---- --- ---- --- ------ --- -----
Flannel 主要分为以下几个模块:
- etcd:使用 etcd 作为网络配置信息的存储和分发中心
- ipam:负责 IP 地址的分配和管理
- subnet:虚拟子网的创建和管理
- vxlan:VXLAN 隧道的创建和管理
以 VXLAN 为例,来分析 Flannel 的源码实现。VXLAN 是 Flannel 中最核心的模块之一,VXLAN 以 vxlan.go
的形式进行了实现。Flannel 中的 VXLAN 模块主要完成了以下几个功能:
- 创建和销毁 VXLAN 设备
- 发送和接收 VXLAN 数据包
- 生成 VXLAN 头部(Header)
VXLAN 设备的创建和销毁可以通过 Linux 的命令行工具实现(ip link add/delete),Flannel 中借助 Go 语言的网络库(netlink)封装了这些操作,将 VXLAN 的创建和销毁过程集成到了 flanneld 的启动和结束中。
-- -------------------- ---- ------- ---- ----------- ------ - ---- ------ -- ------ -- -------- - ---- --- ------------- ------------------------ ------- ---- ------ - --- - - ------------- --- ------- - ---- --- - --------- -- --- -- --- - ------ ------------------ -- --- ----- -------- --- ---- ---- - ---------------- - ------- --------- - ---------- -------------- - - --------- - --- --------- - ------ ----- - - -- --- - -------------------------- -- --- -- --- - ------ ------------------ -- --- --------- ---- ------- - -- --- - -------------------- --- -- --- - --- - -- --- --- -- --------------------------- --- -- --- - -- --- - ------------------------- ---- --- -- --- - --- - - ------ --- - -------------------------------------------- --------- ---------- -- -- --- -- --- - --- - ------ -
而发送和接收数据包则主要是通过 UDP 完成的,VXLAN 将内部的数据包封装成 UDP 数据包进行发送,对端节点通过监听相应的 UDP 端口接收数据包,然后对 VNI 进行判断,解封并将数据包传到对应的 namespace 中。
-- -------------------- ---- ------- ---- -- ------- ------- ---------------- ----- - -- --- -- ------------------------------------- --------------- -- --- -- --- - --- - ----- --------- --- - ------ - ---- ------------- ------ --- -------- --- -- ------------ ---------- ------------------------------------------------------- -- ----- --- -- --------------- --- -- --- -- ------------------ ----- ------- ------- ------------ --- -- --- - --- - - - - ---- -- ------- ------------- ------- ---- --------- ------- ------ ----------------- ---------- ------- ----- - --- -- ---- ----- ------ ----- -- ------------------ -- ------------- -- --- ----- --- --- --- -- ----------------------- -- ---------- -- ----------- -- ------------- - ------ --- - ------ - ----------- ------------ --- -- ------------------------- --- --- -- --------- ------ ------------- ------ ------- -- ----- --- ---------- --- ---- -- ------- ---- ----------------------- ---- ------- ---- ------- -- -------- -- ------------ -- --- - ----------------------------------------- ------- --- ----- --- -- ------------------ ------------- --- ------- ----- --------------- -- --- -
生成 VXLAN 头部是 Flannel 中最核心的部分之一,VXLAN 的头部 Designator 部分包含两个比特的标志和24比特的 Virtual Network Identifier(VNI),其余部分和 Ethernet Frame 头相同。在 Flannel 中,VXLAN 头部的生成由 VXLAN 的 MarshalBinary
函数实现。
-- -------------------- ---- ------- ---- --- ------------- --------------- -------- ------ - - -- ------------ ------------------ ---- - -------------- -- -- ---- - -------------- - ----- ---------------------------------- ------- ------------- ------- ------------------------------------ ------- ------ -- --- -
使用 Flannel
Flannel 的部署和配置相对简单,可以通过 kubelet 的配置文件中直接指定 Flannel 的配置,例如下面的配置以 etcd 做为存储后端:
-- -------------------- ---- ------- ----------- ---------------------- ----- -------------------- --- ------------------ ----- ----------- ---------------- ---------- -------------- ----------------- - - ------- ------- ------------- -------- ------- ---------- ----------- - ------- ------- ---------------- -------------------------------- ------------- ------------------- ------------------- --------------------------------------- ------------------- -------------------------------------- - -
配置启动后,可以通过 kubectl get po -n kube-system
命令来查看 Flannel 的启动状况,并通过 kubectl get node -o wide
来查看 Flannel 所分配的 Pod 网络信息。同时,Flannel 的运行日志可以通过 journalctl -u flanneld -f
来实时查看。
总结
Flannel 作为 Kubernetes 最重要的网络组件之一,为整个 Kubernetes 集群的网络通信提供了非常重要的支持。本文从 Flannel 的原理和源码分析了解到,Flannel 的原理和实现非常复杂,但在实现过程中还是通过简单的方式,借助 Linux 的 namespace 和 VXLAN 技术,为 Kubernetes 提供了更高效、更可靠、更灵活的内部通信方案,让整个集群能够更好地运营。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64cb01505ad90b6d041e49d7