運算和自動擴展 - Amazon EKS

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

運算和自動擴展

身為開發人員,您將預估應用程式的資源需求,例如 CPU 和記憶體,但如果您沒有持續調整,它們可能會過期,進而增加成本並提高效能和可靠性。持續調整應用程式的資源需求,比第一次就正確調整更重要。

以下提及的最佳實務將協助您建置和操作成本感知工作負載,以實現業務成果,同時將成本降至最低,並讓您的組織將投資報酬率最大化。最佳化叢集運算成本的重要高階順序如下:

  1. 適當大小的工作負載

  2. 減少未使用的容量

  3. 最佳化運算容量類型 (例如 Spot) 和加速器 (例如 GPUs)

適當調整工作負載大小

在大多數 EKS 叢集中,大量成本來自用來執行容器化工作負載的 EC2 執行個體。若未了解工作負載需求,您將無法調整運算資源的大小。因此,您必須使用適當的請求和限制,並視需要調整這些設定。此外,執行個體大小和儲存體選擇等相依性可能會影響工作負載效能,進而對成本和可靠性造成各種意外後果。

請求應與實際使用率相符。如果容器的請求太高,則會有未使用的容量,這是叢集總成本的一大因素。Pod 中的每個容器,例如應用程式和附屬,都應設定自己的請求和限制,以確保彙總 Pod 限制盡可能準確。

利用諸如 GoldilocksKRRKubecost 等工具來估計容器的資源請求和限制。根據應用程式的性質、效能/成本需求,以及評估哪些指標最適合擴展、應用程式效能下降的時間點 (飽和點),以及如何相應調整請求和限制的複雜性。如需本主題的進一步指引,請參閱應用程式正確調整大小

我們建議您使用 Horizontal Pod Autoscaler (HPA) 來控制應用程式應執行的複本數量、使用 Vertical Pod Autoscaler (VPA) 來調整每個複本的應用程式請求數量和限制,以及使用 KarpenterCluster Autoscaler 等節點自動擴展器來持續調整叢集中的節點總數。本文件稍後章節會記錄使用 Karpenter 和 Cluster Autoscaler 的成本最佳化技術。

垂直 Pod Autoscaler 可以調整指派給容器的請求和限制,以便工作負載以最佳方式執行。您應該在稽核模式下執行 VPA,這樣它就不會自動進行變更並重新啟動您的 Pod。它會根據觀察到的指標建議變更。對於影響生產工作負載的任何變更,您應該先在非生產環境中檢閱和測試這些變更,因為這些變更可能會影響應用程式的可靠性和效能。

減少耗用量

節省成本的最佳方法是佈建較少的資源。其中一種方法是根據工作負載的目前需求調整工作負載。您應該透過確保您的工作負載定義其需求並動態擴展,開始任何成本最佳化工作。這將需要從您的應用程式取得指標並設定組態,例如 PodDisruptionBudgetsPod 整備閘道,以確保您的應用程式可以安全地動態擴展和縮減。請務必考慮限制性 PodDisruptionBudgets 可防止 Cluster Autoscaler 和 Karpenter 縮減節點,因為 Cluster Autoscaler 和 Karpenter 都遵守 PodDisruptionBudgets。PodDisruptionBudget 中的 'minAvailable' 值應一律低於部署中的 Pod 數量,而且您應該在兩個 之間保持良好的緩衝,例如,在 6 個 Pod 的部署中,您希望 Pod 中至少隨時執行 4 個 Pod,請將 PodDisruptionBidget 中的 'minAvailable' 設定為 4。這將允許 Cluster Autoscaler 和 Karpenter 在節點縮減規模事件期間安全地從未充分利用的節點中耗盡和移出 Pod。請參閱 Cluster Autoscaler 常見問答集文件。

Horizontal Pod Autoscaler 是一種靈活的工作負載自動擴展器,可以調整需要多少個複本才能滿足應用程式的效能和可靠性需求。它具有彈性的模型,可根據 CPU、記憶體或自訂指標等各種指標,例如佇列深度、Pod 的連線數等,來定義何時擴展和縮減。

