Kube-controller-manager(StatefulSet)

基于1.25

StatefulSet Controller控制器主要控制StatefulSet资源

StatefulSet资源主要包含Pod模版、副本数量(Spec.Replicas)、更新策略、管理策略等部分

  • StatefulSet在每个关联的Pod的Name会添加一个序号后缀
  • 创建、删除Pod按照固定的顺序操作
  • 当Pod超出期望的副本数量,或以执行滚动更新策略更新,控制器顺序按顺序从高到低依次删除Pod;反之,如果Pod数量低于期望副本数量,控制器低序号到高序号删除Pod

控制器初始化

  • StatefulSet资源对象:监听Add、Uodtaed、Delete事件
  • Pod资源对象

主要执行逻辑

  1. ssc.setLister.StatefulSets

获取完整的STS对象

  1. ssc.getPodsForStatefulSet

获取关联的Pod

  1. syncStatefulSet

调谐StatefulSet。调用syncStatefulSet func实现STS调谐。内部主要调用了 ssc.control.UpdateStatefulSet和ssc.enqueueSSAfter func

  1. ssc.control.UodateStatefulSet

    调谐Pod的数量。调用ssc.control.UpdateStatefulSet func调谐Pod数量

    ssc.control.UpdateStatefulSet func主要工作流程如下:

    • 从低到高序号,逐个检查每个序号的Pod,删除Status.Phase为Failed的Pod,并且在序号上缺失的Pod时创建新的Pod
    • 从高到低序号,删除超出期望副本数量的序号的Pod
    • 根据STS更新策略执行更新Pod。STS创建的POd带有“controller-revision-hash“Label,其值根据STS资源对象的名称和Pod模版的哈嘻值生产的字符串,用于对于Pod模版
  2. ssc.enqueueSSAfter

重新加入工作队列。和RS Controller相似,如果Ready的Pod和Available不一致,并且MinReadySeconds不为0,延迟加入

调谐Pod的数量

StatefulSet Controller 为每个Pod分配序号并且把序号写入Pod Name,其命名格式为’{StatefulSet.Name}-序号’

创建Pod的时候,STS Controller按照序号从低到高创建;在Pod更新和删除的时候,STS Controller从高到低删除。

  • 最终STSController保证[0-Spec.Replicas-1]序号上的Pod可用

调谐Pod的主要流程如下:

  1. 统计要保留的Pod和要删除的Pod

    STS Controller主要把现有的Pod分为replicas和condemened俩部分

  2. 在缺失的Pod的序号上填充Pod模版

    STS Controller从0开始遍历replicas数组,如果序号上没有Pod,则说明这个序号缺少Pod,STS Controller会生产一个Pod在序号上占位,但是此刻还没真正创建Pod

  3. 删除失败的Pod并创建新的Pod

    根据Pod关联策略(PodManagement Policy)属性不同

    • OrderedReady:严格按照顺序管理Pod,在创建前一序号的Pod已经达到可用状态,或者删除后一序号已经删除中才能处理下一个Pod
    • Parallel:不需要等待Pod到达可用之后就可以创建或者删除

    STS Controller会检查按照低到高,遍历replicas数组,逐个检查各个序号上的Pod

    • 如果是Parall策略,按照顺序执行下面的操作
      • 如果当前Pod已经处于Failed状态,则调用kube-apiserver删除该Pod,在该序号上补充一个创建新的Pod的模版,并且执行后续的逻辑
      • 如果当前的Pod还没有创建,则使用序号上的Pod模版创建Pod
      • 检查Pod的Name、Label、Volume的属性是否与StatefulSet资源对象匹配,并且在不匹配时更新Pod的数据
    • 如果是OrderedReady,执行后续逻辑
      • 如果当前Pod已经是Failed,则调用kube-apiserver删除这个Pod,在该序号上补充一个创建新的Pod模版
      • 如果Pod还没有创建,则创建Pod,退出同步逻辑
      • 如果Pod处于删除中,或者不是Ready或Available状态,则退出同步状态
      • 检查Pod的Name、Label、Volume属性是否与STS资源匹配,并且在不匹配的时候更新Pod的数据
  4. 删除多余的Pod

    STS Controller按序号从高到低删除condemned数组中的Pod,即删除序号大于或者等于期望副本数的Pod

    • 如果是Parall策略,按照顺序执行下面的操作
      • 如果当前Pod已经处于删除中,则跳过当前Pod,继续处理下一个序号的Pod
      • 如果当前Pod不处于删除中,则调用kube-apiserver删除当前Pod,继续处理下一个Pod
    • 如果是OrderedReady,执行后续逻辑
      • 如果当前Pod已经处于删除中,则退出同步状态
      • 如果当前Pod不是Ready或Available状态,并且低于该Pod的序号还有未处于Ready状态的Pod,则退出同步逻辑,等待前序Pod全部就绪之后再删除当前Pod
      • 调用kube-apiserver删除当前Pod,退出同步
  5. 重建过时版本的Pod

    STS Controller根据Pod模版字段,从高到低比较Pod版本是否最新,会根据更新策略更新过时的Pod

更新策略

STS Controller支持俩种更新策略

  • OnDelete:UpddateStatefulSer func直接返回,不会执行Pod删除和创建

    // for the OnDelete strategy we short circuit. Pods will be updated when they are manually deleted.
    if set.Spec.UpdateStrategy.Type == apps.OnDeleteStatefulSetStrategyType {
    return &status, nil
    }
  • RollingUpdate:STS Controller根据序号从高到低删除Pod并创建新Pod,并且在最新版本的Pod处于Ready状态才会更新下一个Pod

    • updateMin决定Pod更新的最低序号

    • 用户没有设置STS对象的Parition属性,STS Controller会对所有Pod更新,不然更新[Partition,Repliacas-1]序号上的的Pod

    • 更新过程中,STS Controller从最高的序号开始

    • Ref:https://github.com/kubernetes/kubernetes/blob/88e994f6bf8fc88114c5b733e09afea339bea66d/pkg/controller/statefulset/stateful_set_control.go#L667

      // we compute the minimum ordinal of the target sequence for a destructive update based on the strategy.
      updateMin := 0
      if set.Spec.UpdateStrategy.RollingUpdate != nil {
      updateMin = int(*set.Spec.UpdateStrategy.RollingUpdate.Partition)
      }
      // we terminate the Pod with the largest ordinal that does not match the update revision.
      for target := len(replicas) - 1; target >= updateMin; target-- {

      // delete the Pod if it is not already terminating and does not match the update revision.
      if getPodRevision(replicas[target]) != updateRevision.Name && !isTerminating(replicas[target]) {
      klog.V(2).InfoS("Pod of StatefulSet is terminating for update",
      "statefulSet", klog.KObj(set), "pod", klog.KObj(replicas[target]))
      err := ssc.podControl.DeleteStatefulPod(set, replicas[target])
      status.CurrentReplicas--
      return &status, err
      }

      // wait for unhealthy Pods on update
      if !isHealthy(replicas[target]) {
      klog.V(4).InfoS("StatefulSet is waiting for Pod to update",
      "statefulSet", klog.KObj(set), "pod", klog.KObj(replicas[target]))
      return &status, nil
      }

      }