当前位置: 首页 > 工具软件 > VPA > 使用案例 >

vpa updater源码分析

伊温书
2023-12-01

1. updater整体逻辑

updater整体逻辑是比较简单的。

(1)定义了一个NewUpdater的对象

(2)然后每隔1分钟,执行NewUpdater.RunOnce

1.1 updater参数

updater轮转周期,默认是1分钟
updaterInterval = flag.Duration("updater-interval", 1*time.Minute, `How often updater should run`)
​
rs最小可用的副本数。比如默认是2表示,如果一个rs当前只有2个副本可用,本轮是不会驱逐的,保障rs服务的可用性
minReplicas = flag.Int("min-replicas", 2, `Minimum number of replicas to perform update`)
​
pod每轮的驱逐比例
evictionToleranceFraction = flag.Float64("eviction-tolerance", 0.5,`Fraction of replica count that can be evicted for update, if more than one pod can be evicted.`)
​
驱逐限速,这里用了令牌桶算法,就个就是令牌桶的QPS。如果是0或者-1表示不限速,默认是不限速
evictionRateLimit = flag.Float64("eviction-rate-limit", -1,`Number of pods that can be evicted per seconds. A rate limit set to 0 or -1 will disable the rate limiter.`)
​
令牌桶的burst大小
evictionRateBurst = flag.Int("eviction-rate-burst", 1, `Burst of pods that can be evicted.`)
​
暴露Prometheus metrics指标的地址
address = flag.String("address", ":8943", "The address to expose Prometheus metrics.")
​
是否检验AdmissionControllerStatus。如果开启的话,updater必须等
useAdmissionControllerStatus = flag.Bool("use-admission-controller-status", true,
      "If true, updater will only evict pods when admission controller status is valid.")
​
vpa作用的命名空间,默认是所有命名空间
namespace          = os.Getenv("NAMESPACE")
vpaObjectNamespace = flag.String("vpa-object-namespace", apiv1.NamespaceAll, "Namespace to search for VPA objects. Empty means all namespaces will be used.")
)

1.2 NewUpdater结构体对象

// NewUpdater creates Updater with given configuration
func NewUpdater(
  cgClient dynamic.Interface,                          // 为了操作cgroups资源,增加的dynamic客户端
  cgGvr schema.GroupVersionResource,                   // cgroups的 gvr
  kubeClient kube_client.Interface,                   
  vpaClient *vpa_clientset.Clientset,                  
  minReplicasForEvicition int,                        
  evictionRateLimit float64,
  evictionRateBurst int,
  evictionToleranceFraction float64,
  useAdmissionControllerStatus bool,
  statusNamespace string,
  recommendationProcessor vpa_api_util.RecommendationProcessor,   //  处理推荐资源相关的process,在vertical-pod-autoscaler/pkg/utils/vpa/capping.go
  evictionAdmission priority.PodEvictionAdmission,                 // 默认为空
  selectorFetcher target.VpaTargetSelectorFetcher,                 // selector相关
  priorityProcessor priority.PriorityProcessor,                    // 驱逐优先级处理。会更加资源diff进行过滤
  namespace string,
) (Updater, error) {
  evictionRateLimiter := getRateLimiter(evictionRateLimit, evictionRateBurst)
  factory, err := eviction.NewPodsEvictionRestrictionFactory(kubeClient, minReplicasForEvicition, evictionToleranceFraction)
  if err != nil {
    return nil, fmt.Errorf("Failed to create eviction restriction factory: %v", err)
  }
  return &updater{
    cgClient:                     cgClient,
    cgGvr:                        cgGvr,
    vpaLister:                    vpa_api_util.NewVpasLister(vpaClient, make(chan struct{}), namespace),
    podLister:                    newPodLister(kubeClient, namespace),
    eventRecorder:                newEventRecorder(kubeClient),
    evictionFactory:              factory,
    recommendationProcessor:      recommendationProcessor,
    evictionRateLimiter:          evictionRateLimiter,
    evictionAdmission:            evictionAdmission,
    priorityProcessor:            priorityProcessor,
    selectorFetcher:              selectorFetcher,
    useAdmissionControllerStatus: useAdmissionControllerStatus,
    statusValidator: status.NewValidator(
      kubeClient,
      status.AdmissionControllerStatusName,
      statusNamespace,
    ),
  }, nil
}

1.3 updater流程

