大数跨境

Karpenter + Spot 加持,助力 AKS 成本降低 80%

Karpenter + Spot 加持,助力 AKS 成本降低 80% Karpenter
2025-03-12
2

 

作者|Osama Sheikh

编译|CloudPilot AI

原文链接:

https://techcommunity.microsoft.com/blog/appsonazureblog/karpenter-run-your-workloads-upto-80-off-using-spot-with-aks/4148840

引言

在 2023 年的 KubeCon 北美大会上,微软宣布在 Azure Kubernetes Service(AKS) 中引入 Karpenter 作为 Cluster Autoscaler(CA)的替代方案,并将其命名为 Node Autoprovisioning(NAP)。

虽然 Cluster Autoscaler 一直以来是 AKS/Kubernetes 的默认节点扩缩工具,但其存在诸多限制,促使微软引入 Karpenter。

本文将深入探讨这些挑战,并介绍 Karpenter 如何有效解决它们。

CA vs Karpenter

太长不看版

如果你想了解这几款工具的更多技术细节、查看 Karpenter 与 Cluster Autoscaler 的架构差异,点击下方卡片,在公众号对话框回复关键词【对比】,获取完整版 PDF 文件。

Cluster Autoscaler 的局限性

以下是 Cluster Autoscaler 进行节点自动扩缩的流程示意图:

1. 受限于虚拟机规模集( VMSS Groups ):

Cluster Autoscaler 仅支持 AKS 中的虚拟机规模集。

每个 VMSS 由特定类型的 VM 实例组成,具有固定的 VM SKU、硬件规格和 CPU:内存比(例如 Standard D4sv5,4 vCPU 和 16GB 内存)。

2. 节点池约束:

当新 Pod 需要部署但当前节点容量已满时,Cluster Autoscaler 会尝试创建新的节点,但只能基于现有 VMSS SKU 进行扩容。如果该类型的实例不可用,Pod 将保持待调度状态。

3. 扩缩能力受限:

Cluster Autoscaler 仅能基于指定的 VMSS 进行弹性扩缩,即使其他虚拟机 SKU 有闲置资源,也无法利用这些 VM SKU 的剩余容量。

Karpenter的优势

Karpenter 是一款开源的 Kubernetes 集群自动扩缩工具,专为优化性能和成本而设计,旨在以灵活、高性能和简洁的方式实现节点的弹性扩展。它比 Cluster Autoscaler 的扩缩速度更快,并且能够直接创建独立节点,无需传统的节点组限制。

Karpenter 的核心特性:

高效扩缩:快速弹性扩展 Kubernetes 节点。

灵活调度:无需依赖 VMSS 也能启动新节点。

成本优化:支持自动补丁更新和 Kubernetes 版本升级,降低总体成本。

✅基于 YAML 配置的 NodePool,可自定义节点类型及调度策略。

Karpenter 的中断管理

中断控制器 (Disruption Controller)负责在 Kubernetes 集群中终止或替换节点,并采用以下三种策略来决定如何处理节点:

1. 节点到期

Karpenter 会为节点设置存活时间(TTL),到期后进行替换。例如:

spec:  disruption:    consolidationPolicy: WhenUnderutilized    expireAfter: 300s  #

2. 延迟合并

设置中断间隔,控制在触发中断操作前等待的时间。

3. 资源整合

Karpenter 通过分析节点资源使用情况来主动减少集群成本。

📌 支持的策略模式:

  • • 无工作负载时:仅移除无 Pod 运行的节点。

  • • 资源利用不足时:当节点资源利用率低时,尝试减少或替换节点。

示例:

apiVersion: karpenter.sh/v1beta1kind: NodePoolmetadata:  name: ondemandspec:  disruption:    consolidationPolicy: WhenEmpty    consolidateAfter: 60s

在 AKS 上启用 Karpenter

启用 Karpenter 之前,需要满足以下前置条件:

✅ 安装 Az CLI 并更新至 0.5.17 以上版本

✅ 注册 NAP 预览功能

