0
点赞
收藏
分享

微信扫一扫

Kubernetes StatefulSet Controller实现原理

前言

本文主要会介绍笔者在学习Kubernetes StatefulSet Controller的实现原理时所总结的知识点,其中会涉及到StatefulSet对象的设计理念、Controller的工作原理、滚动更新以及控制循环等方面的相关内容。 笔者也会将自己的理解在文中进行阐述,这也算是在和大家交流心得的一个过程。若文中有错误的理解和概念,请大家及时纠正;吸纳大家的建议,对于我来说也是很重要的学习过程之一。

(目录)

1.设计理念

StatefulSet的核心功能就是通过某种方式记录业务应用的状态,然后在Pod被重新创建时能够为新Pod恢复业务应用的状态。StatefulSet Controller把业务应用状态抽象为了以下两种状态。

1.1 拓扑状态

由于业务应用的多个实例之间不是完全对等的关系,因此这些应用实例必须按照某些顺序启动,并且再次被创建出来时也必须严格按照这个顺序。新创建出来的Pod必须和原来Pod的网络标识一样,这样原先的访问者才能使用同样的方法,访问到新Pod。

1.2 存储状态

业务应用的多个实例分别绑定了不同的存储数据,因此要求Pod被重建过也应该能够访问同一份数据

2.工作原理

2.1 记录拓扑状态

StatefulSet Controller直接管理的是Pod对象。StatefulSet里的不同Pod实例是有差别的,StatefulSet区分这些实例的方式是通过在Pod的名字里加上事先约定好的编号。即通过使用特殊编号的方式来记录拓扑状态中的实例关系

Tips: StatefulSet与Deployment的区别就在于,Deployment是依靠ReplicaSet管理着一批有着相同特称的Pod。因此StatefulSet无法想Deployment那样以统一的操作模式对Pod进行操作,而必须依据每个Pod的特殊要求/状态来进行特定的操作。

Kubernetes通过Headless Service为有编号的Pod在DNS服务器中生成带有同样编号的DNS记录。这样就可以保证访问Pod的网络标识不会改变。即通过使用固定DNS记录的方式来记录拓扑状态中的网络标识

2.2 记录存储状态

StatefulSet为每一个Pod分配并创建一个带有对应Pod编号的PVC,保证了每一个Pod都拥有一个独立的 Volume。即通过使用特殊编号的方式来记录存储状态

3.实现原理

StatefulSet Controller的主要作用之一就是在使用Pod模板创建Pod的同时对Pod进行编号,并且按照编号顺序逐一完成创建工作。当StatefulSet Controller发现Pod的实际状态与期望状态不一致时,Controller在执行调谐操作会严格按照Pod编号的顺序逐一完成这些操作

3.1 记录拓扑状态

3.1.1 Headless Service

Headless Service实现了StatefulSet中对于网络标识的稳定性的要求

1686029838186.jpeg

Headless Service是一种特殊的Kubernetes Service,Headless Service是一种没有被分配cluster IP的service

Tips: Headless Service与Kubernetes其他的Service一样,也是通过label selector来映射相应的Pod。

Headless Service可以直接以DNS记录的方式解析出被代理Pod的IP地址。Headless Service 所代理的所有 Pod 的 IP 地址都会被绑定固定格式的DNS记录:

<pod-name>.<svc-name>.<namespace>.svc.cluster.local

这个DNS记录正是Kubernetes为 Pod 分配的唯一的“可解析身份”(Resolvable Identity)。即只要Pod name和Service name不变,就能够保证访问Pod的网络标识是固定不变的。

Tips: Headless Service保证的是DNS解析中的Pod域名不变,而DNS解析中的Pod IP部分是会改变的。因为每次重建Pod时, Kubernetes会为Pod分配新的Pod IP。

3.1.2 Pod统一编号

StatefulSet Controller为所管理Pod的名字进行了编号,编号规则为:

<statefulset name>-<ordinal index>

其中,ordinal index都是从0开始累加,并且与StatefulSet的每个Pod实例一一对应,保证不会重复。

StatefulSet Controller在创建这些Pod时也是严格按照编号顺序进行的。只有前一个Pod的状态为ready时,才会按照编号顺序创建下一个Pod。通过这种方法,Kubernetes就可以成将Pod之间的关系按照 Pod 的“名字 + 编号”的方式固定下来。

3.2 存储状态的记录

StatefulSet使用PVC和PV来持久化Pod的数据,而并不是让这些数据随着Pod的消失而删除。

在StatefulSet的定义中,通过spec.volumeClaimTemplates属性来定义Pod所需的PVC。这个 PVC 的名字,会被分配一个与这个Pod完全一致的编号,并且有着规范的命名方式:

<volume name>-<StatefulSet name>-<ordinal index>

由于volume name和StatefulSet name都是在StatefulSet声明中事先定义好的,并且Pod编号也是由StatefulSet规范控制的;因此无论重建多少次Pod,PVC的名称都是固定的。所以Pod在重建后就能够复用到原有的PVC/PV,从而获取到保存在其中的持久化数据。

Tips: 因为PVC与PV是绑定的在一起的,而StatefulSet是和PVC绑定在一起的;所以StatefulSet等同于和指定的PV绑定在了一起。重建Pod时,PVC和PV是不会被删除的。同时,StatefulSet每次在建立Pod时都会去尝试创建相应的PVC,如果PVC已经存在就会绑定该PVC。

4.滚动更新

可以将StatefulSet看作是一种特殊的Deployment,因此StatefulSet也具有滚动更新的功能。

触发方式就是更改StatefulSet的Pod部分定义,之后StatefulSet Controller就会按照与Pod编号相反的顺序,从最后一个Pod开始逐一更新StatefulSet Controller管理的每个Pod。而如果更新发生了错误,这次“滚动更新”就会停止。

StatefulSet的“滚动更新”还允许更精细的控制,允许应用的多个实例中被指定的一部分不会被更新到最新的版本。StatefulSet的spec.updateStrategy.rollingUpdate的partition字段负责上述功能。只有序号大于或者等于partition数值的Pod会被更新到新版本,其余的Pod即使在重建的情况下也还是使用老版本的镜像。

5.控制循环

StatefulSet Controller的Control Loop核心逻辑为:

  1. 获取StatefulSet对象的实际状态 通过调用Kubernetes API来进行获取。

  2. 获取StatefulSet对象的期望状态 使用Informer组件来从API Server中获取。

  3. 分析当前状况 比较两个状态,判断是否需要进行滚动更新或扩展/缩减 Pod 数量。如果是副本数量(replica)发生了变化,则进行水平扩缩。如果是Pod template发生了变化,则进行滚动更新。如果两个状态相同,则保持现状。

  4. (可选)滚动更新 在滚动更新过程中,StatefulSet Controller会按照Pod编号顺序的倒序逐一更新Pod。StatefulSet Controller会持续监控新旧 Pod 副本的状态。如果有问题出现,它会回滚到之前的状态,以确保稳定性。

  5. (可选)水平扩缩 如果决策结果是需要水平扩缩,则StatefulSet Controller会创建新的 Pod 副本,确保它们按照规则命名并具有唯一的标识符。

  6. 操作记录 一旦新的 Pod 副本成功部署并运行,StatefulSet Controller将更新的状态与期望状态匹配,并标记更新为完成。

举报

相关推荐

0 条评论