使用Karpenter实现节点弹性伸缩
Karpenter是一个适用于Kubernetes平台的动态、高性能、开源的集群自动扩展解决方案,意在正确的时间使用正确的节点,简化Kubernetes基础设施管理。相较于Cluster AutoScaler,它将资源扩容时间由分钟级降为秒级,显著提高集群上工作负载的运行效率并降低成本。
Karpenter的工作原理如下:
- 监听:监控被标记为unschedulable状态的Pod。许多场景会导致Pod的不可调度,例如:CPU/内存资源不足、selector条件不满足、Node的taint/toleration条件不匹配、hostport被占用等。
- 计算:Karpenter分析这些导致Pod无法调度的限制。
- 扩容:选择满足Pod调度限制条件的Node进行扩容。
- 缩容:当节点空闲、资源到期等场景下,进行缩容。
核心特性与优势
- 事件驱动,快速扩容:传统CA(Cluster Autoscaler)依赖周期性轮询与云端弹性伸缩组中转,新节点加入通常耗时 3~5 分钟。Karpenter摒弃了这一模式,持续监听集群内部的 Pod 调度事件,实现毫秒级响应。它直接评估未决(Pending)Pod的资源诉求,并绕过中间层直接调用云服务商 API。快速拉起最匹配的计算节点,从容应对突发激增流量与高并发工作负载。
- 无组架构(Group-less): Karpenter绕过传统的固定节点池限制,支持通过声明式的NodePool策略灵活配置可用区、实例架构及计费模式。系统会精准解析Pod的CPU/内存需求及亲和性(Affinity/Tolerations)等调度规则。结合深度适配的Flexus X实例,更可实现按需定制的CPU/内存资源灵活配比,确保节点规格与业务真实需求“严丝合缝”,从源头避免资源超分和浪费。
- 持续智能整合(Consolidation): Karpenter不仅关注扩容速度,更注重集群全生命周期的效能管理。系统会持续评估当前的实时资源利用率,通过启用WhenEmptyOrUnderutilized等节点整合策略,Karpenter能够自动回收完全空闲的节点,并主动将低利用率节点上的Pod进行平滑驱逐与迁移。通过将零散负载聚合至更少或更具成本效益的实例上,最大化压缩集群的闲置成本。
- 容量与费用感知:
- 对接云服务商计费模型。在扩容时,它能够基于实时的实例价格进行多维度的成本计算,智能挑选满足Pod需求的最低单价实例组合。同时它原生支持按需(On-Demand)与竞价(Spot)实例的灵活混部,将集群算力成本压至极低。
- 实时感知云服务商库存。一旦首选规格售罄(触发资源不足异常),它能够在毫秒级自动重试并无缝回退(Fallback)至其他可用规格或可用区,彻底消除传统CA因单一节点池缺货导致的扩容阻塞,强力保障业务连续性。
前提条件
- 已创建一个1.29及以上的集群,且集群中包含可运行Karpenter组件的节点。
- 安装模板过程中,需要拉取公网镜像,需要节点绑定有EIP。
- Karpenter容器依赖公网访问能力,普通集群需要Karpenter所在节点绑定EIP,Turbo集群需要Karpenter容器绑定EIP。
约束与限制
- Karpenter需要配置对应的云服务商权限才能创删节点,目前Karpenter暂时使用AK/SK凭据。后续Karpenter将作为CCE插件市场系统插件,支持自定义插件委托或Pod Identity的鉴权方式。
- Karpenter与CCE集群弹性引擎均为节点的扩缩容插件,因此不能同时安装,避免两者间的相互干扰。
- Karpenter无法缩容部分CCE系统插件Pod所在节点。
部署Karpenter
- 获取模板包。
前往模板发布页面,选择合适的版本并下载tgz格式的Helm Chart包。本文以0.2.1版本的模板包为例,该模板包适用于v1.29及以上的CCE集群。由于不同版本的模板包配置项可能存在差异,本文中的配置适用于0.2.1版本。
- 上传模板
- 登录CCE控制台,进入集群,在左侧导航栏中选择“应用模板”,在右上角单击“上传模板”。
- 单击“添加文件”,选中待上传的模板包后,单击“上传”。
- 自定义value.yaml
您可在本地创建一个value.yaml配置文件用于设置安装工作负载参数,在安装时只需导入此配置文件进行自定义安装,其他未指定的参数将会使用默认配置。
配置内容如下:# Default values for karpenter-provider-huawei # -- Number of controller replicas replicaCount: 1 # Controller image configuration image: # -- Controller image repository repository: swr.ap-southeast-3.myhuaweicloud.com/huaweiclouddeveloper/cce/karpenter/controller # -- Controller image tag tag: "0.2.1" # -- Image pull policy pullPolicy: IfNotPresent # kube-rbac-proxy sidecar configuration rbacProxy: image: # -- kube-rbac-proxy image repository repository: quay.io/brancz/kube-rbac-proxy # -- kube-rbac-proxy image tag tag: "v0.16.0" # -- Image pull policy pullPolicy: IfNotPresent # -- Image pull secrets for controller pods imagePullSecrets: [] # - name: registry-credentials # -- Name prefix for all resources namePrefix: "karpenter-provider-huawei-" serviceAccount: # -- Create ServiceAccount create: true # -- ServiceAccount name name: controller-manager # Controller arguments controller: # -- Metrics port metricsPort: 8080 # -- Health probe port healthProbePort: 8081 # Huawei Cloud credentials # The generated Secret uses HUAWEICLOUD_SDK_AK, HUAWEICLOUD_SDK_SK, # and HUAWEICLOUD_SDK_REGION_ID from this block, plus # HUAWEICLOUD_SDK_CCE_CLUSTER_ID from clusterInfo.clusterID. # If credentials.create=false, the existing Secret should provide the same keys. credentials: # -- Create a Secret for credentials create: true # -- Secret name for Huawei Cloud credentials name: "huawei-credentials" # -- Use an existing Secret when credentials.create is false existingSecret: "" # -- Huawei Cloud access key accessKey: "your-access-key" # -- Huawei Cloud secret key secretKey: "your-secret-key" # -- Huawei Cloud region ID region: "your-region-id" clusterInfo: # -- Huawei Cloud CCE cluster ID clusterID: "your-cluster-id" # -- Cluster category: Optional. Enter "eni" for Turbo network types. # For other network types (vpc-router or overlay_l2), enter other values. category: "" # -- yangtseEipInfo: Supports user-defined EIPs (Elastic IPs) bound to Karpenter pods. # This only takes effect when clusterInfo.category is set to "eni". yangtseEipInfo: yangtse.io/pod-with-eip: "true" # Controller resources resources: limits: cpu: "1" memory: 512Mi requests: cpu: 200m memory: 256Mi # -- Pod security context podSecurityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault # -- Container security context for manager securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: - "ALL" # -- Node selector for controller pods nodeSelector: {} # -- Tolerations for controller pods tolerations: [] # -- Affinity for controller pods affinity: {}- clusterInfo.category指定为eni时,会自动为Karpenter Pod绑定EIP,建议在Turbo集群开启,更多EIP参数可在yangtseEipInfo字段中配置,参数配置请参见在CCE Turbo集群中为Pod配置EIP。
- clusterInfo.clusterID、credentials.accessKey、credentials.secretKey、credentials.region等字段为必填字段,其他参数请根据业务实际所需调整。
- 创建模板实例。
- 登录CCE控制台,进入集群,在左侧导航栏中选择“应用模板”。
- 在已上传的模板中,单击“安装”。
- 填写“实例名称”,选择“命名空间”和“选择版本”。
- 单击“配置文件”后的“添加文件”按钮,选择本地创建的YAML配置文件,单击“安装”。

- 在“模板实例”页签下可以查看模板实例的安装情况。
测试验证
- 创建NodePool、CCENodeClass资源。关于该资源配置参数的说明请参见配置参数说明。
apiVersion: karpenter.k8s.huawei/v1alpha1 kind: CCENodeClass metadata: name: demo-cce-elastic-cpu spec: # Add one subnet per target AZ if you want this demo NodePool to launch # across multiple zones. subnetSelectorTerms: - id: "30abcb7b-ddeb-4a93-9e83-0b21f59b07a3" imsSelector: imsFamily: "Huawei Cloud EulerOS 2.0" blockDeviceMappings: root: volumeSize: 40 volumeType: SSD k8s: volumeSize: 100 volumeType: SSD runtimeConfiguration: type: containerd login: userPassword: username: root password: "JDYk*****" --- apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: demo-cce-elastic-cpu spec: disruption: budgets: - nodes: "1" consolidationPolicy: WhenEmptyOrUnderutilized consolidateAfter: 30s limits: # Allow enough headroom for the 600-replica GSS validation to scale past 4 x 12c nodes. cpu: "100" memory: 384Gi template: metadata: labels: demo.huawei.com/scenario: cpu-elastic demo.huawei.com/nodepool-profile: shared-burst-and-consolidation spec: nodeClassRef: group: karpenter.k8s.huawei kind: CCENodeClass name: demo-cce-elastic-cpu 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 # Keep zone unconstrained so Karpenter can use every AZ exposed by the # selected ECSNodeClass subnets. Re-add a topology.kubernetes.io/zone # requirement if you need to pin this demo to specific AZs. - key: node.kubernetes.io/instance-type operator: In values: - c9.large.4 - c9.xlarge.4 - c9.2xlarge.4 - c9.4xlarge.4 - 创建一个工作负载,验证Karpenter扩容节点。
apiVersion: apps/v1 kind: Deployment metadata: name: cpu-burst namespace: default spec: replicas: 0 selector: matchLabels: app: cpu-burst template: metadata: labels: app: cpu-burst spec: terminationGracePeriodSeconds: 10 nodeSelector: demo.huawei.com/scenario: cpu-elastic containers: - name: web image: nginx:1.27-alpine imagePullPolicy: IfNotPresent ports: - containerPort: 80 name: http resources: requests: cpu: "1400m" memory: "1200Mi" limits: cpu: "1400m" memory: "1200Mi" - 扩容工作负载。
kubectl scale deployment cpu-burst --replicas=10
Deployment部署后可以看到新拉起的Pod无法在已有节点调度,一段时间后新的节点被创建,Pod能够被正常调度到新节点上:
$ kubectl get node NAME STATUS ROLES AGE VERSION 192.168.1.15 Ready <none> 3h28m v1.33.5-r20-33.0.4.9 192.168.1.158 Ready <none> 42m v1.33.5-r20-33.0.4.9 192.168.1.168 Ready <none> 4m7s v1.33.5-r20-33.0.4.9 $ kubectl get pod -l app=cpu-burst NAME READY STATUS RESTARTS AGE cpu-burst-5d84f5647c-697j2 1/1 Running 0 9m35s cpu-burst-5d84f5647c-9r9rs 1/1 Running 0 9m35s cpu-burst-5d84f5647c-9swmq 1/1 Running 0 9m35s cpu-burst-5d84f5647c-bqrmw 1/1 Running 0 9m35s cpu-burst-5d84f5647c-jc7f9 1/1 Running 0 9m35s cpu-burst-5d84f5647c-pshpx 1/1 Running 0 9m35s cpu-burst-5d84f5647c-qkzfm 1/1 Running 0 9m36s cpu-burst-5d84f5647c-rl7mk 1/1 Running 0 9m35s cpu-burst-5d84f5647c-tnt92 1/1 Running 0 9m35s cpu-burst-5d84f5647c-w728l 1/1 Running 0 9m35s
- 缩容工作负载
kubectl scale deployment cpu-burst --replicas=5
当工作负载被缩容后,新的小核节点先创建,而后老节点被回收。
$ kubectl get node NAME STATUS ROLES AGE VERSION 192.168.1.15 Ready <none> 3h30m v1.33.5-r20-33.0.4.9 192.168.1.168 Ready <none> 6m25s v1.33.5-r20-33.0.4.9 192.168.1.71 Ready <none> 2m14s v1.33.5-r20-33.0.4.9


模板实例回收
- 登录CCE控制台,进入集群,在左侧导航栏中选择“应用模板”。
- 在“模板实例”中,选择安装的实例,单击“更多”后的“卸载”。
配置参数说明
- NodePool资源参数说明:请参见Karpenter官方说明
- CCENodeClass资源参数说明:
表1 CCENodeClass资源参数 参数
是否必选
参数类型
描述
subnetSelectorTerms
是
SubnetSelectorTerm object
参数解释:
配置节点子网信息的列表
约束限制:
不涉及
ecsGroupId
否
String
参数解释:
云服务器组ID,若指定,将节点创建在该云服务器组下
约束限制:
不涉及
取值范围:
不涉及
默认取值:
imsSelector
是
IMSSelector object
参数解释:
节点操作系统与镜像的配置对象
约束限制:
不涉及
blockDeviceMappings
是
BlockDeviceMappings Object
参数解释:
节点磁盘设备的配置对象
约束限制:
不涉及
login
是
Login Object
参数解释:
节点的登录方式
约束限制:
不涉及
runtimeConfiguration
否
RuntimeConfiguration Object
参数解释:
运行时配置对象
约束限制:
不涉及
表2 SubnetSelectorTerm 参数
是否必选
参数类型
描述
id
是
String
参数解释:
网卡所在子网的网络ID
约束限制:
不涉及
取值范围:
登录VPC控制台,在左侧导航栏选择“子网”,单击子网名称,在“基本信息”页签下找到“网络ID”字段复制即可。
默认取值:
不涉及
表3 IMSSelector 参数
是否必选
参数类型
描述
imsFamily
是
String
参数解释:
节点的操作系统类型。具体支持的操作系统请参见节点操作系统说明。
约束限制:
不涉及
取值范围:
不涉及
默认取值:
不涉及
表4 BlockDeviceMappings 参数
是否必选
参数类型
描述
root
是
BlockDevice Object
参数解释:
系统磁盘
约束限制:
不涉及
k8s
是
BlockDevice Object
参数解释:
runtime及K8s使用数据盘
约束限制:
不涉及
users
否
Array of BlockDevice Objects
参数解释:
用户数据卷
约束限制:
不涉及
表5 BlockDevice 参数
是否必选
参数类型
描述
volumeSize
是
Int
参数解释:
磁盘大小,单位为GiB
约束限制:
不涉及
取值范围:
- root卷取值范围:20-1024
- k8s卷取值范围:20-32768
- 用户卷取值范围:10-32768
默认取值:
不涉及
volumeType
是
String
参数解释:
磁盘类型
约束限制:
不涉及
取值范围:
- SAS:高IO,是指由SAS存储提供资源的磁盘类型。
- SSD:超高IO,是指由SSD存储提供资源的磁盘类型。
- SATA:普通IO,是指由SATA存储提供资源的磁盘类型。EVS已下线SATA磁盘,仅存量节点有此类型的磁盘。
- ESSD:极速型SSD云硬盘,是指由极速型SSD存储提供资源的磁盘类型。
- GPSSD:通用型SSD云硬盘,是指由通用型SSD存储提供资源的磁盘类型。
- ESSD2:极速型SSD V2云硬盘,是指由极速型SSD V2存储提供资源的磁盘类型。
- GPSSD2:通用型SSD V2云硬盘,是指由通用型SSD V2存储提供资源的磁盘类型。
默认取值:
不涉及


