Karpenter v1 生产实战:智能节点自动扩缩容彻底替代 Cluster Autoscaler
Karpenter 于 2024 年底发布 v1.0 GA,2025-2026 年已在大量 AWS EKS 和 Azure AKS 生产集群验证。相比传统 Cluster Autoscaler,Karpenter 在节点扩容速度上快 3-4 倍(45-60 秒 vs 3-4 分钟),支持直接按 Pod 需求混合选择实例类型,并通过主动整合(Consolidation)自动回收空闲节点降低云成本。本文讲解 Karpenter v1 的核心 API(NodePool / EC2NodeClass)、整合策略配置、Spot 实例混用、以及 Karpenter vs Cluster Autoscaler 的实际对比。
Karpenter 解决了一个长期困扰 Kubernetes 运维的问题:传统 Cluster Autoscaler 太慢、太笨。
Cluster Autoscaler 需要通过 ASG(Auto Scaling Group)来扩容节点,整个流程涉及 ASG → EC2 API → 节点注册 → Ready,通常需要 3-4 分钟。在流量突发场景下,这意味着大量 Pod 长时间处于 Pending 状态,影响用户体验。
Karpenter 跳过 ASG,直接调用 EC2 API 创建实例,同时能根据 Pending Pod 的实际需求(CPU、内存、GPU、架构)选择最合适的实例类型,扩容时间压缩到 45-60 秒。
Karpenter vs Cluster Autoscaler 对比
维度 Karpenter v1 Cluster Autoscaler
─────────────────────────────────────────────────────────────────
扩容速度 45-60 秒 3-4 分钟
实例类型选择 动态选择(按 Pod 需求) 预设 ASG 实例类型
Spot 实例支持 原生混合 需额外配置多 ASG
缩容/整合 主动整合(Consolidation)被动缩容(空闲 N 分钟)
GPU 感知 ✓(读取 Pod 资源请求) 需要手动配置 taint
自定义实例选择逻辑 NodePool requirements ASG 优先级配置
云平台支持 AWS(GA)、Azure(GA)、GKE 不可用(GKE 有原生版本)
适用建议(2026):
AWS EKS → Karpenter(强烈推荐)
Azure AKS → Karpenter(推荐)
GKE → Cluster Autoscaler(Karpenter 暂无 GKE GA 版本)
核心概念
Karpenter v1 的两个核心 CRD:
NodePool(节点池,cluster-scoped)
定义"什么样的节点"和"什么时候扩容"
控制:实例架构/类别/大小范围、操作系统、整合策略、容量限制
EC2NodeClass(EC2 节点类,cluster-scoped)
定义"具体的 AWS 配置"
控制:AMI 选择、安全组、子网、IAM 角色、用户数据(UserData)
关系:NodePool 通过 nodeClassRef 引用 EC2NodeClass
每个 NodePool 可以配置不同的整合策略和实例范围
安装 Karpenter(EKS 场景)
# 前置条件:EKS 集群(v1.28+)、AWS CLI 已配置
# 设置环境变量
export CLUSTER_NAME=my-eks-cluster
export AWS_DEFAULT_REGION=cn-hangzhou # 或 ap-northeast-1 等
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
# 创建 Karpenter 所需的 IAM 角色(使用 IRSA)
eksctl create iamserviceaccount \
--cluster ${CLUSTER_NAME} \
--namespace karpenter \
--name karpenter \
--role-name "KarpenterControllerRole-${CLUSTER_NAME}" \
--attach-policy-arn "arn:aws:iam::${AWS_ACCOUNT_ID}:policy/KarpenterControllerPolicy-${CLUSTER_NAME}" \
--approve
# 安装 Karpenter(Helm)
helm repo add karpenter https://charts.karpenter.sh/
helm repo update
helm install karpenter oci://public.ecr.aws/karpenter/karpenter \
--version "1.5.0" \
--namespace "karpenter" \
--create-namespace \
--set "serviceAccount.annotations.eks\.amazonaws\.com/role-arn=arn:aws:iam::${AWS_ACCOUNT_ID}:role/KarpenterControllerRole-${CLUSTER_NAME}" \
--set "settings.clusterName=${CLUSTER_NAME}" \
--set "settings.interruptionQueue=${CLUSTER_NAME}" \
--wait
# 验证安装
kubectl get pods -n karpenter
kubectl logs -n karpenter -l app.kubernetes.io/name=karpenter -f
EC2NodeClass 配置
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: default
spec:
# AMI 选择:使用 EKS Optimized AL2023
amiFamily: AL2023
# AMI 选择策略:自动使用最新的 EKS Optimized AMI(推荐)
amiSelectorTerms:
- alias: al2023@latest
# 子网(通过 tag 选择)
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: "${CLUSTER_NAME}"
# 或者指定特定子网 ID
# aws-ids: "subnet-abc123,subnet-def456"
# 安全组
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: "${CLUSTER_NAME}"
# 节点 IAM Role(需要有 EC2 SSM 权限和 ECR 拉取权限)
role: "KarpenterNodeRole-${CLUSTER_NAME}"
# 根磁盘配置
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
volumeSize: 100Gi
volumeType: gp3
iops: 3000
throughput: 125
encrypted: true
deleteOnTermination: true
# 自定义 UserData(可选,用于节点初始化脚本)
# userData: |
# #!/bin/bash
# echo "KUBELET_EXTRA_ARGS=--max-pods=110" >> /etc/default/kubelet
# 实例存储(可选,用于需要本地 NVMe 的工作负载)
instanceStorePolicy: RAID0 # 把实例存储配置为 RAID 0
NodePool 配置(核心)
通用 NodePool
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
# 整合策略(最重要的配置)
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized # 空闲或利用率低时整合
consolidateAfter: 30s # 节点空闲 30s 后开始整合
# budgets:控制同时被整合/删除的节点数量,防止大规模节点重建影响业务
budgets:
- nodes: "10%" # 最多同时中断 10% 的节点
# 可以按时间控制(如只在业务低峰期整合)
# schedule: "0 9 * * MON-FRI" # 工作日 9:00
# duration: 8h
# 节点容量限制(防止意外扩容过多)
limits:
cpu: "1000" # 整个 NodePool 最多 1000 个 CPU 核
memory: "4000Gi" # 最多 4TB 内存
template:
metadata:
labels:
node-type: general
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
requirements:
# 架构(x86_64 + ARM64 混用,Graviton 实例更便宜)
- key: kubernetes.io/arch
operator: In
values: ["amd64", "arm64"]
# 容量类型(按需 + Spot,Spot 价格便宜 60-80%)
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand", "spot"]
# 实例类别(避免旧一代实例)
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["c", "m", "r"] # c=计算优化, m=通用, r=内存优化
# 实例代次(只用最新一代)
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ["3"]
# 实例大小(避免过小或过大的实例)
- key: karpenter.k8s.aws/instance-size
operator: NotIn
values: ["nano", "micro", "small", "medium", "metal"]
# 操作系统
- key: kubernetes.io/os
operator: In
values: ["linux"]
# 节点终止等待时间
expireAfter: 720h # 节点 30 天后自动轮换(安全最佳实践)
专用 NodePool:高可用(仅按需实例)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: stable
spec:
disruption:
# WhenEmpty:只在完全空闲时才整合(保护有状态工作负载)
consolidationPolicy: WhenEmpty
consolidateAfter: 5m
budgets:
- nodes: "1" # 每次最多中断 1 个节点
limits:
cpu: "200"
memory: "800Gi"
# 设置较低的 weight,让 default NodePool 优先被选择
weight: 1 # 数值越大优先级越高
template:
metadata:
labels:
node-type: stable
annotations:
# 标记节点为高可用节点(方便运维识别)
team: "platform"
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand"] # 只使用按需实例,不用 Spot
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["m", "r"]
GPU NodePool(AI 工作负载)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: gpu
spec:
disruption:
consolidationPolicy: WhenEmpty # GPU 节点只在空闲时回收
consolidateAfter: 10m
budgets:
- nodes: "1"
limits:
cpu: "500"
nvidia.com/gpu: "32" # 最多 32 张 GPU
template:
metadata:
labels:
node-type: gpu
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
requirements:
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["g", "p"] # g=GPU 实例, p=高性能 GPU 实例
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ["4"]
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand", "spot"]
# GPU 节点自动打 taint,防止普通 Pod 调度到 GPU 节点
taints:
- key: nvidia.com/gpu
value: "true"
effect: NoSchedule
Pod 配置:影响 Karpenter 节点选择
# Karpenter 会读取 Pod 的资源请求、nodeSelector、affinity 来选择合适的实例
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-api
spec:
template:
spec:
containers:
- name: api
resources:
requests:
cpu: "2"
memory: "4Gi"
limits:
cpu: "4"
memory: "8Gi"
# 选择 stable NodePool(按需实例)
nodeSelector:
node-type: stable
# 或使用 nodeAffinity 更灵活
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-type
operator: In
values: ["general", "stable"]
# 拓扑分散(配合 Karpenter 多可用区)
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: web-api
监控和排查
# 查看 Karpenter 创建/删除的节点事件
kubectl get events -n karpenter --sort-by='.lastTimestamp'
# 查看 NodePool 状态
kubectl get nodepools
kubectl describe nodepool default
# 查看当前节点分布(由哪个 NodePool 创建)
kubectl get nodes -L karpenter.sh/nodepool,node.kubernetes.io/instance-type,topology.kubernetes.io/zone
# 查看 Karpenter 正在监控的 Pending Pod
kubectl get pods -A --field-selector=status.phase=Pending
# 实时查看 Karpenter 日志(看整合决策过程)
kubectl logs -n karpenter \
-l app.kubernetes.io/name=karpenter \
-f --tail=100 | grep -E "provisioning|disruption|consolidat"
# 查看 Karpenter 指标(如果集成了 Prometheus)
# karpenter_nodepool_usage - NodePool 当前资源使用
# karpenter_nodes_total - 节点总数
# karpenter_provisioner_scheduling_duration - 调度决策耗时
# karpenter_disruption_disruptions_total - 整合操作次数
成本优化实践
Spot 实例使用建议:
无状态 Web 服务、API:
→ 使用 Spot(80% 请求可以跑在 Spot 上)
→ 设置 PodDisruptionBudget 限制同时中断数量
→ 配合 HPA 快速补充被中断的 Spot 节点
有状态服务(数据库、消息队列):
→ 使用按需实例(stable NodePool)
→ 不要用 Spot(中断风险过高)
批处理 / AI 训练:
→ 积极使用 Spot(可接受中断后重试)
→ 使用 checkpointing 减少重试成本
实际成本节省(参考数据):
Spot 实例 vs 按需:节省 60-80%
Karpenter 整合 vs 手动管理:额外节省 20-30%(因为空闲节点被回收更快)
综合:大多数企业用 Karpenter 后云成本降低 30-50%
小结
Karpenter v1 在 2026 年已经是 AWS EKS 集群的首选节点自动扩缩容方案。它的核心价值不只是“扩得快”,更在于 WhenEmptyOrUnderutilized 整合策略能持续主动缩容空闲节点——这才是长期降低云成本的关键。
从 Cluster Autoscaler 迁移到 Karpenter 的主要工作是配置 NodePool 和 EC2NodeClass,逻辑比 ASG 配置更清晰,只需要用 Kubernetes 资源声明意图,Karpenter 负责实现。