Kubernetes Metrics Server 可針對 CPU 和記憶體用量等內建指標進行擴展,但如果您想要根據 Amazon CloudWatch 或 SQS 佇列深度等其他指標進行擴展,則應考慮事件驅動的自動擴展專案,例如 KEDA。請參閱此部落格文章,了解如何搭配 CloudWatch 指標使用 KEDA。如果您不確定要根據哪些指標進行監控和擴展,請查看監控重要指標的最佳實務

減少工作負載耗用量會在叢集中產生多餘的容量,而使用適當的自動擴展組態可讓您自動縮減節點,並減少總支出。建議您不要嘗試手動最佳化運算容量。Kubernetes 排程器和節點自動擴展器旨在為您處理此程序。

減少未使用的容量

確定應用程式的正確大小後,減少過多的請求,您可以開始減少佈建的運算容量。如果您已花時間從上述區段正確調整工作負載大小,應該可以動態執行此操作。AWS 中與 Kubernetes 搭配使用的主要節點自動擴展器有兩個。

Karpenter 和 Cluster Autoscaler

Karpenter 和 Kubernetes Cluster Autoscaler 都會在建立或移除 Pod 和運算需求變更時,擴展叢集中的節點數量。兩者的主要目標是相同的,但 Karpenter 採用不同的節點管理佈建和取消佈建方法,這有助於降低成本和最佳化叢集整體用量。

隨著叢集大小的增加和工作負載的變多,預先設定節點群組和執行個體變得更加困難。如同工作負載請求一樣,設定初始基準並持續視需要調整也很重要。

如果您使用的是 Cluster Autoscaler,它會遵守每個 Auto Scaling 群組 (ASG) 的「最小值」和「最大值」值,並且只調整「所需」值。設定基礎 ASG 的這些值時請務必注意,因為 Cluster Autoscaler 無法將 ASG 縮減到超過其「最小」計數。將「所需」計數設定為您在正常上班時間所需的節點數量,並將「最少」設定為您在非上班時間所需的節點數量。請參閱 Cluster Autoscaler 常見問答集文件。

Cluster Autoscaler Priority Expander

Kubernetes Cluster Autoscaler 的運作方式是隨著應用程式擴展和縮減,擴展和縮減節點群組,稱為節點群組。如果您不是動態擴展工作負載,則 Cluster Autoscaler 不會協助您節省成本。Cluster Autoscaler 需要叢集管理員事先建立節點群組,工作負載才能使用。節點群組需要設定為使用具有相同「設定檔」的執行個體,即大約相同數量的 CPU 和記憶體。

您可以擁有多個節點群組,而且 Cluster Autoscaler 可以設定為設定優先順序擴展層級,而且每個節點群組可以包含大小不同的節點。節點群組可以有不同的容量類型,而優先順序擴展器可以用來先擴展成本較低的群組。

以下是叢集組態片段的範例,該程式碼片段使用 ConfigMap`來排定保留容量的優先順序,然後再使用隨需執行個體。您可以使用相同的技術,將 Graviton 或 Spot 執行個體優先於其他類型。

apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: my-cluster managedNodeGroups: - name: managed-ondemand minSize: 1 maxSize: 7 instanceType: m5.xlarge - name: managed-reserved minSize: 2 maxSize: 10 instanceType: c5.2xlarge
apiVersion: v1 kind: ConfigMap metadata: name: cluster-autoscaler-priority-expander namespace: kube-system data: priorities: |- 10: - .*ondemand.* 50: - .*reserved.*

根據預設,使用節點群組可協助基礎運算資源執行預期事項,例如跨AZs分散節點,但並非所有工作負載都有相同的需求或期望,最好讓應用程式明確宣告其需求。如需 Cluster Autoscaler 的詳細資訊,請參閱最佳實務一節

取消排程器

Cluster Autoscaler 可以根據需要排程的新 Pod 或節點使用率不足,從叢集新增和移除節點容量。排程到節點之後,它不會取得 Pod 置放的全清單檢視。如果您使用的是 Cluster Autoscaler,您也應該查看 Kubernetes 取消排程器,以避免浪費叢集中的容量。

如果您在叢集中有 10 個節點,且每個節點使用率為 60%,則表示您未使用叢集中佈建容量的 40%。使用 Cluster Autoscaler,您可以將每個節點的使用率閾值設定為 60%,但只有在使用率降至低於 60% 之後,才會嘗試縮減單一節點。

使用取消排程器,它可以在已排程 Pod 或節點新增至叢集之後查看叢集容量和使用率。它會嘗試將叢集的總容量保持在指定的閾值以上。它也可以根據節點污點或聯結叢集的新節點來移除 Pod,以確保 Pod 在其最佳的運算環境中執行。請注意,取消排程器不會排程取代移出的 Pod,但會依賴預設排程器。

Karpenter 合併

Karpenter 採用「無群組」方法來管理節點。此方法對於不同的工作負載類型更靈活,且叢集管理員需要較少的前期組態。Karpenter 使用佈建器和節點範本來廣泛定義可建立的 EC2 執行個體類型,以及執行個體在建立時的相關設定,而不是根據工作負載的需求預先定義群組和擴展每個群組。

Bin 封裝是將更多工作負載封裝到較少、大小最佳之執行個體上,藉此利用更多執行個體資源的做法。雖然這有助於僅佈建工作負載使用的資源,進而降低運算成本,但其具有權衡性。啟動新的工作負載可能需要更長的時間,因為必須將容量新增至叢集,特別是在大型擴展事件期間。設定 bin 封裝時,請考慮成本最佳化、效能和可用性之間的平衡。

Karpenter 可以持續監控 和 binpack,以改善執行個體資源使用率並降低運算成本。Karpenter 也可以為您的工作負載選擇更具成本效益的工作者節點。這可以透過在佈建器中將「合併」旗標開啟為 true 來實現 (下面的範例程式碼片段)。以下範例顯示啟用整合的範例佈建器。在撰寫本指南時,Karpenter 不會將執行中的 Spot 執行個體取代為價格較低的 Spot 執行個體。如需 Karpenter 整合的更多詳細資訊,請參閱此部落格

apiVersion: karpenter.sh/v1 kind: Provisioner metadata: name: enable-binpacking spec: consolidation: enabled: true

對於可能無法中斷的工作負載,例如在沒有檢查點的情況下長時間執行的批次任務,請考慮使用 do-not-evict註釋註釋 Pod。選擇不移出 Pod,表示您告知 Karpenter 不應自願移除包含此 Pod 的節點。不過,如果在節點耗盡時將 Pod do-not-evict 新增至節點,剩餘的 Pod 仍會移出,但該 Pod 會封鎖終止,直到移除為止。在任何一種情況下,都會封鎖節點,以防止在節點上排程其他工作。以下是示範如何設定註釋的範例:

8"" linenumbering="unnumbered">apiVersion: v1 kind: Pod metadata: name: label-demo labels: environment: production annotations: + "karpenter.sh/do-not-evict": "true" spec: containers: * name: nginx image: nginx ports: ** containerPort: 80

調整 Cluster Autoscaler 參數以移除未充分利用的節點

節點使用率定義為請求的資源總和除以容量。預設為 scale-down-utilization-threshold 50%。此參數可以與 和 搭配使用scale-down-unneeded-time,這決定節點在符合縮減規模的資格之前應該不需要多久,預設值為 10 分鐘。在縮減規模的節點上執行的 Pod 將由 kube-scheduler 排程在其他節點上。調整這些設定有助於移除未充分利用的節點,但請務必先測試這些值,以免強制叢集過早縮減規模。

您可以透過確保昂貴的 Pod 受到 Cluster Autoscaler 辨識的標籤保護,來防止縮減規模。若要執行此作業,請確定移出成本高昂的 Pod 具有註釋 cluster-autoscaler.kubernetes.io/safe-to-evict=false。以下是設定註釋的範例 yaml:

8"" linenumbering="unnumbered">apiVersion: v1 kind: Pod metadata: name: label-demo labels: environment: production annotations: + "cluster-autoscaler.kubernetes.io/safe-to-evict": "false" spec: containers: * name: nginx image: nginx ports: ** containerPort: 80