成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Kubernetes 節(jié)點自動伸縮(Cluster Autoscaler)原理與實踐

云計算 云原生
Cluster Autoscaler(簡稱 CA) 作為 Kubernetes 官方提供的自動伸縮組件,通過監(jiān)控調(diào)度器中未能調(diào)度的 Pod,并自動調(diào)整節(jié)點數(shù)量,為集群資源的動態(tài)調(diào)配提供了一種高效解決方案。

在 Kubernetes 集群中,如何在保障應用高可用的同時有效地管理資源,一直是運維人員和開發(fā)者關注的重點。隨著微服務架構的普及,集群內(nèi)各個服務的負載波動日趨明顯,傳統(tǒng)的手動擴縮容方式已無法滿足實時性和彈性需求。

Cluster Autoscaler(簡稱 CA) 作為 Kubernetes 官方提供的自動伸縮組件,通過監(jiān)控調(diào)度器中未能調(diào)度的 Pod,并自動調(diào)整節(jié)點數(shù)量,為集群資源的動態(tài)調(diào)配提供了一種高效解決方案。

Kubernetes 的自動伸縮分為三個維度:

  • Pod 級別:Horizontal Pod Autoscaler (HPA) 根據(jù) CPU/內(nèi)存等指標調(diào)整 Pod 副本數(shù);
  • 節(jié)點級別:Cluster Autoscaler (CA) 動態(tài)調(diào)整集群節(jié)點數(shù)量;
  • 資源粒度:Vertical Pod Autoscaler (VPA) 動態(tài)調(diào)整 Pod 的 Request/Limit。

本篇文章,就來詳細介紹下 CA 的原理和實踐。

一、 Cluster Autoscaler 工作原理

CA 抽象出了一個 NodeGroup 的概念,與之對應的是云廠商的伸縮組服務。CA 通過 CloudProvider 提供的 NodeGroup 計算集群內(nèi)節(jié)點資源,以此來進行伸縮。

CA 啟動后,CA 會定期(默認 10s)檢查未調(diào)度的 Pod 和 Node 的資源使用情況,并進行相應的 Scale UP 和 Scale Down 操作。

CA 由以下幾個模塊組成:

  • autoscaler:核心模塊,負責整體擴縮容功能;
  • estimator:負責評估計算擴容節(jié)點;
  • simulator:負責模擬調(diào)度,計算縮容節(jié)點;

CA cloud-provider:與云交互進行節(jié)點的增刪操作。社區(qū)目前僅支持AWS和GCE,其他云廠商需要自己實現(xiàn)CloudProvider和NodeGroup相關接口。

CA的架構如下:

接下來,我們來看下 CA 的擴縮容時的具體工作流程(原理)。

1. 擴容原理(Scale UP)

當 Cluster Autoscaler 發(fā)現(xiàn)有 Pod 由于資源不足而無法調(diào)度時,就會通過調(diào)用 Scale UP 執(zhí)行擴容操作。

CA 擴容時會根據(jù)擴容策略,選擇合適的 NodeGroup。為了業(yè)務需要,集群中可能會有不同規(guī)格的 Node,我們可以創(chuàng)建多個 NodeGroup,在擴容時會根據(jù) --expander 選項配置指定的策略,選擇一個擴容的節(jié)點組,支持如下五種策略:

  • random:隨機選擇一個 NodeGroup。如果未指定,則默認為此策略;
  • most-pods:選擇能夠調(diào)度最多 Pod 的 NodeGroup,比如有的 Pod 未調(diào)度是因為 nodeSelector,此策略會優(yōu)先選擇能滿足的 NodeGroup 來保證大多數(shù)的 Pod 可以被調(diào)度;
  • least-waste:為避免浪費,此策略會優(yōu)先選擇能滿足 Pod 需求資源的最小資源類型的 NodeGroup。
  • price:根據(jù) CloudProvider 提供的價格模型,選擇最省錢的 NodeGroup;
  • priority:通過配置優(yōu)先級來進行選擇,用起來比較麻煩,需要額外的配置,可以看Priority based expander for cluster-autoscaler。

如果有需要,也可以平衡相似 NodeGroup 中的 Node 數(shù)量,避免 NodeGroup 達到 MaxSize 而導致無法加入新 Node。通過 --balance-similar-node-groups 選項配置,默認為 false。

再經(jīng)過一系列的操作后,最終計算出要擴容的 Node 數(shù)量及 NodeGroup,使用 CloudProvider 執(zhí)行 IncreaseSize 操作,增加云廠商的伸縮組大小,從而完成擴容操作。

2. CA 擴容流程

Cluster Autoscaler 的擴容核心在于對集群資源的實時監(jiān)控和決策,其主要工作流程如下:

