Karpenter 实战:用开源节点自动伸缩器优化 Kubernetes 成本与弹性

当 Kubernetes 集群的流量像潮汐一样起伏时,手动加节点既慢又贵。Karpenter 是 AWS 开源、现由 CNCF 托管的 Kubernetes 节点自动伸缩器,它能直接观察 Pending Pod 的需求,绕过传统节点组,即时供应最合适规格的节点,让集群弹性伸缩真正”刚刚好”,同时大幅压低云成本。

一、传统 Cluster Autoscaler 的痛点

在 Karpenter 之前,绝大多数团队用 Cluster Autoscaler(CA)。它的核心思路是”节点组驱动”:你必须预先在云厂商侧建好 Auto Scaling Group(ASG)或托管实例组,CA 检测到 Pending Pod 后,再去扩对应的节点组。这种机制有三个绕不开的短板。

  • 粒度粗:扩容的最小单位是一个节点组,里面机型是固定模板,无法为不同工作负载挑不同机型。
  • 扩容慢:要经过”节点组扩容 → 新实例启动 → 注册到集群”多步,冷启动常常要几分钟。
  • 装箱率低:CA 不了解 Pod 真实的资源形状,经常出现”大节点上只放一个小 Pod”的浪费。

Karpenter 的思路完全不同:它直接读取调度器标记的 unschedulable Pod,计算资源需求,调用云 API 即时起一个”刚好够用”的节点(JIT Provisioning),节点就绪后立刻绑定,闲置时再自动回收整合。想深入 Kubernetes 基础可以先看我们的 Kubernetes 入门实战。

二、Karpenter 工作原理

Karpenter v1 由控制器 + 一组 CRD 组成,核心是 NodePool 与 NodeClaim。其闭环大致如下:

  1. 调度器发现无法放置的 Pod,打上 karpenter.sh/unschedulable 标记;
  2. Karpenter 的调度器插件读取这些 Pod 的资源请求、亲和性、污点容忍;
  3. 根据 NodePool 里定义的机型约束,挑出成本最优或延迟最优的实例规格;
  4. 调用云厂商 API 起节点,节点启动后自动加标签并加入集群;
  5. 持续做 consolidation(整合):当若干节点可被更少的节点容纳时,优雅驱逐并回收空节点。

这意味着你不再需要为每种 workload 维护一个节点组,Karpenter 自己会”算账”。

三、快速部署:Helm 安装

以 AWS EKS 为例,先添加仓库并安装。注意控制面需要能调用 EC2 的权限(通过 IAM Roles for Service Accounts 注入),并给节点打上默认污点,避免系统组件被调度到临时节点上。

# 添加并安装 Karpenter(v1 版本)
helm repo add karpenter https://charts.karpenter.sh
helm repo update

helm upgrade --install karpenter karpenter/karpenter \
  --namespace karpenter --create-namespace \
  --set settings.clusterName=my-eks-cluster \
  --set settings.clusterEndpoint=$(aws eks describe-cluster \
      --name my-eks-cluster --query status.endpoint --output text) \
  --set controller.resources.requests.cpu=1 \
  --set controller.resources.requests.memory=1Gi \
  --wait

部署完成后,用 kubectl get pods -n karpenter 确认控制器处于 Running。若你用的是轻量集群,可参考我们 k3s 轻量级 Kubernetes 实战 的思路先搭好底座。

四、配置 NodePool:定义节点的”游戏规则”

NodePool 取代了旧版 Provisioner,用来声明”允许起哪些节点”。下面这份配置允许 Karpenter 在按需与 Spot 之间自由选择 AMD/ARM 实例,并设置了 30 天过期轮换与资源上限。

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
    metadata:
      labels:
        karpenter.sh/capacity-type: spot-or-ondemand
    spec:
      taints:
        - key: karpenter.sh/uncordoned
          effect: NoSchedule
      requirements:
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64", "arm64"]
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["c", "m", "r"]
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: ["5"]
  limits:
    cpu: "1000"
    memory: 1000Gi
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    expireAfter: 720h

其中 capacity-type 同时允许 spot 与 on-demand,是降本的关键开关;expireAfter 让节点定期滚动,避免长期运行的”配置漂移”。

五、实战:让工作负载自动触发扩缩容

写一个带明确资源请求的 Deployment,再把它放大,就能直观看到 Karpenter 起节点。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: load-demo
spec:
  replicas: 1
  selector:
    matchLabels: { app: load-demo }
  template:
    metadata:
      labels: { app: load-demo }
    spec:
      containers:
        - name: app
          image: nginx:1.27
          resources:
            requests: { cpu: "1", memory: 1Gi }
            limits:   { cpu: "1", memory: 1Gi }

把副本数拉到 50:

kubectl apply -f deployment.yaml
kubectl scale deployment/load-demo --replicas=50

# 观察 Karpenter 即时起的新节点
kubectl get nodes -l karpenter.sh/initialized=true -w

# 缩回后,节点会在 consolidation 或 ttl 到期后被自动回收
kubectl scale deployment/load-demo --replicas=1

你会发现节点数量跟着 Pending Pod 曲线走,而不是跟着你手动改节点组。配合 CI 流水线做压测验证也很方便,参考 GitHub Actions 自动化实战 把这套扩容验证固化进流水线。