✅ AKS 需使用 Cilium + Overlay 作为网络配置

在现有 AKS 集群上启用 Karpenter

确保 AKS 集群启用了 Azure 网络插件,并使用 Cilium 作为网络策略。

关键参数:--node-provisioning-mode Auto,用于将 Karpenter 设为默认节点扩缩工具。

az aks update --name <aks-cluster-name> --resource-group <rg-name> --node-provisioning-mode Auto

创建新的 AKS 集群并启用 Karpenter

az aks create --name <aks-cluster-name> --resource-group <rg-name> \  --node-provisioning-mode Auto --network-plugin azure --network-plugin-mode overlay --network-dataplane cilium

验证 Karpenter 是否已启用

kubectl api-resources | grep -e aksnodeclasses -e nodeclaims -e nodepools

返回结果示例:

aksnodeclasses      aksnc,aksncs      karpenter.azure.com/v1alpha2      false      AKSNodeClassnodeclaims                               karpenter.sh/v1beta1             false      NodeClaimnodepools                                karpenter.sh/v1beta1             false      NodePool

禁用 Cluster Autoscaler

如果希望从 Cluster Autoscaler 切换到 Karpenter,首先需要在 AKS 集群上禁用 Cluster Autoscaler:

az aks update --name <aks-cluster-name> --resource-group <rg-name> --disable-cluster-autoscaler

部署示例应用

为了观察节点自动扩缩的实际运行情况,可以部署一个示例应用:

osama [ ~ ]$ kubectl get nodesNAME                                STATUS   ROLES   AGE     VERSIONaks-default-h2jxh                   Ready    agent   35m     v1.27.9aks-nodepool1-41633911-vmss000000   Ready    agent   3d19h   v1.27.9

调整 Vote 应用副本数量以触发扩容事件

