本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
Karpenter
-
監控 Kubernetes 排程器因為資源限制而無法排程的 Pod。
-
評估不可排程 Pod 的排程需求 (資源請求、節點選擇器、親和性、容錯能力等)。
-
佈建符合這些 Pod 要求的新節點。
-
不再需要節點時,請將其移除。
使用 Karpenter,您可以定義 NodePools,並限制節點佈建,例如污點、標籤、需求 (執行個體類型、區域等),以及佈建資源總數的限制。部署工作負載時,您可以在 Pod 規格中指定各種排程限制,例如資源請求/限制、節點選擇器、節點/Pod 親和性、容錯能力和拓撲分散限制。然後,Karpenter 將根據這些規格佈建大小正確的節點。
使用 Karpenter 的原因
在 Karpenter 推出之前,Kubernetes 使用者主要依賴 Amazon EC2 Auto Scaling 群組和 Kubernetes Cluster Autoscaler
Karpenter 將執行個體協同運作責任合併在單一系統中,這更簡單、更穩定且能感知叢集。Karpenter 旨在透過提供簡化的方式,克服 Cluster Autoscaler 帶來的一些挑戰:
-
根據工作負載需求佈建節點。
-
使用靈活的 NodePool 選項,依執行個體類型建立多樣化的節點組態。Karpenter 可以讓您使用單一、靈活的 NodePool 管理各種工作負載容量,而不是管理許多特定的自訂節點群組。
-
透過快速啟動節點和排程 Pod,大規模實現改善的 Pod 排程。
如需有關使用 Karpenter 的資訊和文件,請造訪 https:// https:// karpenter.sh
建議
最佳實務分為 Karpenter 本身、NodePools 和 Pod 排程的區段。
Karpenter 最佳實務
下列最佳實務涵蓋與 Karpenter 本身相關的主題。
鎖定生產叢集中的 AMIs
強烈建議您鎖定 Karpenter 用於生產叢集的已知 Amazon Machine Image (AMIs)。使用 amiSelector
搭配 別名設為 @latest
,或使用一些其他方法,導致在發佈未測試AMIs 時部署, 會在您的生產叢集中提供工作負載失敗和停機的風險。因此,強烈建議您在非生產叢集中測試較新版本時,鎖定生產叢集的 AMIs 測試工作版本。例如,您可以在 NodeClass 中設定別名,如下所示:
amiSelectorTerms
- alias: al2023@v20240807
如需在 Karpenter 中管理和鎖定 AMIs 的資訊,請參閱 Karpenter 文件中的管理 AMIs
針對容量需求不斷變化的工作負載使用 Karpenter
相較於 Autoscaling Groups
Karpenter 會移除 AWS 抽象層,將一些彈性直接帶入 Kubernetes。Karpenter 最適合用於工作負載遇到高峰值需求或有多樣化運算需求的叢集。MNGs 和 ASGs 適用於執行工作負載的叢集,這些工作負載往往更靜態且一致。您可以根據您的需求,混合使用動態和靜態受管節點。
考慮其他自動擴展專案,當...
您需要仍在 Karpenter 中開發的功能。由於 Karpenter 是相對較新的專案,如果您需要尚未屬於 Karpenter 的功能,請考慮目前其他的自動擴展專案。
在 EKS Fargate 或屬於節點群組的工作者節點上執行 Karpenter 控制器
Karpenter 是使用 【Helm Chart】(https://karpenter.sh/docs/getting-started/getting-started-with-karpenter/#4-install-karpenterkarpenter
命名空間的 Fargate 設定檔,在 EKS Fargate 上執行這些 Pod。這樣做將導致部署到此命名空間的所有 Pod 都能夠在 EKS Fargate 上執行。請勿在由 Karpenter 管理的節點上執行 Karpenter。
Karpenter 不支援自訂啟動範本
v1 APIs 沒有自訂啟動範本支援。您可以使用自訂使用者資料和/或直接在 EC2NodeClass 中指定自訂 AMIs。如需如何執行此操作的詳細資訊,請參閱 NodeClasses
排除不符合工作負載的執行個體類型
如果叢集中執行的工作負載不需要特定執行個體類型,請考慮使用 node.kubernetes.io/instance-type
金鑰來排除這些執行個體類型。
下列範例示範如何避免佈建大型 Graviton 執行個體。
- key: node.kubernetes.io/instance-type
operator: NotIn
values:
- m6g.16xlarge
- m6gd.16xlarge
- r6g.16xlarge
- r6gd.16xlarge
- c6g.16xlarge
使用 Spot 時啟用中斷處理
Karpenter 支援原生中斷處理--interruption-queue
CLI 引數。不建議搭配 Node Termination Handler 使用 Karpenter 中斷處理,如此處
需要檢查點或其他形式正常耗盡的 Pod,在關機前需要 2 分鐘的 Pod,應該會在其叢集中啟用 Karpenter 中斷處理。
沒有傳出網際網路存取的 Amazon EKS 私有叢集
將 EKS 叢集佈建至沒有網際網路路由的 VPC 時,您必須確定已根據 EKS 文件中出現的私有叢集需求來設定環境。此外,您需要確定已在 VPC 中建立 STS VPC 區域端點。如果沒有,您會看到類似以下顯示的錯誤。
{"level":"FATAL","time":"2024-02-29T14:28:34.392Z","logger":"controller","message":"Checking EC2 API connectivity, WebIdentityErr: failed to retrieve credentials\ncaused by: RequestError: send request failed\ncaused by: Post \"https://sts.<region>.amazonaws.com/\": dial tcp 54.239.32.126:443: i/o timeout","commit":"596ea97"}
這些變更在私有叢集中是必要的,因為 Karpenter 控制器使用 IAM Roles for Service Accounts (IRSA)。使用 IRSA 設定的 Pod 會透過呼叫 AWS Security Token Service (AWS STS) API 來取得登入資料。如果沒有傳出網際網路存取,您必須在 VPC 中建立並使用 AWS STS VPC 端點。
私有叢集也需要您為 SSM 建立 VPC 端點。當 Karpenter 嘗試佈建新節點時,它會查詢啟動範本組態和 SSM 參數。如果您的 VPC 中沒有 SSM VPC 端點,則會導致下列錯誤:
{"level":"ERROR","time":"2024-02-29T14:28:12.889Z","logger":"controller","message":"Unable to hydrate the AWS launch template cache, RequestCanceled: request context canceled\ncaused by: context canceled","commit":"596ea97","tag-key":"karpenter.k8s.aws/cluster","tag-value":"eks-workshop"} ... {"level":"ERROR","time":"2024-02-29T15:08:58.869Z","logger":"controller.nodeclass","message":"discovering amis from ssm, getting ssm parameter \"/aws/service/eks/optimized-ami/1.27/amazon-linux-2/recommended/image_id\", RequestError: send request failed\ncaused by: Post \"https://ssm.<region>.amazonaws.com/\": dial tcp 67.220.228.252:443: i/o timeout","commit":"596ea97","ec2nodeclass":"default","query":"/aws/service/eks/optimized-ami/1.27/amazon-linux-2/recommended/image_id"}
價格清單查詢 API 沒有 VPC 端點。因此,定價資料會隨著時間而過時。Karpenter 透過在其二進位中包含隨需定價資料來解決此問題,但只會在 Karpenter 升級時更新該資料。失敗的定價資料請求將導致下列錯誤訊息:
{"level":"ERROR","time":"2024-02-29T15:08:58.522Z","logger":"controller.pricing","message":"retreiving on-demand pricing data, RequestError: send request failed\ncaused by: Post \"https://api.pricing.<region>.amazonaws.com/\": dial tcp 18.196.224.8:443: i/o timeout; RequestError: send request failed\ncaused by: Post \"https://api.pricing.<region>.amazonaws.com/\": dial tcp 18.185.143.117:443: i/o timeout","commit":"596ea97"}
請參閱本文件
建立 NodePools
下列最佳實務涵蓋與建立 NodePools 相關的主題。
建立多個 NodePools 時...
當不同的團隊共用叢集,且需要在不同的工作者節點上執行工作負載,或具有不同的作業系統或執行個體類型需求時,請建立多個 NodePools 例如,一個團隊可能想要使用 Bottlerocket,而另一個團隊可能想要使用 Amazon Linux。同樣地,一個團隊可能可以存取另一個團隊不需要的昂貴 GPU 硬體。使用多個 NodePools 可確保每個團隊都能使用最適當的資產。
建立互斥或加權NodePools
建議建立互斥或加權的 NodePools以提供一致的排程行為。如果它們不是 ,且多個 NodePools 相符,Karpenter 會隨機選擇要使用的節點Pools,從而導致非預期的結果。建立多個 NodePools的實用範例包括:
使用 GPU 建立 NodePool,且僅允許在這些 (昂貴) 節點上執行特殊工作負載:
# NodePool for GPU Instances with Taints
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: gpu
spec:
disruption:
consolidateAfter: 1m
consolidationPolicy: WhenEmptyOrUnderutilized
template:
metadata: {}
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
expireAfter: Never
requirements:
- key: node.kubernetes.io/instance-type
operator: In
values:
- p3.8xlarge
- p3.16xlarge
- key: kubernetes.io/os
operator: In
values:
- linux
- key: kubernetes.io/arch
operator: In
values:
- amd64
- key: karpenter.sh/capacity-type
operator: In
values:
- on-demand
taints:
- effect: NoSchedule
key: nvidia.com/gpu
value: "true"
具有污點容錯能力的部署:
# Deployment of GPU Workload will have tolerations defined
apiVersion: apps/v1
kind: Deployment
metadata:
name: inflate-gpu
spec:
spec:
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
對於另一個團隊的一般部署,NodePool 規格可能包含 nodeAffinity。然後,部署可以使用 nodeSelectorTerms 來比對 billing-team
。
# NodePool for regular EC2 instances
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: generalcompute
spec:
template:
metadata:
labels:
billing-team: my-team
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
expireAfter: Never
requirements:
- key: node.kubernetes.io/instance-type
operator: In
values:
- m5.large
- m5.xlarge
- m5.2xlarge
- c5.large
- c5.xlarge
- c5a.large
- c5a.xlarge
- r5.large
- r5.xlarge
- key: kubernetes.io/os
operator: In
values:
- linux
- key: kubernetes.io/arch
operator: In
values:
- amd64
- key: karpenter.sh/capacity-type
operator: In
values:
- on-demand
使用 nodeAffinity 部署:
# Deployment will have spec.affinity.nodeAffinity defined
kind: Deployment
metadata:
name: workload-my-team
spec:
replicas: 200
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: "billing-team"
operator: "In"
values: ["my-team"]
使用計時器 (TTL) 從叢集自動刪除節點
您可以在已佈建節點上使用計時器來設定何時刪除沒有工作負載 Pod 或已達到過期時間的節點。節點過期可用作升級方式,以便淘汰節點並以更新版本取代。如需使用 spec.template.spec
設定節點過期
避免過度限制 Karpenter 可以佈建的執行個體類型,尤其是在使用 Spot 時
使用 Spot 時,Karpenter 會使用 Price Capacity Optimized 配置策略來佈建 EC2 執行個體。此策略會指示 EC2 從最深的集區佈建執行個體,以取得您啟動的執行個體數量,且中斷風險最低。EC2 機群接著會從這些集區的最低價格請求 Spot 執行個體。您允許 Karpenter 利用的執行個體類型越多,EC2 就越能最佳化 Spot 執行個體的執行時間。根據預設,Karpenter 將使用叢集部署所在區域和可用區域中的所有執行個體類型 EC2 優惠。Karpenter 會根據待定 Pod 以智慧方式從所有執行個體類型中選擇,以確保您的 Pod 已排程在適當大小且配備的執行個體上。例如,如果您的 Pod 不需要 GPU,Karpenter 不會將您的 Pod 排程到支援 GPU 的 EC2 執行個體類型。當您不確定要使用的執行個體類型時,可以執行 Amazon ec2-instance-selector
$ ec2-instance-selector --memory 4 --vcpus 2 --cpu-architecture x86_64 -r ap-southeast-1
c5.large
c5a.large
c5ad.large
c5d.large
c6i.large
t2.medium
t3.medium
t3a.medium
使用 Spot 執行個體時,您不應該對 Karpenter 設定太多限制,因為這樣做可能會影響應用程式的可用性。例如,假設回收特定類型的所有執行個體,而且沒有可用的替代選項可以取代它們。您的 Pod 將保持待定狀態,直到已設定執行個體類型的 Spot 容量補充為止。您可以將執行個體分散到不同的可用區域,以減少容量不足錯誤的風險,因為 Spot 集區在 AZs 之間不同。也就是說,一般最佳實務是允許 Karpenter 在使用 Spot 時使用一組不同的執行個體類型。
排程 Pod
下列最佳實務與使用 Karpenter 在叢集中部署 Pod 進行節點佈建相關。
遵循 EKS 最佳實務以獲得高可用性
如果您需要執行高可用性應用程式,請遵循一般 EKS 最佳實務建議
使用分層限制條件來限制雲端供應商提供的運算功能
Karpenter 的分層限制模型可讓您建立一組複雜的 NodePool 和 Pod 部署限制,以取得 Pod 排程的最佳可能相符項目。Pod 規格可以請求的限制範例包括:
建立帳單警示以監控您的運算支出
當您將叢集設定為自動擴展時,您應該建立帳單警示,在支出超過閾值時警告您,並將資源限制新增至 Karpenter 組態。使用 Karpenter 設定資源限制類似於設定 AWS Autoscaling 群組的最大容量,因為它代表 Karpenter NodePool 可執行個體化的運算資源數量上限。
注意
無法設定整個叢集的全域限制。限制適用於特定 NodePools。
以下程式碼片段會告知 Karpenter 最多只能佈建 1000 個 CPU 核心和 1000Gi 記憶體。只有在達到或超過限制時,Karpenter 才會停止新增容量。超過限制時,Karpenter 控制器會將 memory resource usage of 1001 exceeds limit of 1000
或類似的注視訊息寫入控制器的日誌。如果您要將容器日誌路由到 CloudWatch 日誌,您可以建立指標篩選條件來尋找日誌中的特定模式或詞彙,然後建立 CloudWatch 警示,以便在您設定的指標閾值違反時提醒您。
如需使用限制搭配 Karpenter 的詳細資訊,請參閱 Karpenter 文件中的設定資源限制
spec:
limits:
cpu: 1000
memory: 1000Gi
如果您未使用限制或限制 Karpenter 可以佈建的執行個體類型,Karpenter 會視需要繼續將運算容量新增至您的叢集。雖然以這種方式設定 Karpenter 可讓您的叢集自由擴展,但它也可能具有重大的成本影響。因此,我們建議您設定帳單警示。帳單警示可讓您在帳戶中計算的預估費用超過定義的閾值時收到提醒並主動通知您 (這些費用)。如需詳細資訊,請參閱設定 Amazon CloudWatch 帳單警示以主動監控預估費用
您可能也想要啟用成本異常偵測,這是一種 AWS 成本管理功能,使用機器學習持續監控您的成本和用量,以偵測不尋常的支出。如需詳細資訊,請參閱 AWS 成本異常偵測入門指南。如果您已經在 AWS Budgets 中建立預算,您也可以設定 動作,以便在超過特定閾值時通知您。透過預算動作,您可以傳送電子郵件、將訊息發佈至 SNS 主題,或將訊息傳送至 Slack 之類的聊天機器人。如需詳細資訊,請參閱設定 AWS Budgets 動作。
使用 karpenter.sh/do-not-disrupt 註釋來防止 Karpenter 取消佈建節點
如果您在 Karpenter 佈建的節點上執行關鍵應用程式,例如長時間執行的批次任務或具狀態應用程式,且節點的 TTL 已過期,則執行個體終止時,應用程式將會中斷。透過將karpenter.sh/do-not-disrupt
註釋新增至 Pod,您可以指示 Karpenter 保留節點,直到 Pod 終止或移除karpenter.sh/do-not-disrupt
註釋為止。如需詳細資訊,請參閱中斷
如果節點上唯一留下的非協助程式集 Pod 是與任務相關聯的 Pod,只要任務狀態成功或失敗,Karpenter 就能夠鎖定和終止這些節點。
使用整合時,設定所有非 CPU 資源的 request=limits
透過比較 Pod 資源請求與節點上可配置資源的數量,進行一般性的合併和排程。不會考慮資源限制。例如,記憶體限制大於記憶體請求的 Pod 可能會爆量超過請求。如果同一節點上的多個 Pod 同時爆量,這可能會導致某些 Pod 因記憶體不足 (OOM) 條件而終止。合併可能會使這種情況更可能發生,因為它可以只考慮其請求,將 Pod 封裝到節點上。
使用 LimitRanges 設定資源請求和限制的預設值
由於 Kubernetes 不會設定預設請求或限制,因此容器對基礎主機、CPU 和記憶體資源的耗用不受限制。Kubernetes 排程器會查看 Pod 的請求總數 (Pod 容器的請求總數或 Pod Init 容器的資源總數較高),以決定要排程 Pod 的工作者節點。同樣地,Karpenter 會考慮 Pod 的請求,以判斷其佈建的執行個體類型。您可以使用限制範圍來套用命名空間的合理預設值,以防某些 Pod 未指定資源請求。
將準確的資源請求套用至所有工作負載
當 Karpenter 的工作負載需求相關資訊準確無誤時,其能夠啟動最適合您工作負載的節點。如果使用 Karpenter 的合併功能,這尤其重要。
CoreDNS 建議
更新 CoreDNS 的組態以維護可靠性
在 Karpenter 管理的節點上部署 CoreDNS Pod 時,考慮到 Karpenter 在快速終止/建立新節點以符合需求的動態本質,建議遵循下列最佳實務:
這將確保 DNS 查詢不會導向尚未就緒或已終止的 CoreDNS Pod。
Karpenter 藍圖
由於 Karpenter 採取應用程式優先的方法,將 的運算容量佈建至 Kubernetes 資料平面,因此您可能想知道如何正確設定它們。Karpenter 藍圖