(1) 監(jiān)控未調(diào)度的 Pod: 當 Kubernetes 調(diào)度器發(fā)現(xiàn)某個 Pod 因為資源不足而無法被調(diào)度到現(xiàn)有節(jié)點時,CA 會監(jiān)測到因無法調(diào)度而 Pending 的 Pod,進而觸發(fā) CA 擴容操作。CA 擴容的觸發(fā)條件如下:

  • Pod 因資源不足(CPU/Memory/GPU)無法調(diào)度;
  • Pod 因節(jié)點選擇器(NodeSelector)、親和性(Affinity)或污點容忍(Tolerations)不匹配無法調(diào)度;
  • 節(jié)點資源碎片化導致無法容納 Pod(例如剩余資源分散在不同節(jié)點)。

(2) 節(jié)點模板選擇:CA 根據(jù)每個節(jié)點池的節(jié)點模板進行調(diào)度判斷,挑選合適的節(jié)點模板。若有多個模板合適,即有多個可擴的節(jié)點池備選,CA 會調(diào)用 expanders 從多個模板挑選最優(yōu)模板并對對應節(jié)點池進行擴容。選擇了 NodeGroup 之后,便會調(diào)用云平臺的 API 創(chuàng)建新的節(jié)點,并加入到集群中。

(3) 節(jié)點加入與 Pod 調(diào)度: 新增節(jié)點加入后,調(diào)度器重新調(diào)度之前未能分配的 Pod,滿足業(yè)務需求。

3. CA ScaleUp 源碼剖析

CA 擴容時調(diào)用,ScaleUp 的源碼剖析如下:

func ScaleUp(context *context.AutoscalingContext, processors *ca_processors.AutoscalingProcessors, clusterStateRegistry *clusterstate.ClusterStateRegistry, unschedulablePods []*apiv1.Pod, nodes []*apiv1.Node, daemonSets []*appsv1.DaemonSet, nodeInfos map[string]*schedulernodeinfo.NodeInfo, ignoredTaints taints.TaintKeySet) (*status.ScaleUpStatus, errors.AutoscalerError) {
    
    ......
    // 驗證當前集群中所有 ready node 是否來自于 nodeGroups,取得所有非組內(nèi)的 node
    nodesFromNotAutoscaledGroups, err := utils.FilterOutNodesFromNotAutoscaledGroups(nodes, context.CloudProvider)
    if err != nil {
        return &status.ScaleUpStatus{Result: status.ScaleUpError}, err.AddPrefix("failed to filter out nodes which are from not autoscaled groups: ")
    }

    nodeGroups := context.CloudProvider.NodeGroups()
    gpuLabel := context.CloudProvider.GPULabel()
    availableGPUTypes := context.CloudProvider.GetAvailableGPUTypes()

    // 資源限制對象,會在 build cloud provider 時傳入
    // 如果有需要可在 CloudProvider 中自行更改,但不建議改動,會對用戶造成迷惑
    resourceLimiter, errCP := context.CloudProvider.GetResourceLimiter()
    if errCP != nil {
        return &status.ScaleUpStatus{Result: status.ScaleUpError}, errors.ToAutoscalerError(
            errors.CloudProviderError,
            errCP)
    }

    // 計算資源限制
    // nodeInfos 是所有擁有節(jié)點組的節(jié)點與示例節(jié)點的映射
    // 示例節(jié)點會優(yōu)先考慮真實節(jié)點的數(shù)據(jù),如果 NodeGroup 中還沒有真實節(jié)點的部署,則使用 Template 的節(jié)點數(shù)據(jù)
    scaleUpResourcesLeft, errLimits := computeScaleUpResourcesLeftLimits(context.CloudProvider, nodeGroups, nodeInfos, nodesFromNotAutoscaledGroups, resourceLimiter)
    if errLimits != nil {
        return &status.ScaleUpStatus{Result: status.ScaleUpError}, errLimits.AddPrefix("Could not compute total resources: ")
    }

    // 根據(jù)當前節(jié)點與 NodeGroups 中的節(jié)點來計算會有多少節(jié)點即將加入集群中
    // 由于云服務商的伸縮組 increase size 操作并不是同步加入 node,所以將其統(tǒng)計,以便于后面計算節(jié)點資源
    upcomingNodes := make([]*schedulernodeinfo.NodeInfo, 0)
    for nodeGroup, numberOfNodes := range clusterStateRegistry.GetUpcomingNodes() {
        ......
    }
    klog.V(4).Infof("Upcoming %d nodes", len(upcomingNodes))

    // 最終會進入選擇的節(jié)點組
    expansionOptions := make(map[string]expander.Option, 0)
    ......
    // 出于某些限制或錯誤導致不能加入新節(jié)點的節(jié)點組,例如節(jié)點組已達到 MaxSize
    skippedNodeGroups := map[string]status.Reasons{}
    // 綜合各種情況,篩選出節(jié)點組
    for _, nodeGroup := range nodeGroups {
    ......
    }
    iflen(expansionOptions) == 0 {
        klog.V(1).Info("No expansion options")
        return &status.ScaleUpStatus{
            Result:                 status.ScaleUpNoOptionsAvailable,
            PodsRemainUnschedulable: getRemainingPods(podEquivalenceGroups, skippedNodeGroups),
            ConsideredNodeGroups:   nodeGroups,
        }, nil
    }

    ......
    // 選擇一個最佳的節(jié)點組進行擴容,expander 用于選擇一個合適的節(jié)點組進行擴容,默認為 RandomExpander,flag: expander
    // random 隨機選一個,適合只有一個節(jié)點組
    // most-pods 選擇能夠調(diào)度最多 pod 的節(jié)點組,比如有 noSchedulerPods 是有 nodeSelector 的,它會優(yōu)先選擇此類節(jié)點組以滿足大多數(shù) pod 的需求
    // least-waste 優(yōu)先選擇能滿足 pod 需求資源的最小資源類型的節(jié)點組
    // price 根據(jù)價格模型,選擇最省錢的
    // priority 根據(jù)優(yōu)先級選擇
    bestOption := context.ExpanderStrategy.BestOption(options, nodeInfos)
    if bestOption != nil && bestOption.NodeCount > 0 {
    ......
        newNodes := bestOption.NodeCount

        // 考慮到 upcomingNodes, 重新計算本次新加入節(jié)點
        if context.MaxNodesTotal > 0 && len(nodes)+newNodes+len(upcomingNodes) > context.MaxNodesTotal {
            klog.V(1).Infof("Capping size to max cluster total size (%d)", context.MaxNodesTotal)
            newNodes = context.MaxNodesTotal - len(nodes) - len(upcomingNodes)
            if newNodes < 1 {
                return &status.ScaleUpStatus{Result: status.ScaleUpError}, errors.NewAutoscalerError(
                    errors.TransientError,
                    "max node total count already reached")
            }
        }

        createNodeGroupResults := make([]nodegroups.CreateNodeGroupResult, 0)
    
        // 如果節(jié)點組在云服務商端處不存在,會嘗試創(chuàng)建根據(jù)現(xiàn)有信息重新創(chuàng)建一個云端節(jié)點組
        // 但是目前所有的 CloudProvider 實現(xiàn)都沒有允許這種操作,這好像是個多余的方法
        // 云服務商不想,也不應該將云端節(jié)點組的創(chuàng)建權限交給 ClusterAutoscaler
        if !bestOption.NodeGroup.Exist() {
            oldId := bestOption.NodeGroup.Id()
            createNodeGroupResult, err := processors.NodeGroupManager.CreateNodeGroup(context, bestOption.NodeGroup)
        ......
        }

        // 得到最佳節(jié)點組的示例節(jié)點
        nodeInfo, found := nodeInfos[bestOption.NodeGroup.Id()]
        if !found {
            // This should never happen, as we already should have retrieved
            // nodeInfo for any considered nodegroup.
            klog.Errorf("No node info for: %s", bestOption.NodeGroup.Id())
            return &status.ScaleUpStatus{Result: status.ScaleUpError, CreateNodeGroupResults: createNodeGroupResults}, errors.NewAutoscalerError(
                errors.CloudProviderError,
                "No node info for best expansion option!")
        }

        // 根據(jù) CPU、Memory及可能存在的 GPU 資源(hack: we assume anything which is not cpu/memory to be a gpu.),計算出需要多少個 Nodes
        newNodes, err = applyScaleUpResourcesLimits(context.CloudProvider, newNodes, scaleUpResourcesLeft, nodeInfo, bestOption.NodeGroup, resourceLimiter)
        if err != nil {
            return &status.ScaleUpStatus{Result: status.ScaleUpError, CreateNodeGroupResults: createNodeGroupResults}, err
        }

        // 需要平衡的節(jié)點組
        targetNodeGroups := []cloudprovider.NodeGroup{bestOption.NodeGroup}
        // 如果需要平衡節(jié)點組,根據(jù) balance-similar-node-groups flag 設置。
        // 檢測相似的節(jié)點組,并平衡它們之間的節(jié)點數(shù)量
        if context.BalanceSimilarNodeGroups {
        ......
        }
        // 具體平衡策略可以看 (b *BalancingNodeGroupSetProcessor) BalanceScaleUpBetweenGroups 方法
        scaleUpInfos, typedErr := processors.NodeGroupSetProcessor.BalanceScaleUpBetweenGroups(context, targetNodeGroups, newNodes)
        if typedErr != nil {
            return &status.ScaleUpStatus{Result: status.ScaleUpError, CreateNodeGroupResults: createNodeGroupResults}, typedErr
        }
        klog.V(1).Infof("Final scale-up plan: %v", scaleUpInfos)
        // 開始擴容,通過 IncreaseSize 擴容
        for _, info := range scaleUpInfos {
            typedErr := executeScaleUp(context, clusterStateRegistry, info, gpu.GetGpuTypeForMetrics(gpuLabel, availableGPUTypes, nodeInfo.Node(), nil), now)
            if typedErr != nil {
                return &status.ScaleUpStatus{Result: status.ScaleUpError, CreateNodeGroupResults: createNodeGroupResults}, typedErr
            }
        }
        ......
    }
    ......
}

4. 縮容原理(Scale Down)

縮容是一個可選的功能,通過 --scale-down-enabled 選項配置,默認為 true。在 CA 監(jiān)控 Node 資源時,如果發(fā)現(xiàn)有 Node 滿足以下三個條件時,就會標記這個 Node 為 unneeded:

  • Node 上運行的所有的 Pod 的 CPU 和內(nèi)存之和小于該 Node 可分配容量的 50%。可通過 --scale-down-utilization-threshold 選項改變這個配置;
  • Node 上所有的 Pod 都可以被調(diào)度到其他節(jié)點;
  • Node 沒有表示不可縮容的 annotaition。

如果一個 Node 被標記為 unneeded 超過 10 分鐘(可通過 --scale-down-unneeded-time 選項配置),則使用 CloudProvider 執(zhí)行 DeleteNodes 操作將其刪除。一次最多刪除一個 unneeded Node,但空 Node 可以批量刪除,每次最多刪除 10 個(通過 --max-empty-bulk-delete 選項配置)。

實際上并不是只有這一個判定條件,還會有其他的條件來阻止刪除這個 Node,比如 NodeGroup 已達到 MinSize,或在過去的 10 分鐘內(nèi)有過一次 Scale UP 操作(通過 --scale-down-delay-after-add 選項配置)等等,更詳細可查看 How does scale-down work?。

在決定縮容前,CA 會通過調(diào)度器模擬 Pod 遷移過程,確保其他節(jié)點有足夠資源接收被遷移的 Pod。若模擬失敗(如資源不足或親和性沖突),則放棄縮容。

4. CA 縮容流程

(1) CA 監(jiān)測到分配率(即 Request 值,取 CPU 分配率和 MEM 分配率的最大值)低于設定的節(jié)點。計算分配率時,可以設置 Daemonset 類型不計入 Pod 占用資源;

(2) CA 判斷集群的狀態(tài)是否可以觸發(fā)縮容,需要滿足如下要求:

  • 節(jié)點利用率低于閾值(默認 50%);
  • 節(jié)點上所有 Pod 均能遷移到其他節(jié)點(包括容忍 PDB 約束);
  • 節(jié)點持續(xù)空閑時間超過 scale-down-unneeded-time(默認 10 分鐘)。

(3) CA 判斷該節(jié)點是否符合縮容條件。可以按需設置以下不縮容條件(滿足條件的節(jié)點不會被 CA 縮容):

  • 節(jié)點上有 pod 被 PodDisruptionBudget 控制器限制;
  • 節(jié)點上有命名空間是 kube-system 的 pods;
  • 節(jié)點上的 pod 不是被控制器創(chuàng)建,例如不是被 deployment, replica set, job, statefulset 創(chuàng)建;
  • 節(jié)點上有 pod 使用了本地存儲;
  • 節(jié)點上 pod 驅(qū)逐后無處可去,即沒有其他node能調(diào)度這個 pod;
  • 節(jié)點有注解:"cluster-autoscaler.kubernetes.io/scale-down-disabled": "true"(在 CA 1.0.3 或更高版本中受支持)。

(4) CA 驅(qū)逐節(jié)點上的 Pod 后釋放/關機節(jié)點。

  • 完全空閑節(jié)點可并發(fā)縮容(可設置最大并發(fā)縮容數(shù));
  • 非完全空閑節(jié)點逐個縮容。

Cluster Autoscaler 在縮容時會檢查 PodDisruptionBudget (PDB),確保驅(qū)逐 Pod 不會違反最小可用副本數(shù)約束。若 Pod 受 PDB 保護且驅(qū)逐可能導致違反約束,則該節(jié)點不會被縮容。

二、與云服務提供商的集成

Cluster Autoscaler 原生支持多個主流云平臺,如 AWS、GCP、Azure 等。它通過調(diào)用云服務 API 來實現(xiàn)節(jié)點的創(chuàng)建和銷毀。實踐中需要注意:

  • 認證與權限: 確保 Cluster Autoscaler 擁有足夠的權限調(diào)用云平臺的相關 API,通常需要配置相應的 IAM 角色或 API 密鑰。
  • 節(jié)點組配置: 集群內(nèi)通常會預先劃分多個節(jié)點組,每個節(jié)點組對應不同的資源規(guī)格和用途。在擴縮容決策時,Autoscaler 會根據(jù) Pod 的資源需求選擇最合適的節(jié)點組。

多節(jié)點組配置示例(以 AWS 為例):

apiVersion: eksctl.io/v1alpha5
kind:ClusterConfig
nodeGroups:
-name:ng-spot
    instanceType:m5.large
    spot:true
    minSize:0
    maxSize:10
    labels:
      node-type:spot
-name:ng-on-demand
    instanceType:m5.xlarge
    minSize:1
    maxSize:5
    labels:
      node-type:on-demand

通過標簽區(qū)分節(jié)點組,CA 可根據(jù) Pod 的 nodeSelector 選擇擴縮容目標組。

混合云注意事項:若集群跨公有云和本地數(shù)據(jù)中心,需確保 CA 僅管理云上節(jié)點組,避免誤刪物理節(jié)點。可通過注釋排除本地節(jié)點組:

metadata:
  annotations:
    cluster-autoscaler.kubernetes.io/scale-down-disabled: "true"

1. 如何實現(xiàn) CloudProvider?

如果使用上述中已實現(xiàn)接入的云廠商,只需要通過 --cloud-provider 選項指定來自哪個云廠商就可以,如果想要對接自己的 IaaS 或有特定的業(yè)務邏輯,就需要自己實現(xiàn) CloudProvider Interface 與 NodeGroup Interface。并將其注冊到 builder 中,用于通過 --cloud-provider 參數(shù)指定。

builder 在 cloudprovider/builder 中的 builder_all.go 中注冊,也可以在其中新建一個自己的 build,通過 go 文件的 +build 編譯參數(shù)來指定使用的 CloudProvider。

CloudProvider 接口與 NodeGroup 接口在 cloud_provider.go 中定義,其中需要注意的是 Refresh 方法,它會在每一次循環(huán)(默認 10 秒)的開始時調(diào)用,可在此時請求接口并刷新 NodeGroup 狀態(tài),通常的做法是增加一個 manager 用于管理狀態(tài)。有不理解的部分可參考其他 CloudProvider 的實現(xiàn)。

type CloudProvider interface {
    // Name returns name of the cloud provider.
    Name() string

    // NodeGroups returns all node groups configured for this cloud provider.
    // 會在一此循環(huán)中多次調(diào)用此方法,所以不適合每次都請求云廠商服務,可以在 Refresh 時存儲狀態(tài)
    NodeGroups() []NodeGroup

    // NodeGroupForNode returns the node group for the given node, nil if the node
    // should not be processed by cluster autoscaler, or non-nil error if such
    // occurred. Must be implemented.
    // 同上
    NodeGroupForNode(*apiv1.Node) (NodeGroup, error)

    // Pricing returns pricing model for this cloud provider or error if not available.
    // Implementation optional.
    // 如果不使用 price expander 就可以不實現(xiàn)此方法
    Pricing() (PricingModel, errors.AutoscalerError)

    // GetAvailableMachineTypes get all machine types that can be requested from the cloud provider.
    // Implementation optional.
    // 沒用,不需要實現(xiàn)
    GetAvailableMachineTypes() ([]string, error)

    // NewNodeGroup builds a theoretical node group based on the node definition provided. The node group is not automatically
    // created on the cloud provider side. The node group is not returned by NodeGroups() until it is created.
    // Implementation optional.
    // 通常情況下,不需要實現(xiàn)此方法,但如果你需要 ClusterAutoscaler 創(chuàng)建一個默認的 NodeGroup 的話,也可以實現(xiàn)。
    // 但其實更好的做法是將默認 NodeGroup 寫入云端的伸縮組
    NewNodeGroup(machineType string, labels map[string]string, systemLabels map[string]string,
        taints []apiv1.Taint, extraResources map[string]resource.Quantity) (NodeGroup, error)

    // GetResourceLimiter returns struct containing limits (max, min) for resources (cores, memory etc.).
    // 資源限制對象,會在 build 時傳入,通常情況下不需要更改,除非在云端有顯示的提示用戶更改的地方,否則使用時會迷惑用戶
    GetResourceLimiter() (*ResourceLimiter, error)

    // GPULabel returns the label added to nodes with GPU resource.
    // GPU 相關,如果集群中有使用 GPU 資源,需要返回對應內(nèi)容。 hack: we assume anything which is not cpu/memory to be a gpu.
    GPULabel() string

    // GetAvailableGPUTypes return all available GPU types cloud provider supports.
    // 同上
    GetAvailableGPUTypes() map[string]struct{}

    // Cleanup cleans up open resources before the cloud provider is destroyed, i.e. go routines etc.
    // CloudProvider 只會在啟動時被初始化一次,如果每次循環(huán)后有需要清除的內(nèi)容,在這里處理
    Cleanup() error

    // Refresh is called before every main loop and can be used to dynamically update cloud provider state.
    // In particular the list of node groups returned by NodeGroups can change as a result of CloudProvider.Refresh().
    // 會在 StaticAutoscaler RunOnce 中被調(diào)用
    Refresh() error
}

// NodeGroup contains configuration info and functions to control a set
// of nodes that have the same capacity and set of labels.
type NodeGroup interface {
    // MaxSize returns maximum size of the node group.
    MaxSize() int

    // MinSize returns minimum size of the node group.
    MinSize() int

    // TargetSize returns the current target size of the node group. It is possible that the
    // number of nodes in Kubernetes is different at the moment but should be equal
    // to Size() once everything stabilizes (new nodes finish startup and registration or
    // removed nodes are deleted completely). Implementation required.
    // 響應的是伸縮組的節(jié)點數(shù),并不一定與 kubernetes 中的節(jié)點數(shù)保持一致
    TargetSize() (int, error)

    // IncreaseSize increases the size of the node group. To delete a node you need
    // to explicitly name it and use DeleteNode. This function should wait until
    // node group size is updated. Implementation required.
    // 擴容的方法,增加伸縮組的節(jié)點數(shù)
    IncreaseSize(delta int) error

    // DeleteNodes deletes nodes from this node group. Error is returned either on
    // failure or if the given node doesn't belong to this node group. This function
    // should wait until node group size is updated. Implementation required.
    // 刪除的節(jié)點一定要在該節(jié)點組中
    DeleteNodes([]*apiv1.Node) error
    // DecreaseTargetSize decreases the target size of the node group. This function
    // doesn't permit to delete any existing node and can be used only to reduce the
    // request for new nodes that have not been yet fulfilled. Delta should be negative.
    // It is assumed that cloud provider will not delete the existing nodes when there
    // is an option to just decrease the target. Implementation required.
    // 當 ClusterAutoscaler 發(fā)現(xiàn) kubernetes 節(jié)點數(shù)與伸縮組的節(jié)點數(shù)長時間不一致,會調(diào)用此方法來調(diào)整
    DecreaseTargetSize(delta int) error

    // Id returns an unique identifier of the node group.
    Id() string

    // Debug returns a string containing all information regarding this node group.
    Debug() string

    // Nodes returns a list of all nodes that belong to this node group.
    // It is required that Instance objects returned by this method have Id field set.
    // Other fields are optional.
    // This list should include also instances that might have not become a kubernetes node yet.
    // 返回伸縮組中的所有節(jié)點,哪怕它還沒有成為 kubernetes 的節(jié)點
    Nodes() ([]Instance, error)

    // TemplateNodeInfo returns a schedulernodeinfo.NodeInfo structure of an empty
    // (as if just started) node. This will be used in scale-up simulations to
    // predict what would a new node look like if a node group was expanded. The returned
    // NodeInfo is expected to have a fully populated Node object, with all of the labels,
    // capacity and allocatable information as well as all pods that are started on
    // the node by default, using manifest (most likely only kube-proxy). Implementation optional.
    // ClusterAutoscaler 會將節(jié)點信息與節(jié)點組對應,來判斷資源條件,如果是一個空的節(jié)點組,那么就會通過此方法來虛擬一個節(jié)點信息。
    TemplateNodeInfo() (*schedulernodeinfo.NodeInfo, error)

    // Exist checks if the node group really exists on the cloud provider side. Allows to tell the
    // theoretical node group from the real one. Implementation required.
    Exist() bool

    // Create creates the node group on the cloud provider side. Implementation optional.
    // 與 CloudProvider.NewNodeGroup 配合使用
    Create() (NodeGroup, error)

    // Delete deletes the node group on the cloud provider side.
    // This will be executed only for autoprovisioned node groups, once their size drops to 0.
    // Implementation optional.
    Delete() error

    // Autoprovisioned returns true if the node group is autoprovisioned. An autoprovisioned group
    // was created by CA and can be deleted when scaled to 0.
    Autoprovisioned() bool
}

三、實踐中的常見問題與最佳實踐

1. 部署與配置

(1) 安裝方式:Cluster Autoscaler 可以通過 Helm Chart 或直接使用官方提供的 YAML 清單進行部署。安裝完成后,建議結合日志和監(jiān)控系統(tǒng),對其運行狀態(tài)進行持續(xù)觀察;

(2) 關鍵參數(shù)配置: 根據(jù)集群規(guī)模和業(yè)務需求,合理配置參數(shù)非常關鍵。例如:

  • --scale-down-delay-after-add:設定新增節(jié)點后多久開始進行縮容判斷;
  • --max-node-provision-time:控制節(jié)點從請求到成功加入集群的最長時間。

(3) 日志與監(jiān)控: 建議將 Autoscaler 的日志與集群監(jiān)控系統(tǒng)(如 Prometheus)集成,以便及時發(fā)現(xiàn)和解決問題;

(4) 關鍵參數(shù)詳解:

參數(shù)

默認值

說明

--scale-down-delay-after-add

10m

擴容后等待多久開始縮容判斷

-scale-down-unneeded-time

10m

節(jié)點持續(xù)空閑多久后觸發(fā)縮容

--expander

random

擴容策略(支持 priority, most-pods, least-waste)

--skip-nodes-with-local-storage

true

跳過含本地存儲的節(jié)點縮容

(5) 資源請求(Request)的重要性:CA 完全依賴 Pod 的 resources.requests 計算節(jié)點資源需求。若未設置 Request 或設置過低,可能導致:

  • 擴容決策錯誤(節(jié)點資源不足);
  • 縮容激進(誤判節(jié)點利用率低)。

建議結合 VPA 或人工審核確保 Request 合理。

2. 常見問題

(1) Pod 長時間處于等待狀態(tài): 可能是由于資源請求過高或節(jié)點配置不足,建議檢查 Pod 定義和節(jié)點組資源規(guī)格是否匹配;

(2) P節(jié)點頻繁擴縮容: 這種情況可能導致集群不穩(wěn)定。通過調(diào)整縮容延遲和擴容策略,可以避免頻繁的節(jié)點創(chuàng)建和銷毀;

(3) P云平臺 API 限額: 在大規(guī)模伸縮場景下,需注意云服務商對 API 調(diào)用的限額,合理配置重試和等待機制;

(4) PDaemonSet Pod 阻礙縮容:若節(jié)點僅運行 DaemonSet Pod(如日志收集組件),默認情況下 CA 不會縮容該節(jié)點。可通過以下注解允許縮容:

kind: DaemonSet
metadata:
  annotations:
    cluster-autoscaler.kubernetes.io/daemonset-taint-eviction: "true"

(5) P僵尸節(jié)點(Zombie Node)問題:若云平臺 API 返回節(jié)點已刪除但 Kubernetes 未更新狀態(tài),CA 會持續(xù)嘗試縮容。可通過 --node-deletion-retries(默認 3)控制重試次數(shù)。

3. 最佳實踐

(1) P與 HPA 結合: 將 CA 與 HPA 聯(lián)合使用,可以實現(xiàn)從 Pod 級別到節(jié)點級別的全方位自動擴縮,提升資源利用率和集群彈性。HPA 會根據(jù)當前 CPU 負載更改部署或副本集的副本數(shù)。如果負載增加,則 HPA 將創(chuàng)建新的副本,集群中可能有足夠的空間,也可能沒有足夠的空間。如果沒有足夠的資源,CA 將嘗試啟動一些節(jié)點,以便 HPA 創(chuàng)建的 Pod 可以運行。如果負載減少,則 HPA 將停止某些副本。結果,某些節(jié)點可能變得利用率過低或完全為空,然后 CA 將終止這些不需要的節(jié)點;

(2) P定期評估和調(diào)整配置: 根據(jù)實際業(yè)務負載和集群運行情況,定期回顧和優(yōu)化 Autoscaler 的配置,確保擴縮容策略始終符合當前需求;

(3) P充分測試: 在生產(chǎn)環(huán)境部署前,建議在測試環(huán)境中模擬高負載和低負載場景,對擴縮容邏輯進行充分驗證,避免意外情況影響業(yè)務;

(4) P成本優(yōu)化策略:

  • 使用 Spot 實例節(jié)點組:通過多 AZ 和實例類型分散中斷風險;
  • 設置 --expander=priority:為成本更低的節(jié)點組分配更高優(yōu)先級;
  • 啟用 --balance-similar-node-groups:均衡相似節(jié)點組的節(jié)點數(shù)量。

(5) P穩(wěn)定性保障:

  • 為關鍵組件(如 Ingress Controller)設置 Pod 反親和性,避免單點故障;
  • 使用 podDisruptionBudget 防止縮容導致服務不可用:
apiVersion: policy/v1
kind:PodDisruptionBudget
metadata:
name:zk-pdb
spec:
minAvailable:2
selector:
    matchLabels:
      app:zookeeper

四、案例分享