六、成本优化四板斧

  • 用 Spot 实例:非核心、可中断的负载放 Spot,通常能省 60%–90% 费用,配合 Pod 的 toleration 与 topologySpreadConstraints 提升容错。
  • 开启 Consolidation:让 Karpenter 把碎片化的 Pod 重新装箱,回收半空的节点。
  • 选对机型形状:CPU 密集选 c 系、内存密集选 r 系,避免”买内存送 CPU”的浪费。
  • 过期与滚动:用 expireAfter 周期性翻新节点,规避长期漏洞与漂移。

成本与可用性的取舍,本质上和 服务器安全加固 里”按需开放、最小暴露”的思路一脉相承:只给刚好够的资源,只开刚好够的口子。

七、Karpenter 与 Cluster Autoscaler 对比

维度Cluster AutoscalerKarpenter
扩容单位节点组(ASG/MIG)单节点(JIT)
机型选择固定模板按 Pod 需求动态选
启动延迟分钟级秒级到分钟级
装箱优化弱强(consolidation)
Spot 支持需多个节点组原生混合
运维负担维护多节点组维护 NodePool 规则

八、生产落地检查清单与常见误区

误区 / 风险正确做法
系统 Pod 被调度到临时 Spot 节点给 kube-system 加污点容忍豁免,或为关键组件单独 NodePool
Spot 中断导致服务雪崩设置 PDB + 多 AZ 分散 + 中断处理(terminationGracePeriod)
NodePool 无上限被刷爆账单务必配置 limits.cpu/memory 与预算告警
节点回收时 Pod 被强制杀开启 graceful eviction,给应用 preStop 与宽限时间

落地时建议把节点扩缩容指标接进 Prometheus + Grafana 监控,用一眼可见的曲线验证 Karpenter 是否真的在帮你省钱。容器层的入口流量治理可搭配 Traefik 实战 与 Cilium 零信任网络 形成完整栈。

九、与 HPA / KEDA 配合:Pod 层与节点层双层弹性

Karpenter 解决的是”节点够不够”的问题,而副本数由 Horizontal Pod Autoscaler(HPA)或 KEDA 决定。两者配合,才能形成”Pod 先扩、节点紧随补位”的顺滑曲线,而不是各管一段。一个典型的 HPA 配置如下:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: load-demo-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: load-demo
  minReplicas: 2
  maxReplicas: 50
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

当 HPA 把副本顶上去、现有节点放不下时,Karpenter 会立刻补节点;副本回落后,多余节点又被整合回收。我们之前在 KEDA 实战:事件驱动伸缩 里讲过的事件驱动扩容,同样可以叠加在这套节点底座之上。需要特别注意的是:不要让 HPA 的上限远高于 Karpenter 的 limits,否则会出现”Pod 想扩、节点却被卡住”的死锁。

十、从 Cluster Autoscaler 平滑迁移

别一刀切。推荐四步走,让业务全程无感:

  1. 并行部署:先在集群里装好 Karpenter,但只给它一个单独 NodePool,用节点标签把少数非核心负载调度过去试水;
  2. 观察验证:盯一段时间这些负载的扩缩容周期与账单,确认稳定可靠;
  3. 灰度迁移:用节点亲和性或污点,逐步把更多负载迁到 Karpenter 管理的节点;
  4. 下线旧方案:最后再停用 Cluster Autoscaler 背后的旧节点组,完成切换。

整个过程可随时回滚——只要把流量切回原来的节点组即可。对于已经在跑关键业务的集群,这种”先旁路、后切换”的节奏远比一次性替换安全。

小结:Karpenter 把”节点该是什么样”的决策权从运维手里交还给调度器,用按需即时供应 + 自动整合,换来了更顺滑的弹性与更低的账单。对于流量波动明显、希望把云成本压到极致的 Kubernetes 团队,它几乎是必选项。先用一个非核心的负载做灰度,观察几个扩缩容周期,再逐步把核心负载迁过来,是最稳妥的节奏。

上一篇 MapStruct 实战:用注解告别手写 DTO 转换
下一篇 MySQL 主从延迟排查实战:监控到根治
最新评论
Docker 网络模式详解:bridge/host 生产选型 - FSData
Docker 网络模式详解:bridge/host 生产选型 - FSData
8月20日
[…] 注意最后那条:把端口绑定到 127.0.0.1,再由宿主机上的 Nginx 反代进来,比直接 -p 80:80 暴露安全得多,也方便统一做
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
8月20日
[…] Pinia 的工程化用法,可以参考我们之前的实战文章 《Vue3 组合式 API + Pinia:状态管理从入门到实战》,那里覆盖了 Sto
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
8月19日
[…] 状态,点一下就能起停容器,配合我们讲过的 Docker Compose 编排 […]
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
8月19日
[…] 缓存三大坑的本质都是”缓存失效导致请求穿透到数据库”。记住口诀:穿透用布隆、击穿用锁、雪崩用错峰。配合合理的过期策略
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
8月19日
[…] Docker 镜像部署。结合我们之前写的 Docker Compose 一键编排实战,可以在 CI […]