kubernets学习kuberne...

vpa updater 源码分析

2022-07-09  本文已影响0人  zoux

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资源的逻辑

举例说明会更清楚一点:

场景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
上一篇 下一篇

猜你喜欢

热点阅读