在云原生的背景下,对 Kubernetes 的集群的生命周期的管理的期望和需求越来越多,很多企业的集群数量也与日俱增,少则几个,多则几十个。有的分布在企业的私有云,有的分布在公有云,有的分布在混合云。社区也涌现了很多项目专注于这个方向的研究和实践,这里以开源项目** cluster-api 为切入点,来介绍云原生集群生命周期的管理能力,主要介绍 cluster-api 中的 ControlPlane 的工作原理**。对于 cluster-api 整体介绍可参见 Kubernetes 多云管理利器 -- cluster-api 。
以下整理出了与本篇文章相关联的概念的描述,帮助接下来的理解。
Cluster: 代表一个完整的集群的安装,包括安装 Kubernetes 集群需要的集群层面的资源,如 LB 、VPC 等;包括机器的创建;暴露整个控制平面组件的安装;包括集群的健康检查等等。
KubeadmControlPlane: 代表了一个集群的控制平面的完整安装,包括 api server 、controller manager 等 Kubernetes 的管理组件。其中也包含了机器的创建,以及不同机器需要的 BootstrapConfig 的创建、集群证书的创建、集群控制平面的组件的健康检查、版本升级、控制平面的扩缩容等。一个 ControlPlane 被创建,同时状态变为 ready 的话,代表着一个 Kubernetes 的所有的管理组件都是 ready 的,可以直接使用 kubectl 去操作集群,这是一个具体的 ControlPlane 的实现。控制平面的整体的安装和管理,使用的是 kubeadm ,是社区比较流行和广泛使用的 Kubernetes 安装程序。
InfrastructureRef: Infrastructure 的定义是基础设施,可以理解成 IaaS 层面的资源定义。Ref 指的是 Reference 引用,理解成对基础设施资源对象的引用。举例来说,在 Cluster 定义的时候,会指定对应的厂商实现的 Cluster ,如 VSphereCluster ;在定义 KubeadmControlPlane 的时候,可以指定这个控制平面使用的机器的虚拟机模版是哪个厂商提供的,如 VSphereMachineTemplate 。
Machine: 代表被集群纳管和使用的机器。不同的 Provider 可以根据自己的平台,实现自己怎样创建机器出来。这里有一点需要注意的是,机器和启动配置的关系,每台机器的启动都会绑定一个当前机器自己的 BootstrapConfig 。举例 aws 对应的实现是 AWSMachine ,vmware 对应的实现是 VSphereMachine 。
BootstrapConfig: 代表了集群的不同角色的机器,在启动时候的配置,如控制节点的 BootstrapConfig 和计算节点的 BootstrapConfig 是不同的,以及控制节点里的第一台机器和剩余的控制节点也是不同的。这需要注意的一点,BootstrapConfig 是和 Machine 绑定的,不同的机器的 BootstrapConfig 是不同的。每个提供商在实现的时候可以完全不同,比如可以实现 kubeadm 的启动配置,也可以使用提供商自己封装好的启动配置 (aws 就是自己实现的),所以可以理解成 bootstrap 其实是一种启动的类型定义,默认实现的 kubeadm 作为 bootstrap 的类型的,也可以自定义,比如像 aws 也是另外一种 bootstrap 的类型。目前社区的实现,主要就是包含了 kubeadm 和 aws ,这两种 BootstrapConfig 的实现。
对于 cluster-api 整体架构的介绍,以及整体架构中的 Cluster 的原理部分可参见 Kubernetes 多云管理利器 -- cluster-api 。本篇文章重点介绍整体架构中的 ControlPlane 的原理部分。
本篇文章以 vmware 的 VSphere 为 Infrastructure Provider ,介绍 cluster-api 中,与 ControlPlane 相关的业务模型。
Cluster: 代表了一套完整的 Kubernetes 集群,一个集群的定义,就从定义 Cluster 开始。其中包括 Cluster 对应的 Kubernetes 集群的集群层面的基础设施管理,比如集群高可用依赖的 VIP 能力,比如公有云的 VPC 的创建,在这些集群层面的基础设施创建好之后,才会进行控制平面 ControlPlane 的创建;还包括 Cluster 关联的控制平面 ControlPlane 是什么样的。在 Cluster 定义中,使用 controlPlaneRef 引用了 KubeadmControlPlane 类型的资源对象,使用 infrastructureRef 引用了对应的 provider 实现的 Cluster ,这里举例以 VSphere 为例,对应的 infrastructureRef 为 VSphereCluster 类型的资源对象;还包括集群 Cluster 的网络相关的定义,如 Pod 的 cidr 是哪个网段,如 Service 的 cidr 是哪个网段,如 APIServer 的端口是多少,如 Service 服务的域名是什么;还包括集群 Cluster 的部署的拓扑结构的定义,如有多少台控制平面的机器,如有多少台计算节点的机器等。
VSphereCluster: 这里的 VSphereCluster 是其中的一个 Provider 的实现,用来说明 Cluster 对象的 infrastructureRef 所引用的资源对象,VSphereCluster 的资源对象被创建之后,会在 VSphere 中为 Kubernetes 集群准备 VIP ,haproxy (用于高可用)。
KubeadmControlPlane: 这里的意思是使用 kubeadm 完成 Kubernetes 的控制平面的安装,也就是会安装出指定规模机器的控制节点,不包含计算节点。KubeadmControlPlane 中会指定和 kubeadm 要安装一套 Kubernetes 集群所相关的配置信息,包括 kubeadm 在 ini 时候的配置,在 join 时候的配置,在执行 kubeadm 之前要执行的命令,以及对 Kubernetes 集群创建的 apiServer ,controllerManager 的一些参数设置。
VSphereMachineTemplate: 定义了用于创建对应 Provider 机器的模版,这里以 VSphereMachineTemplate 为例,VSphereMachineTemplate 中的定义包含了基于 VSphere 的虚拟机模版的技术,按需创建出虚拟机的能力。如使用哪个数据中心的 VSphere 服务器,使用哪个资源池,虚拟机模版是哪个,内存多大,CPU 是几核,存储用哪个 datastore ,磁盘空间是多大,网卡是不是开启 dhcp 的开关。
获取当前的控制平面 kcp 对应的 Cluster 集群对象,因为控制平面 kcp 是属于一个 Cluster 集群对象的,关联关系在 Cluster 控制器里已经通过给控制平面 kcp 的 OwnerReferences 设置了 Cluster 进行了绑定。
判断当前集群对应的 Cluster 级别的基础设施,比如 VPC ,LB 之类的是不是已经创建好了,如果没有创建好就跳过,前提是基础设施要准备好,才可以继续进行后面的操作。
给这个控制平面的对象设置 Finalizer 用于清理操作时候的处理逻辑。
调用 reconcile 方法去完成真正的控制平面对象的调和,具体的逻辑将在下面进行分析。
调和外部对象,也就是需要更新一下外部的对象,这样外部对象的控制器,就会执行自己的逻辑,去完成外部对象需要的期望状态。这里要调和的外部对象,是控制平面 kcp 使用的基础设施 VSphere 的 VSphereMachineTemplate 虚拟机模版对象( kcp.Spec.MachineTemplate.InfrastructureRef ),将 kcp 当前所属的集群对象 Cluster 对象设置给 VSphereMachineTemplate 资源对象的 OwnerReferences 。为什么说是外部,因为 VSphereMachineTemplate 资源对象不是在 cluster-api 这个项目中管理的,而是由 cluster-api-provider-vsphere 这个项目来完成,在 cluster-api-provider-vsphere 中实现了 VSphereMachineTemplate 的具体能力。
为当前控制平面生成这个新集群的证书,这个证书就是安装 Kubernetes 需要的集群的证书。
为当前控制平面生成这个新集群的 kubeconfig 文件。
找出控制平面 kcp 的所有 Machines ,用于后面进一步的处理,这里 Machines 有可能是空的,这种情况就是控制平面第一次创建和初始化,还没有 Machine ,在后面的分析过程中会分析,在开始没有找到属于控制平面 kcp 的所有 Machines 是怎么处理的。
根据集群 Cluster 、Machines 等信息,初始化一个完成控制平面 kcp 业务逻辑的对象,这个对象不是控制平面 kcp 的 cr 对象,而是处理 kcp cr 对象,封装了处理一个控制平面 kcp 实例的相关业务逻辑。
调和这个集群应该有的 etcd 集群,以及保证 etcd 的健康,这里主要是保证 etcd 的成员要和控制平面的所有 Machine 数量匹配,不是创建 etcd 集群。同时调和不健康的 Machine ,对于不健康的 Machine 进行相关的处理,比如对于不健康的 Machine 是 etcd 的 master 节点,那需要先找一个健康的 Machine ,通过 etcd 的客户端切换新的健康的 Machine 为 etcd 的新的 master 节点,然后删除 Machine cr 对象,这个删除的操作,会触发基础设施的控制器去删除物理的 Machine ;判断 Machine 健康不健康是通过 c.Machines.Filter(collections.HasUnhealthyCondition) 来完成的,也就是看看机器的 Condition 里有没有 HasUnhealthyCondition 。
判断当前控制平面的期待的副本数和当前已有的 Machine 数量对比,来判断是初始化,还是扩容,还是缩容控制平面。1) 如果当前的机器数小于期望数,同时当前这个控制平面拥有的机器数是 0 台机器,就执行初始化控制平面的操作; 2) 如果当前的机器数小于期望数,同时当前这个控制平面拥有的机器数大于 0 ,就执行扩容控制平面的操作; 3) 如果当前的机器数大于期望数,就执行缩容控制平面的操作。这里重点说明第一种情况,也就是初始化控制平面的情况。
去 API Server 读取最新的数据,找到当前控制平面所控制的所有的机器。
如果找到的被控制平面控制的机器的数量是大于 0 的,意思就是已经初始化了控制平面的第一台 master ,就退出了,因为已经不不需要初始化了,已经有了第一个 master ,后面只要 join 其他的控制节点就可以。
初始化控制平面的配置,这里会创建一个 KubeadmConfig ,用于机器的 boot ,这个 KubeadmConfig 是和机器对应的,不同的机器的配置是不一样,如下,设置了 join 相关的配置为空,说明了这个就是第一个 master , 因为 master 需要设置 InitConfiguration ,对应到 kubeadm 的 init 命令,而 JoinConfiguration 对应到 kubeadm 的 join 命令。
bootstrapSpec := c.KCP.Spec.KubeadmConfigSpec.DeepCopy()bootstrapSpec.JoinConfiguration = nil
15.根据上述的 bootstrapspec 和 kcp.Spec.MachineTemplate.InfrastructureRef 的配置,通过 clone infra 的模版来创建机器。在创建机器的时候,是必须要知道机器对应的 bootstrap 的 config ,也就是 bootstrapspec ,同时还要设置机器是属于这个集群的,也是属于这个集群的控制平面的 (这里会给机器的 spec 加上一个控制平面的 label ,但是这个 label 的 value 是空的,但是这样已经可以标记是一个控制平面的机器了就足够了)。\
克隆基础设施的模版,这里指的是虚拟机模版,这里指的是 VSphereMachineTemplate ,用于创建控制平面的机器。
根据控制平面, 集群,bootstrapspec 创建 bootstrapv1.KubeadmConfig ,创建出来的 bootstrapv1.KubeadmConfig 是属于当前这个控制平面。KubeadmConfig 中包含 clusterConfiguration 这种用于配置 Kubernetes 集群组件的属性;包含了 files 这种用于 cloud-init 去在机器上创建的文件;包含了 kubeadm 安装节点的 initConfiguration 和 joinConfiguration ;包含了在 kubeadm 执行前和执行后的命令 preKubeadmCommands 和 postKubeadmCommands ;包含了操作系统的用户的预创建;包括了磁盘的安装;包括了 NTP 的配置;包括机器的 mountpoint 等。
经过上述的分析,可以看出,一个 Cluster 会包含一个 VSphereCluster ,一个 KubeadmControlPlane 。VSphereCluster 负责为 Cluster 处理好集群层面的资源,KubeadmControlPlane 负责创建出机器,以及根据 kubeadm 的配置,结合 VSphere 的虚拟机模版技术完成基于 kubeadm 安装 Kubernetes 控制节点。当 VSphereCluster 和 KubeadmControlPlane 都 ready 了之后,Cluster 也就 ready 了,这样完整的一套不包含计算节点的 Kubernetes 集群就创建好了。从而体现出 cluster-api 在管理 Kubernetes 集群生命周期的能力。
本文作者
熊中祥
「 DaoCloud 道客」技术合伙人 云原生技术专家
参考链接: https://cluster-api.sigs.k8s.io/user/concepts.html\
加入群聊沟通: