vpa updater 源碼分析

1. updater整體邏輯

updater整體邏輯是比較簡單的。

(1)定義了一個(gè)NewUpdater的對象

(2)然后每隔1分鐘,執(zhí)行NewUpdater.RunOnce

1.1 updater參數(shù)

updater輪轉(zhuǎn)周期,默認(rèn)是1分鐘
updaterInterval = flag.Duration("updater-interval", 1*time.Minute, `How often updater should run`)

rs最小可用的副本數(shù)。比如默認(rèn)是2表示,如果一個(gè)rs當(dāng)前只有2個(gè)副本可用,本輪是不會驅(qū)逐的,保障rs服務(wù)的可用性
minReplicas = flag.Int("min-replicas", 2, `Minimum number of replicas to perform update`)

pod每輪的驅(qū)逐比例
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.`)

驅(qū)逐限速,這里用了令牌桶算法,就個(gè)就是令牌桶的QPS。如果是0或者-1表示不限速,默認(rèn)是不限速
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指標(biāo)的地址
address = flag.String("address", ":8943", "The address to expose Prometheus metrics.")

是否檢驗(yàn)AdmissionControllerStatus。如果開啟的話,updater必須等
useAdmissionControllerStatus = flag.Bool("use-admission-controller-status", true,
      "If true, updater will only evict pods when admission controller status is valid.")

vpa作用的命名空間,默認(rèn)是所有命名空間
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結(jié)構(gòu)體對象

// 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,   //  處理推薦資源相關(guān)的process,在vertical-pod-autoscaler/pkg/utils/vpa/capping.go
    evictionAdmission priority.PodEvictionAdmission,                 // 默認(rèn)為空
    selectorFetcher target.VpaTargetSelectorFetcher,                 // selector相關(guān)
    priorityProcessor priority.PriorityProcessor,                    // 驅(qū)逐優(yōu)先級處理。會更加資源diff進(jìn)行過濾
    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分鐘進(jìn)行以下的運(yùn)行邏輯:

  1. 獲取所有的vpa, 并進(jìn)行遍歷,對于每個(gè)vpa而言,執(zhí)行以下步驟

    1.1 如果vpa.model != auto 或者vpa.model != recreate, 直接跳過這個(gè)vpa

    1.2 根據(jù)vpa對應(yīng)的selector, 獲取所有的pods,假設(shè)為 allPods

    1.3 從allPods中過濾deletionTimestamp != nil 的pods, 假設(shè)為 activesPods

    1.4 從activesPods中過濾可以進(jìn)行驅(qū)逐的pod, 假設(shè)為canEvictedPods. 判斷邏輯如下:

    • updater啟動時(shí)有兩個(gè)參數(shù):defaultUpdateThreshold = 0.10。podLifetimeUpdateThreshold = time.Hour * 12

      含義為:

      如果一個(gè)pod從開始運(yùn)行到當(dāng)前時(shí)間,沒有超過12小時(shí)(podLifetimeUpdateThreshold),不能進(jìn)行驅(qū)逐

      如果一個(gè)pod從資源改變在 0.1范圍內(nèi),不應(yīng)該驅(qū)逐。這個(gè)0.1是 cpu + memory的和。

    • 結(jié)合OOM事件,判斷pod是否應(yīng)該Evict,這個(gè)目前待確定細(xì)節(jié)

  2. 經(jīng)過第一步,得到一個(gè)map, key=vap, value= canEvictedPods (這是一個(gè)列表,表示需要驅(qū)逐的pod)

  3. 遍歷上訴map, 針對某個(gè)vpa進(jìn)行以下邏輯判斷。

    updater啟動時(shí)還有兩個(gè)參數(shù),控制沒輪驅(qū)逐時(shí)pod的數(shù)量

    • evictionTolerance 表示當(dāng)前沒輪驅(qū)逐的比例,默認(rèn)0.5。 假設(shè)當(dāng)前vpa對應(yīng)的canEvictedPods有10個(gè)pod, 那么當(dāng)前只會驅(qū)逐5個(gè)。
    • min-replica 表示rs最少可用的pod數(shù)量。例如一個(gè)rs 當(dāng)前只有2個(gè)pod running, 就是前面滿足了驅(qū)逐條件,到這里也不會驅(qū)逐。


熱升級調(diào)整的邏輯:

(1)修改 podLifetimeUpdateThreshold = 30s

(2)跳過canEvictedPods邏輯

2. updater驅(qū)逐邏輯如下:

每隔1分鐘進(jìn)行以下的運(yùn)行邏輯:

  1. 獲取所有的vpa, 并進(jìn)行遍歷,對于每個(gè)vpa而言,執(zhí)行以下步驟

    1.1 如果vpa.model != auto 或者vpa.model != recreate, 直接跳過這個(gè)vpa

    1.2 根據(jù)vpa對應(yīng)的selector, 獲取所有的pods,假設(shè)為 allPods

    1.3 從allPods中過濾deletionTimestamp != nil 的pods, 假設(shè)為 activesPods

    1.4 從activesPods中過濾可以進(jìn)行驅(qū)逐的pod, 假設(shè)為canEvictedPods. 判斷邏輯如下:

    • updater啟動時(shí)有兩個(gè)參數(shù):defaultUpdateThreshold = 0.10。podLifetimeUpdateThreshold = time.Hour * 12

      含義為:

      如果一個(gè)pod從開始運(yùn)行到當(dāng)前時(shí)間,沒有超過12小時(shí)(podLifetimeUpdateThreshold),不能進(jìn)行驅(qū)逐

      如果一個(gè)pod從資源改變在 0.1范圍內(nèi),不應(yīng)該驅(qū)逐。這個(gè)0.1是 cpu + memory的和。

    • 結(jié)合OOM事件,判斷pod是否應(yīng)該Evict,這個(gè)目前待確定細(xì)節(jié)

  2. 經(jīng)過第一步,得到一個(gè)map, key=vap, value= canEvictedPods (這是一個(gè)列表,表示需要驅(qū)逐的pod)

  3. 遍歷上訴map, 針對某個(gè)vpa進(jìn)行以下邏輯判斷。

    updater啟動時(shí)還有兩個(gè)參數(shù),控制沒輪驅(qū)逐時(shí)pod的數(shù)量

    • evictionTolerance 表示當(dāng)前沒輪驅(qū)逐的比例,默認(rèn)0.5。 假設(shè)當(dāng)前vpa對應(yīng)的canEvictedPods有10個(gè)pod, 那么當(dāng)前只會驅(qū)逐5個(gè)。
    • min-replica 表示rs最少可用的pod數(shù)量。例如一個(gè)rs 當(dāng)前只有2個(gè)pod running, 就是前面滿足了驅(qū)逐條件,到這里也不會驅(qū)逐。

2.1 總結(jié)

感覺驅(qū)逐邏輯遷移到cgroupManager可以如下:

(1)繼承上訴的步驟1,步驟2,因?yàn)槭菬嵘?,所以不用關(guān)注步驟三(考慮min-replica )

(2)OOM事件會影響pod驅(qū)逐,但是是熱升級的情況下感覺可以忽略

3.vpa的修改pod資源的邏輯

  • vap修改的都是pod的request值,但是limit值會按照比例進(jìn)行擴(kuò)縮

  • Deploy yaml中沒有指定limit,vpa也不會修改limit

  • vpa不會修改pod的QOS類型

舉例說明會更清楚一點(diǎn):

場景1 deploy yaml中設(shè)置了requet, limit

假設(shè)deploy yaml中定義的資源為:(這里limit:request=2:1)

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

而vpa推薦值為:cpu=25m mem=262144k。那么這個(gè)pod實(shí)際運(yùn)行時(shí)的request如下:

    resources:
      limits:                 //limit會改變,會維持limit:request=2:1的關(guān)系
        cpu: 50m
        memory: 500Mi
      requests:              // request采用的是vpa的值
        cpu: 25m
        memory: 262144k


場景2 pod yaml只中設(shè)置了requet沒有設(shè)置limit

假設(shè)pod yaml中定義的資源為:(這里沒有l(wèi)imit)

 resources:
      requests:
        cpu: 1
        memory: 1Gi

而vpa推薦值為:cpu=25m mem=262144k。那么這個(gè)pod實(shí)際運(yùn)行時(shí)的request如下:

    resources:     
      requests:              // request采用的是vpa的值。也不會有l(wèi)imit
        cpu: 25m
        memory: 262144k

場景3 pod yaml沒有設(shè)置resources

假設(shè)pod yaml中定義沒有定義資源:(besteffort)

而vpa推薦值為:cpu=25m mem=262144k。那么這個(gè)pod實(shí)際運(yùn)行時(shí)的request如下:

resources:     
  requests:              // request采用的是vpa的值。也不會有l(wèi)imit
    cpu: 25m
    memory: 262144k
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容