osama [ ~ ]$ kubectl scale deployment azure-vote-front --replicas=12 -n karpenter-demo-ns^[[Adeployment.apps/azure-vote-front scaledosama [ ~ ]$ kubectl scale deployment azure-vote-back --replicas=12 -n karpenter-demo-nsdeployment.apps/azure-vote-back scaled

使用以下 kubectl 命令检查 Karpenter 自动扩容情况

kubectl get events -A --field-selector source=karpenter --sort-by='.lastTimestamp' -n 10NAMESPACE           LAST SEEN   TYPE     REASON                  OBJECT                                  MESSAGEdefault             50m         Normal   Unconsolidatable        nodeclaim/default-95f54                 SpotToSpotConsolidation is disabled, can't replace a spot node with a spot nodedefault             50m         Normal   Unconsolidatable        node/aks-default-95f54                  SpotToSpotConsolidation is disabled, can't replace a spot node with a spot nodedefault             38m         Normal   DisruptionBlocked       nodepool/default                        No allowed disruptions due to blocking budgetdefault             5m33s       Normal   Unconsolidatable        nodeclaim/default-h2jxh                 Can't remove without creating 2 candidatesdefault             5m33s       Normal   Unconsolidatable        node/aks-default-h2jxh                  Can't remove without creating 2 candidatesdefault             2m12s       Normal   DisruptionBlocked       nodepool/system-surge                   No allowed disruptions due to blocking budgetkarpenter-demo-ns   63s         Normal   Nominated               pod/azure-vote-front-6855444955-bnq7p   Pod should schedule on: nodeclaim/default-mrh7wkarpenter-demo-ns   63s         Normal   Nominated               pod/azure-vote-front-6855444955-gbwk6   Pod should schedule on: nodeclaim/default-mrh7wkarpenter-demo-ns   63s         Normal   Nominated               pod/azure-vote-front-6855444955-l2bgj   Pod should schedule on: nodeclaim/default-mrh7wkarpenter-demo-ns   63s         Normal   Nominated               pod/azure-vote-front-6855444955-nvc56   Pod should schedule on: nodeclaim/default-mrh7wkarpenter-demo-ns   63s         Normal   Nominated               pod/azure-vote-front-6855444955-22glj   Pod should schedule on: nodeclaim/default-mrh7wkarpenter-demo-ns   63s         Normal   Nominated               pod/azure-vote-front-6855444955-sxdl6   Pod should schedule on: nodeclaim/default-mrh7wkarpenter-demo-ns   63s         Normal   Nominated               pod/azure-vote-front-6855444955-t69w4   Pod should schedule on: nodeclaim/default-mrh7w

自定义 Karpenter 配置

Karpenter 在 Kubernetes 中引入了一种新的资源类型:NodePool,用于管理和优化节点调度。

  • • 自定义 NodePools:指定特定的 VM 系列、VM 家族,或自定义 CPU 与内存比例。

  • • 基于特性选择节点:支持 GPU 加速或网络加速等功能。

  • • 定义 CPU 架构:根据特定工作负载需求,选择 ARM 或 AMD 架构。

  • • 构建高可用节点架构:通过配置可用区拓扑提高容灾能力。

  • • 限制节点级别的 CPU 和内存使用:控制单个节点可分配的 CPU 和内存资源。

以下是 Karpenter 默认的 NodePool 配置 YAML,其中包含:

  • • 节点 SKU 类型和容量配置

  • • CPU:内存比例限制

  • • 在多个 NodePools 存在时的调度权重(Weight)

apiVersion: karpenter.sh/v1beta1kind: NodePoolmetadata:  name: defaultspec:  disruption:    consolidationPolicy: WhenUnderutilized    expireAfter: 10s  template:    spec:      nodeClassRef:        name: default
# Requirements that constrain the parameters of provisioned nodes. # These requirements are combined with pod.spec.affinity.nodeAffinity rules. # Operators { In, NotIn, Exists, DoesNotExist, Gt, and Lt } are supported. # https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#operators requirements: - key: kubernetes.io/arch operator: In values: - amd64 - key: kubernetes.io/os operator: In values: - linux - key: karpenter.sh/capacity-type operator: In values: - ondemand - key: karpenter.azure.com/sku-family operator: In values: - E - D - key: karpenter.azure.com/sku-name operator: In values: - Standard_E2s_v5 - Standard_D4s_v3limits: cpu: "1000" memory: 1000Giweight: 100

使用 Spot 节点与 Karpenter

  • • 在 AKS-Vote 示例应用中添加 Toleration(如 "karpenter.sh/disruption:NoSchedule"),该 Toleration 在 AKS 集群预配 Spot 节点时默认存在。

  • • 请参考我的 GitHub 仓库,获取应用的 YAML 配置和示例 NodePool 配置。(https://github.com/Osshaikh/Karpenter-AKS-Spot)

spec:      nodeSelector:        "kubernetes.io/os": linux      tolerations:      - key: "kubernetes.azure.com/scalesetpriority"        operator: "Equal"        value: "spot"        effect: "NoSchedule"      containers:      - name: azure-vote-front        image: mcr.microsoft.com/azuredocs/azure-vote-front:v1        
  • • 缩减应用副本数量,以便 Karpenter 逐步驱逐现有的 On-Demand 节点,并用 Spot 节点替换:

osama [ ~/karpenter ]$ kubectl get nodesNAME                                STATUS   ROLES   AGE     VERSIONaks-nodepool1-41633911-vmss000000   Ready    agent   3d21h   v1.27.9aks-nodepool1-41633911-vmss00000b   Ready    agent   24m     v1.27.9
osama [ ~/karpenter ]$ kubectl get pods -n karpenter-demo-ns -o wideNo resources found in karpenter-demo-ns namespace.
osama [ ~/karpenter ]$ kubectl scale deployment azure-vote-back --replicas=10 -n karpenter-demo-nsdeployment.apps/azure-vote-back scaledosama [ ~/karpenter ]$ kubectl scale deployment azure-vote-front --replicas=10 -n karpenter-demo-nsdeployment.apps/azure-vote-front scaledosama [ ~/karpenter ]$
  • • 部署并扩展 Vote 应用副本,使 Karpenter 根据 NodePool 配置启动 Spot 节点,并在 Toleration 验证后将 Pod 调度到 Spot 节点上。

  • • Karpenter 启动新的 Spot 节点,并将该节点指定用于调度 Vote 示例应用。

osama [ ~/karpenter ]$ kubectl get events -A --field-selector source=karpenter --sort-by='.lastTimestamp'NAMESPACE           LAST SEEN   TYPE      REASON                       OBJECT                                    MESSAGEkarpenter-demo-ns   104s        Normal    Nominated                    pod/azure-vote-back-687ddb67bd-pz8sp      Pod should schedule on: nodeclaim/default-52gbgkarpenter-demo-ns   104s        Normal    Nominated                    pod/azure-vote-back-687ddb67bd-ckdcq      Pod should schedule on: nodeclaim/default-52gbgkarpenter-demo-ns   104s        Normal    Nominated                    pod/azure-vote-back-687ddb67bd-v9nqj      Pod should schedule on: nodeclaim/default-52gbgkarpenter-demo-ns   104s        Normal    Nominated                    pod/azure-vote-back-687ddb67bd-vswvs      Pod should schedule on: nodeclaim/default-52gbgkarpenter-demo-ns   104s        Normal    Nominated                    pod/azure-vote-back-687ddb67bd-lnxmp      Pod should schedule on: nodeclaim/default-52gbgkarpenter-demo-ns   104s        Normal    Nominated                    pod/azure-vote-back-687ddb67bd-jc2jz      Pod should schedule on: nodeclaim/default-52gbgkarpenter-demo-ns   104s        Normal    Nominated                    pod/azure-vote-back-687ddb67bd-hwnbh      Pod should schedule on: nodeclaim/default-52gbgkarpenter-demo-ns   104s        Normal    Nominated                    pod/azure-vote-back-687ddb67bd-r7msb      Pod should schedule on: nodeclaim/default-52gbgkarpenter-demo-ns   104s        Normal    Nominated                    pod/azure-vote-back-687ddb67bd-96lm9      Pod should schedule on: nodeclaim/default-52gbgkarpenter-demo-ns   104s        Normal    Nominated                    pod/azure-vote-back-687ddb67bd-5qcvk      Pod should schedule on: nodeclaim/default-52gbgdefault             1s          Normal    DisruptionLaunching          nodeclaim/default-bkz6c                   Launching NodeClaim: Expiration/Replacedefault             1s          Normal    DisruptionWaitingReadiness   nodeclaim/default-bkz6c                   Waiting on readiness to continue disruptiondefault             1s          Normal    DisruptionBlocked            nodepool/system-surge                     No allowed disruptions due to blocking budgetdefault             1s          Normal    DisruptionWaitingReadiness   nodeclaim/default-5vp7x                   Waiting on readiness to continue disruptiondefault             1s          Normal    DisruptionLaunching          nodeclaim/default-5vp7x                   Launching NodeClaim: Expiration/Replace

配置多个NodePools

  • • 为 Spot 和 On-Demand 资源分别配置 NodePool:
    使用 E 系列 VM(如 "Standard_E2s_v5")的 Spot 节点和使用 D 系列 VM(如 "Standard_D4s_v5")的 On-Demand 节点。

  • • 设置 NodePool 的优先级
    在多 NodePool 场景中,每个 NodePool 需要配置 Weight 属性,Karpenter 会优先选择权重最高的 NodePool 进行调度。
    📌 在此配置中,Spot 节点的权重为 100,On-Demand 节点的权重为 60:

osama [ ~ ]$ kubectl get nodepool default -o yamlapiVersion: karpenter.sh/v1beta1kind: NodePoolmetadata:  name: defaultspec:  disruption:    budgets:    - nodes: 100%    consolidationPolicy: WhenUnderutilized    expireAfter: 720h  template:    spec:      nodeClassRef:        name: default      requirements:      - key: kubernetes.io/arch        operator: In        values:        - amd64      - key: kubernetes.io/os        operator: In        values:        - linux      - key: karpenter.sh/capacity-type        operator: In        values:        - spot      - key: karpenter.azure.com/sku-family        operator: In        values:        - B      - key: karpenter.azure.com/sku-name        operator: In        values:        - Standard_B2s_v2  weight: 100
  • • 如果未指定具体的 SKU 名称,Karpenter 将默认考虑整个 VM 系列。

  • • 要验证示例 VoteApp 是否运行在 Spot 节点上,请使用以下命令:

  • • 输出结果应显示节点的容量类型为 "spot":

osama [ ~ ]$ kubectl get pods -n karpenter-demo-ns -o wideNAME                                READY   STATUS    RESTARTS   AGE   IP             NODE                NOMINATED NODE   READINESS GATESazure-vote-back-687ddb67bd-w7ghm    1/1     Running   0          63m   10.244.3.11    aks-default-5cr5f   <none>           <none>azure-vote-front-6855444955-64558   1/1     Running   0          63m   10.244.3.168   aks-default-5cr5f   <none>           <none>osama [ ~ ]$ kubectl describe node aks-default-5cr5f | grep karpenter.sh                    karpenter.sh/capacity-type=spot                    karpenter.sh/initialized=true                    karpenter.sh/nodepool=default                    karpenter.sh/registered=true                    karpenter.sh/nodepool-hash: 12393960163388511505                    karpenter.sh/nodepool-hash-version: v2

模拟 Spot 节点驱逐

要测试 Spot 节点的驱逐情况,可以使用 Azure CLI 模拟 Spot 节点被回收:

osama [ ~ ]$ az vm simulate-eviction --resource-group MC_aks-lab_aks-karpenter_eastus --name aks-default-5cr5fosama [ ~ ]$ dateTue May 21 06:20:02 PM IST 2024
  • • 使用以下 curl 命令监控 VoteApp 的可用性:

while true; do echo "$(date) $(curl -s -v -o /dev/null -w 'HTTP %{http_code}\n' http://voteapp.com 2>&1 | grep 'HTTP')"; sleep 2; done
  • • 在运行 Spot 模拟驱逐后,现有节点将被标记为终止,Karpenter 将自动创建新的 Spot 节点来调度 VoteApp 的 Pods。在不到一分钟内,VoteApp 应该会恢复运行,并开始返回 HTTP 200 状态码。

 root@MININT-8C81HDE:/home/osamaex while true; do echo "$(date) $(curl -s -v -o /dev/null -w 'HTTP %{http_code}\n' http://voteapp.com 2>&1 | grep 'HTTP')"; sleep 2; done    Tue May 21 18:20:04 IST 2024 > GET / HTTP/1.1    < HTTP/1.1 200 OK    HTTP 200    Tue May 21 18:20:07 IST 2024 > GET / HTTP/1.1    < HTTP/1.1 200 OK    HTTP 200    Tue May 21 18:20:09 IST 2024 > GET / HTTP/1.1    < HTTP/1.1 200 OK    HTTP 200    Tue May 21 18:20:12 IST 2024 HTTP 000  $Failure-Alert    Tue May 21 18:21:14 IST 2024 > GET / HTTP/1.1    < HTTP/1.1 200 OK                      $Successful-Response    HTTP 200    Tue May 21 18:22:58 IST 2024 > GET / HTTP/1.1    < HTTP/1.1 200 OK    HTTP 200
  • • 查看 Karpenter 记录的事件日志:

       kubectl get events -A --field-selector source=karpenter --sort-by='.lastTimestamp'
  • • Karpenter 记录的事件日志显示 Spot 节点被替换为 On-Demand 节点的过程:

osama [ ~ ]$     NAMESPACE           LAST SEEN   TYPE      REASON           OBJECT                                  MESSAGE    default             23s         Warning   FailedDraining   node/aks-default-5cr5f                  Failed to drain node, 10 pods are waiting to be evicted    karpenter-demo-ns   22s         Normal    Evicted          pod/azure-vote-back-687ddb67bd-w7ghm    Evicted pod    karpenter-demo-ns   22s         Normal    Evicted          pod/azure-vote-front-6855444955-64558   Evicted pod    karpenter-demo-ns   21s         Normal    Nominated        pod/azure-vote-back-687ddb67bd-tb2pv    Pod should schedule on: nodeclaim/default-6zkkl    karpenter-demo-ns   21s         Normal    Nominated        pod/azure-vote-front-6855444955-7wzss   Pod should schedule on: nodeclaim/default-6zkkl
  • • 验证 Pods 是否已运行在新的 Spot 节点上:

kubectl get pods -n karpenter-demo-ns -o wideNAME                                READY   STATUS    RESTARTS   AGE   IP             NODE                NOMINATED NODE   READINESS GATESazure-vote-back-687ddb67bd-tb2pv    1/1     Running   0          18m   10.244.2.103   aks-default-6zkkl   <none>           <none>azure-vote-front-6855444955-7wzss   1/1     Running   0          18m   10.244.2.47    aks-default-6zkkl   <none>           <none>

通过使用预留实例节省成本

NodePool 配置允许您指定不同的 VM 系列以及多个 VM SKU。

您可以创建一个独立的 NodePool,设置最高权重,并通过karpenter.azure.com/sku-name或 karpenter.azure.com/sku-family 参数,指定所有预留实例的 VM SKU 家族或具体 SKU 名称。

spec:      nodeClassRef:        name: default      requirements:      - key: kubernetes.io/arch        operator: In        values:        - amd64      - key: kubernetes.io/os        operator: In        values:        - linux      - key: karpenter.sh/capacity-type        operator: In        values:        - on-demand      - key: karpenter.azure.com/sku-family        operator: In        values:        - D      - key: karpenter.azure.com/sku-name        operator: In        values:        - [Standard_D2s_v3, Standard_D4s_v3, Standard_D8s_v3, Standard_D16s_v3, Standard_D32s_v3, Standard_D64s_v3, Standard_D96s_v3]  weight: 90

结论

在 AKS 引入 Karpenter 标志着节点扩缩效率、灵活性和成本优化方面的一次重大升级。

Karpenter 克服了 Cluster Autoscaler 的局限性,引入了动态且快速的节点预置能力,为 Kubernetes 集群管理提供了更强大、更高效的解决方案。

Karpenter 在支持不同 VM 类型、提高扩缩能力以及优化成本方面展现出了极大的灵活性,使其成为 Kubernetes 集群管理的重要利器。

通过 Karpenter,企业可以实现更敏捷、更具成本效益的 Kubernetes 部署,提升集群的响应速度和资源利用率。

如果你正在寻找 Karpenter 的相关实践教程,点击下方卡片关注「 Karpenter 」,我们将持续带来更多干货💡

推荐阅读

劲省85%云成本!在K8s上使用Karpenter私有部署DeepSeek-R1

Prometheus v2.47+Karpenter:轻松月省4万云成本

一文消除大数据处理的资源浪费,实现 90% 成本降低

项目介绍

Karpenter 于2021年11月推出并开源,是一款开源的Kubernetes集群自动扩缩容工具,专为优化 Kubernetes 集群的工作负载设计,旨在以灵活、高性能和简洁的方式实现节点的弹性扩展。今年9月已发布1.0版本。目前,Karpenter 已为全球超500家知名企业在生产环境中提供服务,包括阿迪达斯、Anthropic、Slack、Figma等。

Karpenter项目地址:
https://github.com/kubernetes-sigs/karpenter


 


【声明】内容源于网络
0
0
Karpenter
Karpenter is a Kubernetes Node Autoscaler built for flexibility, performance, and simplicity.
内容 51
粉丝 0
Karpenter Karpenter is a Kubernetes Node Autoscaler built for flexibility, performance, and simplicity.
总阅读49
粉丝0
内容51