跳到主要内容

使用 CPA + CA 预热扩容 Node

概述

在 Kubernetes 集群中,业务 Pod 扩容时如果资源不足,Cluster Autoscaler (CA) 会扩容节点,但通常需要 2-5 分钟,导致业务 Pod 长时间 Pending。

本文介绍通过 Cluster Proportional Autoscaler (CPA) 管理低优先级占位 Pod,提前触发 CA 扩容,业务 Pod 获得秒级响应(5-10 秒),响应速度提升 24-60 倍。这种思路和这种思路和阿里云基于ack-autoscaling-placeholder实现容器秒级伸缩 是类似的

工作原理

核心流程:

  1. CPA 根据节点数量自动管理占位 Pod(运行 pause 容器,最低优先级)
  2. 业务 Pod 扩容时立即抢占占位 Pod 资源
  3. 占位 Pod 进入 Pending 状态,触发 CA 扩容节点
  4. 新节点就绪后,占位 Pod 重新调度,恢复资源缓冲池

优势:

  • 部分业务 Pod 立即获得资源(5-10 秒 vs 2-5 分钟)
  • 保持集群始终有一定比例的资源缓冲
  • pause 容器实际消耗极少(~1MB 内存,~0.001 核 CPU)

适用场景:

  • 在线业务(Web、API)对响应时间敏感
  • 突发流量场景(秒杀、营销活动)
  • 资源规格统一的业务
  • 可承受 10-30% 资源预留成本

容量规划

以 16C32G 节点、4C8G 业务 Pod 为例:

节点规格:16C/32G
系统组件占用:~4C/8G(kubelet、kube-proxy、监控等)
可用资源:12C/24G
可运行业务 Pod(4C/8G):3 个

缓冲策略选择:

策略nodesPerReplica每节点占位 Pod资源缓冲适用场景
保守30.33 个10-13%成本优先
推荐20.5 个17-20%平衡成本与性能
水位线0.6671.5 个30-37%保证资源水位线
激进11 个33%极致响应速度

计算 nodesPerReplica

方法 1:基于目标缓冲比例

每个节点可运行业务 Pod 数:3 个
目标缓冲比例:20%
每个节点占位 Pod 数 = 3 × 20% = 0.6 个
nodesPerReplica = 1 / 0.6 = 1.67 ≈ 2

方法 2:基于资源水位线(更精确)

目标保留 30% 资源水位线:

步骤 1:每节点需保留 = 16C × 30% = 4.8C
步骤 2:每节点占位 Pod 数 = 4.8C / 4C = 1.2 个
步骤 3:向上调整为 1.5 个(更保守)
步骤 4:nodesPerReplica = 1 / 1.5 = 0.667

不同水位线配置对照:

目标水位线每节点保留占位 Pod 数 (4C)nodesPerReplica实际缓冲
20%3.2C1 个1.0~25%
30%4.8C1.5 个0.667~37%
40%6.4C2 个0.5~50%

注意:实际缓冲比例因 ceil() 向上取整会略高于目标值。

完整部署方案

步骤 1:创建 PriorityClass

# placeholder-priority.yaml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: placeholder-priority
value: -10 # 负数表示最低优先级
globalDefault: false
description: "Priority class for placeholder pods"

步骤 2:创建占位 Pod Deployment

# placeholder-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: placeholder-pods
namespace: default
spec:
replicas: 1 # CPA 会自动调整
selector:
matchLabels:
app: placeholder
template:
metadata:
labels:
app: placeholder
spec:
priorityClassName: placeholder-priority
containers:
- name: pause
image: registry.k8s.io/pause:3.9
resources:
requests:
cpu: "4000m"
memory: "8Gi"
limits:
cpu: "4000m"
memory: "8Gi"
# 反亲和性:分散到不同节点
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: placeholder
topologyKey: kubernetes.io/hostname

步骤 3:部署 CPA

推荐策略配置(20% 缓冲):

# placeholder-autoscaler-values.yaml
config:
linear:
nodesPerReplica: 2
min: 2
max: 50
preventSinglePointFailure: false
includeUnschedulableNodes: false

options:
namespace: default
target: "deployment/placeholder-pods"
pollPeriodSeconds: 30

水位线策略配置(30% 缓冲):

config:
linear:
nodesPerReplica: 0.667
min: 2
max: 100

安装:

# 添加 Helm 仓库
helm repo add cluster-proportional-autoscaler \
https://kubernetes-sigs.github.io/cluster-proportional-autoscaler
helm repo update

# 安装
helm install placeholder-autoscaler \
cluster-proportional-autoscaler/cluster-proportional-autoscaler \
-f placeholder-autoscaler-values.yaml \
--namespace default

步骤 4:配置业务 Pod 优先级

确保业务 Pod 优先级高于占位 Pod:

spec:
priorityClassName: system-cluster-critical # 或 high-priority
containers:
- name: app
resources:
requests:
cpu: "4000m"
memory: "8Gi"

效果验证

# 查看占位 Pod 分布
kubectl get pods -l app=placeholder -o wide

# 模拟业务 Pod 扩容
kubectl scale deployment business-app --replicas=15

# 观察占位 Pod 被抢占
kubectl get pods -l app=placeholder -w

# 观察业务 Pod 快速获得资源
kubectl get pods -l app=business -w

# 观察 CA 扩容节点
kubectl get nodes -w

扩缩容时序分析

10 节点集群,推荐策略(nodesPerReplica=2),扩容 15 个业务 Pod:

T0: 初始状态
- 10 节点,占位 Pod:5 个
- 业务 Pod:20 个运行中

T1 (+5秒): 业务 Pod 扩容
✓ 5 个业务 Pod 立即抢占占位 Pod(33% 即时响应)
- 10 个业务 Pod Pending

T2 (+10秒): CA 检测到 Pending
- 开始扩容 5 个节点

T3 (+2-5分钟): 稳定状态
- 15 节点,占位 Pod:8 个
- 业务 Pod:35 个运行

对比传统方式:
- 传统:15 个 Pod 全部等待 2-5 分钟
- 占位 Pod:5 个立即响应(33%),10 个等待 2-5 分钟

成本分析

集群规模策略占位 Pod占位资源缓冲比例年成本估算*
10 节点推荐5 个20C + 40GB16.7%~8,640 USD
10 节点水位线15 个60C + 120GB37.5%~25,920 USD
30 节点推荐15 个60C + 120GB16.7%~25,920 USD
100 节点推荐50 个200C + 400GB16.7%~86,400 USD

* 按 0.05 USD/核/小时估算,实际成本取决于云服务商定价

注意

  • 资源预留成本:高(占用可调度资源)
  • 实际运行成本:极低(pause 容器几乎不消耗资源)
  • 投资回报:部分 Pod 扩容时间从分钟级降至秒级

监控与告警

关键指标:

# 占位 Pod 总数
kubectl get pods -l app=placeholder --no-headers | wc -l

# Pending 状态的占位 Pod
kubectl get pods -l app=placeholder --field-selector=status.phase=Pending

# 抢占事件
kubectl get events --field-selector reason=Preempted

告警规则(Prometheus):

# 占位 Pod 持续 Pending 超过 10 分钟(CA 可能异常)
- alert: PlaceholderPodsPendingTooLong
expr: count(kube_pod_status_phase{pod=~"placeholder-pods-.*", phase="Pending"}) > 5
for: 10m
annotations:
summary: "占位 Pod 持续 Pending,检查 CA 是否正常工作"

最佳实践

  1. 资源规格对齐:占位 Pod 的资源请求必须与业务 Pod 一致,如果有多种规格,需要部署多组占位 Pod

  2. 优先级设计

    • 业务关键 Pod:system-cluster-critical(2000000000)
    • 业务普通 Pod:high-priority(1000)
    • 占位 Pod:placeholder-priority(-10)
  3. 缓冲比例选择

    • 突发流量大:激进策略(33% 缓冲)
    • 平衡场景:推荐策略(17-20% 缓冲)
    • 成本敏感:保守策略(10-13% 缓冲)
  4. 准确计算容量节点总资源 - 系统组件 = 可用资源,在测试环境验证实际可运行的 Pod 数量

  5. 节点异构处理:如果集群有多种规格节点,为每种规格部署独立的占位 Pod 和 CPA 实例

  6. 监控告警:持续监控占位 Pod Pending 数量,超过阈值说明 CA 可能异常

  7. 灰度验证:先在少量节点验证,确认抢占机制正常后再全面推广

  8. 动态调整:高峰时段提高缓冲,低峰时段降低缓冲(可通过 CronJob 调整 CPA 配置)

  9. 环境区分:生产环境使用推荐/水位线策略,测试环境使用保守策略或不使用

  10. 成本评估:根据实际扩容频率和响应速度提升,评估投资回报率

故障排查

1. 占位 Pod 一直 Pending

可能原因

  • CA 未正常工作
  • 节点规格限制(节点组已达上限)
  • 资源配额限制

排查

kubectl logs -n kube-system -l app=cluster-autoscaler -f
kubectl describe configmap cluster-autoscaler-status -n kube-system

2. 业务 Pod 没有抢占占位 Pod

可能原因

  • 业务 Pod 优先级不高于占位 Pod
  • 业务 Pod 没有配置 PriorityClass

排查

kubectl get priorityclass
kubectl describe pod <business-pod> | grep Priority
kubectl get events --field-selector reason=Preempted

3. 占位 Pod 数量不符合预期

可能原因

  • CPA 配置错误
  • min/max 限制触发

排查

kubectl logs -n default -l app=cluster-proportional-autoscaler -f
# 手动计算预期数量:ceil(节点数 / nodesPerReplica)

方案局限性

核心限制

1. 业务 Pod 资源规格必须统一

占位 Pod 是固定规格(如 4C/8G),要求所有业务 Pod 资源请求相同或接近。

问题

  • 小规格 Pod(2C/4G)抢占大占位 Pod(4C/8G)→ 浪费 2C/4G 资源
  • 大规格 Pod(8C/16G)无法抢占小占位 Pod(4C/8G)→ 必须等待 CA 扩容

解决方案

  • 按规格分类部署多组占位 Pod(小、中、大规格)
  • 标准化业务 Pod 资源规格(如仅 2C/4G、4C/8G、8C/16G)
  • 为每种规格部署独立的 CPA 实例

2. 无法综合评估多维度资源

CPA 计算公式是单维度的(节点数或 CPU 核心数),无法综合考虑 CPU 和内存。

问题

  • CPU 密集型业务(4C/2G)与内存密集型业务(1C/8G)混合时,单一规格占位 Pod 无法适配
  • 不同规格节点混合部署时(4C8G、16C32G、32C64G),单一占位 Pod 无法适应

解决方案

  • 为不同节点组部署独立的占位 Pod(使用 nodeSelector)
  • 使用多个 CPA 实例,按节点规格分组管理
  • 使用基于核心数的计算(coresPerReplica)更能适应异构环境

其他限制

  1. 资源成本:预留 10-30% 资源无法用于业务,存在明显成本
  2. 资源碎片化:固定规格占位 Pod 可能导致节点资源碎片
  3. 调度器性能:频繁抢占会增加调度器负载(大规模集群需注意)
  4. CA 扩容策略限制:CA 最小扩容单元可能导致过度扩容

适用性评估

适合使用:

  • 业务 Pod 资源规格统一或种类少(≤3 种)
  • 对响应时间敏感(需要秒级响应)
  • 可承受 10-30% 资源预留成本
  • 在线业务、实时计算、突发流量场景

不适合使用:

  • 业务 Pod 资源规格差异大(>5 种)
  • 稳定负载,扩容需求少
  • 成本高度敏感
  • 批处理任务,可接受分钟级扩容等待

方案对比

维度传统 CA占位 Pod 方案KarpenterCluster API
响应速度2-5 分钟5-10 秒(部分)
2-5 分钟(全部)
30-60 秒1-3 分钟
资源成本中高(预留 10-30%)
配置复杂度中高
资源规格要求无限制需要统一灵活灵活
异构节点支持差(需额外配置)
适用规模所有规模中小规模(<200 节点)所有规模大规模
推荐场景通用场景在线业务快速扩容成本敏感场景多云/混合云

卸载

# 卸载 CPA
helm uninstall placeholder-autoscaler -n default

# 删除占位 Pod Deployment
kubectl delete deployment placeholder-pods -n default

# 删除 PriorityClass
kubectl delete priorityclass placeholder-priority

参考资源