以某大型電商平臺為例,該平臺在促銷期間流量激增,通過配置 Cluster Autoscaler,實現(xiàn)了在高峰期自動擴容,而在流量恢復正常后及時縮容。實踐中,他們不僅調(diào)整了擴縮容相關的時間參數(shù),還結合應用流量監(jiān)控,提前預估負載變化,確保集群資源始終處于最優(yōu)狀態(tài)。通過這種自動化手段,既保證了業(yè)務的高可用性,也大幅降低了運維成本。

案例補充:某金融公司未配置 podDisruptionBudget,導致縮容時 Kafka Pod 同時被驅(qū)逐,引發(fā)消息堆積。

解決方案:

  • 為 Kafka 設置 minAvailable: 2 的 PDB;
  • 調(diào)整 scale-down-delay-after-add 至 30 分鐘,避免促銷后立即縮容

參數(shù)調(diào)優(yōu)示例:

# 生產(chǎn)環(huán)境推薦配置(兼顧響應速度與穩(wěn)定性)
command:
-./cluster-autoscaler
---v=4
---stderrthreshold=info
---cloud-provider=aws
---skip-nodes-with-local-storage=false
---expander=least-waste
---scale-down-delay-after-add=20m
---scale-down-unneeded-time=15m
--balance-similar-node-groups=true

五、總結

Kubernetes Cluster Autoscaler 為集群的自動伸縮提供了一種高效、智能的解決方案。通過對未調(diào)度 Pod 的實時監(jiān)控和云平臺 API 的調(diào)用,Cluster Autoscaler 能夠根據(jù)實際負載動態(tài)調(diào)整集群規(guī)模,實現(xiàn)資源的按需分配。結合實際生產(chǎn)環(huán)境中的部署經(jīng)驗和最佳實踐,合理配置和調(diào)優(yōu) Autoscaler,不僅可以提升集群的彈性,還能有效降低運維成本。隨著云原生生態(tài)系統(tǒng)的不斷發(fā)展,Cluster Autoscaler 也在不斷演進,未來將為更復雜的場景提供更加完善的支持。

未來演進方向:

  • 預測性伸縮:基于歷史負載預測資源需求;
  • GPU 彈性調(diào)度:支持動態(tài)創(chuàng)建/釋放 GPU 節(jié)點;
  • 多集群協(xié)同:跨集群資源池化,實現(xiàn)全局彈性。
責任編輯:趙寧寧 來源: 令飛編程
相關推薦

2021-04-22 09:46:35

K8SCluster Aut集群

2019-12-05 09:34:29

KubernetesHPA集群

2021-03-12 07:47:44

KubernetesRedis-clustRedis

2025-03-07 10:23:46

2023-10-29 16:26:27

Python動查重

2023-02-22 07:04:05

自動機原理優(yōu)化實踐

2023-01-17 08:51:10

2023-12-21 11:53:34

KubernetesKEDA云原生

2018-04-25 07:35:07

Kubernetes節(jié)點解決方法

2020-05-22 09:12:46

HTTP3網(wǎng)絡協(xié)議

2024-12-25 16:01:01

2023-08-31 08:21:42

KubernetesKADA驅(qū)動

2009-06-08 16:52:00

2025-02-06 08:24:25

AQS開發(fā)Java

2017-04-17 15:48:15

Cinder備份實踐

2024-05-10 11:35:22

Redis延時隊列數(shù)據(jù)庫

2025-02-08 08:10:00

2022-04-07 09:30:00

自動化LinodeKubernetes

2018-10-17 10:49:49

Kubernetes存儲處理

2021-07-26 14:31:49

GitLab KubernetesFlask Web
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产高清久久久 | 91极品尤物在线播放国产 | av一级毛片 | 黄色一级免费 | 久色网| 亚洲视频三区 | 午夜视频一区 | 中文字幕一级 | 国产精品一区二区不卡 | av网站在线看 | 欧美成人一区二区三区 | 中文字幕第二十页 | 中文字幕免费视频 | 三级免费 | 日韩一区二区三区视频 | 波多野吉衣在线播放 | 在线视频一区二区三区 | av永久 | 欧美精品欧美精品系列 | 欧美日韩国产在线观看 | 久久精品亚洲一区二区三区浴池 | 中文字幕在线免费视频 | 久久久久网站 | 欧美一区二区三区在线观看 | 91精品综合久久久久久五月天 | 亚洲一区二区av | 91亚洲精品国偷拍自产在线观看 | 国产一区二区三区四区 | 亚洲精品乱码久久久久久蜜桃 | 久久一| 精品欧美一区二区精品久久 | 每日在线更新av | 99热精品6| 99精品欧美一区二区蜜桃免费 | 欧美成人影院在线 | 99re热精品视频国产免费 | 激情五月激情综合网 | 精品亚洲一区二区三区 | 亚洲成人网在线观看 | 综合色站导航 | 99免费精品视频 |