Skip to content

19 — 自动伸缩深度教材

自动伸缩是 K8s 的核心竞争力。本章覆盖 HPA/VPA/KEDA/Cluster Autoscaler 原理、协同、生产调优。


1. 四种伸缩机制

┌──────────────────┬────────────────────┬─────────────────────┐
│ 组件              │ 伸缩对象            │ 触发条件             │
├──────────────────┼────────────────────┼─────────────────────┤
│ HPA              │ Pod 副本数          │ CPU/内存/自定义指标  │
│ VPA              │ Pod resources       │ 历史资源使用         │
│ KEDA             │ Pod 副本数          │ 外部指标(MQ/Redis) │
│ Cluster Autoscaler│ Node 数量          │ Pending Pod         │
└──────────────────┴────────────────────┴─────────────────────┘

2. HPA(Horizontal Pod Autoscaler)

yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  minReplicas: 2
  maxReplicas: 20
  behavior:                          # 伸缩行为控制
    scaleUp:
      stabilizationWindowSeconds: 60  # 扩容前稳定 60 秒
      policies:
      - type: Percent
        value: 100                   # 每次最多扩容 100%
        periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300 # 缩容前稳定 5 分钟(防止抖动)
      policies:
      - type: Percent
        value: 10                    # 每次最多缩容 10%
        periodSeconds: 60
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70       # CPU 使用率 70% 触发扩容
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
bash
# 查看 HPA 状态
kubectl get hpa
# NAME          REFERENCE              TARGETS         MINPODS   MAXPODS   REPLICAS
# web-app-hpa   Deployment/web-app     45%/70%         2         20        5

# 调试 HPA
kubectl describe hpa web-app-hpa
# 查看 Events 中的伸缩决策

# HPA 不生效的常见原因:
# 1. metrics-server 未安装或不可用
# 2. Pod 未设置 resources.requests(无法计算使用率)
# 3. HPA min=max(固定副本数)

3. VPA(Vertical Pod Autoscaler)

yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: web-app-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  updatePolicy:
    updateMode: "Auto"     # Auto: 自动重启调整 / Off: 只建议不执行
  resourcePolicy:
    containerPolicies:
    - containerName: app
      minAllowed:
        cpu: 100m
        memory: 128Mi
      maxAllowed:
        cpu: 4
        memory: 8Gi
bash
# VPA 建议值
kubectl describe vpa web-app-vpa
# 查看 Recommendation 中的 Target/Lower Bound/Upper Bound

# VPA vs HPA 冲突:
# VPA 和 HPA 不能同时基于 CPU/内存伸缩
# 解决方案:VPA Off + HPA 基于自定义指标

4. KEDA(Kubernetes Event-Driven Autoscaling)

yaml
# KEDA 支持的外部指标源:
# Kafka/RabbitMQ 队列长度、Redis 列表长度、Prometheus 查询、AWS SQS 等

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: worker-scaler
spec:
  scaleTargetRef:
    name: worker
  minReplicaCount: 0          # 可以缩到 0
  maxReplicaCount: 50
  triggers:
  - type: kafka
    metadata:
      bootstrapServers: kafka:9092
      consumerGroup: worker-group
      topic: tasks
      lagThreshold: "100"     # 队列延迟超过 100 条触发扩容
  - type: prometheus
    metadata:
      serverAddress: http://prometheus:9090
      metricName: queue_length
      query: sum(kafka_consumer_lag)
      threshold: "1000"

5. Cluster Autoscaler

Cluster Autoscaler 工作原理:
  扩容:检测到 Pending Pod(无法调度)→ 请求云 API 创建新节点
  缩容:检测到低使用率节点(<50%)且 Pod 可迁移 → 排空并删除节点

生产配置:
  --scale-down-delay-after-add=10m     # 新节点加入后 10 分钟内不缩容
  --scale-down-unneeded-time=10m       # 节点空闲 10 分钟后才缩容
  --scale-down-utilization-threshold=0.5 # 使用率 <50% 才考虑缩容
  --max-node-provision-time=15m        # 节点创建超时
  --max-nodes-total=100                # 总节点上限
  
PDB 保护:Cluster Autoscaler 缩容时会尊重 PDB

6. 面试高频问题

Q: HPA 和 VPA 如何协同使用?

最佳实践:
1. VPA updateMode: Off(只建议不执行)
2. 参考 VPA 建议设置合理的 requests
3. HPA 基于 requests 百分比进行水平伸缩
4. 或者:VPA 管理内存 + HPA 基于 CPU/自定义指标水平伸缩

禁止:VPA 和 HPA 同时基于 CPU 伸缩(会冲突)

Q: 如何实现缩到 0(完全停止)?

HPA 不支持 minReplicas=0
解决方案:
1. KEDA:支持缩到 0(基于外部事件触发)
2. 自定义 Controller:监听队列长度,0 时停止
3. Knative:Serverless 模式,无流量时缩到 0