每隔1分钟进行以下的运行逻辑:

  1. 获取所有的vpa, 并进行遍历,对于每个vpa而言,执行以下步骤

    1.1 如果vpa.model != auto 或者vpa.model != recreate, 直接跳过这个vpa

    1.2 根据vpa对应的selector, 获取所有的pods,假设为 allPods

    1.3 从allPods中过滤deletionTimestamp != nil 的pods, 假设为 activesPods

    1.4 从activesPods中过滤可以进行驱逐的pod, 假设为canEvictedPods. 判断逻辑如下:

    • updater启动时有两个参数:defaultUpdateThreshold = 0.10。podLifetimeUpdateThreshold = time.Hour * 12

      含义为:

      如果一个pod从开始运行到当前时间,没有超过12小时(podLifetimeUpdateThreshold),不能进行驱逐

      如果一个pod从资源改变在 0.1范围内,不应该驱逐。这个0.1是 cpu + memory的和。

    • 结合OOM事件,判断pod是否应该Evict,这个目前待确定细节

  2. 经过第一步,得到一个map, key=vap, value= canEvictedPods (这是一个列表,表示需要驱逐的pod)

  3. 遍历上诉map, 针对某个vpa进行以下逻辑判断。

    updater启动时还有两个参数,控制没轮驱逐时pod的数量

    • evictionTolerance 表示当前没轮驱逐的比例,默认0.5。 假设当前vpa对应的canEvictedPods有10个pod, 那么当前只会驱逐5个。

    • min-replica 表示rs最少可用的pod数量。例如一个rs 当前只有2个pod running, 就是前面满足了驱逐条件,到这里也不会驱逐。

热升级调整的逻辑:

(1)修改 podLifetimeUpdateThreshold = 30s

(2)跳过canEvictedPods逻辑

2. updater驱逐逻辑如下:

每隔1分钟进行以下的运行逻辑:

  1. 获取所有的vpa, 并进行遍历,对于每个vpa而言,执行以下步骤

    1.1 如果vpa.model != auto 或者vpa.model != recreate, 直接跳过这个vpa

    1.2 根据vpa对应的selector, 获取所有的pods,假设为 allPods

    1.3 从allPods中过滤deletionTimestamp != nil 的pods, 假设为 activesPods

    1.4 从activesPods中过滤可以进行驱逐的pod, 假设为canEvictedPods. 判断逻辑如下:

    • updater启动时有两个参数:defaultUpdateThreshold = 0.10。podLifetimeUpdateThreshold = time.Hour * 12

      含义为:

      如果一个pod从开始运行到当前时间,没有超过12小时(podLifetimeUpdateThreshold),不能进行驱逐

      如果一个pod从资源改变在 0.1范围内,不应该驱逐。这个0.1是 cpu + memory的和。

    • 结合OOM事件,判断pod是否应该Evict,这个目前待确定细节

  2. 经过第一步,得到一个map, key=vap, value= canEvictedPods (这是一个列表,表示需要驱逐的pod)

  3. 遍历上诉map, 针对某个vpa进行以下逻辑判断。

    updater启动时还有两个参数,控制没轮驱逐时pod的数量

    • evictionTolerance 表示当前没轮驱逐的比例,默认0.5。 假设当前vpa对应的canEvictedPods有10个pod, 那么当前只会驱逐5个。

    • min-replica 表示rs最少可用的pod数量。例如一个rs 当前只有2个pod running, 就是前面满足了驱逐条件,到这里也不会驱逐。

2.1 总结

感觉驱逐逻辑迁移到cgroupManager可以如下:

(1)继承上诉的步骤1,步骤2,因为是热升级,所以不用关注步骤三(考虑min-replica )

(2)OOM事件会影响pod驱逐,但是是热升级的情况下感觉可以忽略

3.vpa的修改pod资源的逻辑

  • vap修改的都是pod的request值,但是limit值会按照比例进行扩缩

  • Deploy yaml中没有指定limit,vpa也不会修改limit

  • vpa不会修改pod的QOS类型

举例说明会更清楚一点:

场景1 deploy yaml中设置了requet, limit

假设deploy yaml中定义的资源为:(这里limit:request=2:1)

   resources:
      limits:
        cpu: 2
        memory: 2Gi
      requests:
        cpu: 1
        memory: 1Gi

而vpa推荐值为:cpu=25m mem=262144k。那么这个pod实际运行时的request如下:

   resources:
      limits:                 //limit会改变,会维持limit:request=2:1的关系
        cpu: 50m
        memory: 500Mi
      requests:              // request采用的是vpa的值
        cpu: 25m
        memory: 262144k

场景2 pod yaml只中设置了requet没有设置limit

假设pod yaml中定义的资源为:(这里没有limit)

resources:
      requests:
        cpu: 1
        memory: 1Gi

而vpa推荐值为:cpu=25m mem=262144k。那么这个pod实际运行时的request如下:

   resources:     
      requests:              // request采用的是vpa的值。也不会有limit
        cpu: 25m
        memory: 262144k

场景3 pod yaml没有设置resources

假设pod yaml中定义没有定义资源:(besteffort)

而vpa推荐值为:cpu=25m mem=262144k。那么这个pod实际运行时的request如下:

resources:     
  requests:              // request采用的是vpa的值。也不会有limit
    cpu: 25m
    memory: 262144k
 类似资料: