跳到主要内容

HPA与资源弹性伸缩

1. 概念

HPA(Horizontal Pod Autoscaler)根据指标自动调整 Pod 副本数。前端服务突发流量(大促、活动)最实用的自动化能力。

┌────────────┐
│ HPA 控制器 │
│ (每 15s) │
└──────┬─────┘
│ 读指标 + 决策

metrics-server / Prometheus adapter

┌──────┴──────┐
│ Deployment │
│ replicas: ? │
└─────────────┘

2. 基础配置

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

含义:当所有 Pod 平均 CPU > 70% 或内存 > 80%,扩容;低于阈值缩容。

前提:Pod 必须设 resources.requests,否则 utilization 无法计算。

3. 扩缩容行为控制

spec:
behavior:
scaleUp:
stabilizationWindowSeconds: 0 # 立即扩
policies:
- type: Percent
value: 100 # 最多翻倍
periodSeconds: 30
- type: Pods
value: 10 # 或最多加 10
periodSeconds: 30
selectPolicy: Max # 取两者最大
scaleDown:
stabilizationWindowSeconds: 300 # 稳定 5 分钟才缩
policies:
- type: Percent
value: 10 # 每分钟最多缩 10%
periodSeconds: 60

关键原则:扩快缩慢。扩容要迅速应对流量高峰,缩容要慢防止流量回弹。

4. 自定义指标

4.1 Prometheus Adapter

用 Prometheus 的任何指标做 HPA:

metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "100" # 每 Pod 100 RPS
- type: Object
object:
describedObject:
apiVersion: networking.k8s.io/v1
kind: Ingress
name: my-frontend
metric:
name: requests_per_second
target:
type: Value
value: "1000"

4.2 KEDA(更强大)

支持 30+ 事件源(SQS、Kafka、RabbitMQ、Cron、HTTP)作为扩缩触发:

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: my-frontend
spec:
scaleTargetRef:
name: my-frontend
minReplicaCount: 2
maxReplicaCount: 50
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus:9090
metricName: http_requests_total
query: sum(rate(http_requests_total{service="frontend"}[1m]))
threshold: "500"

5. VPA(垂直伸缩)

调整单 Pod 的 CPU/内存 requests(而非副本数):

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-frontend
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-frontend
updatePolicy:
updateMode: "Auto" # Off | Initial | Recreate | Auto

VPA 会重启 Pod 生效。HPA 和 VPA 不要同时对 CPU 生效(冲突),一般 HPA 管 CPU + VPA 只管内存。

6. 查看状态

kubectl get hpa -n frontend
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
# my-frontend Deployment/my-frontend 35%/70% 2 50 3

kubectl describe hpa my-frontend -n frontend
# Conditions / Events 段看扩缩历史

kubectl top pods -n frontend

7. 最佳实践

要点说明
requests 合理设置偏小→过早扩、偏大→不触发
minReplicas ≥ 2容灾
maxReplicas 设上限防失控扩容打爆预算
扩快缩慢stabilization 5 分钟+
非 CPU 指标兜底QPS / 队列长度比 CPU 更贴业务
配合 PDB(PodDisruptionBudget)缩容不把可用 Pod 缩到 0

PDB 示例

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-frontend
spec:
minAvailable: 1 # 任何时候至少 1 可用
# 或
# maxUnavailable: 1 # 任何时候最多 1 不可用
selector:
matchLabels:
app: my-frontend

8. 故障排查

# HPA TARGETS 显示 <unknown>
kubectl describe hpa my-frontend
# 原因:metrics-server 没装 / requests 没设 / permission 问题

# 不扩容
# 1. 看指标是否已超阈值
kubectl top pods
# 2. 看 events
kubectl describe hpa
# 3. 确认 metrics-server 运行
kubectl get pods -n kube-system | grep metrics-server

# 扩容太慢
# 调 stabilizationWindowSeconds 和 policies

9. 常见反模式

  • 不设 resources.requests:HPA 完全不工作(无法算比例)
  • minReplicas=1:缩容到 1 单点故障
  • 缩容太快:流量回弹时来不及扩回
  • HPA + VPA 同时管 CPU:互相打架
  • maxReplicas 太大不看成本:深夜流量低但 10 点突增 → 扩到 500 → 账单爆炸
  • 只看 CPU,Node SSR 瓶颈在内存:CPU 70% 但内存 OOM
  • 没有 PDB:缩容 + 滚动更新同时进行,可用 Pod 变 0

10. 延伸阅读