Kubernetes水平自动扩缩容控制器
HorizontalPodAutoscaler(简称 HPA)根据观测到的指标自动调整工作负载的副本数。它周期性地(默认每 15 秒)从 Metrics API 读取指标,计算出期望副本数,再写回目标对象的 scale 子资源。
HPA 的扩缩容公式为:
desiredReplicas = ceil[currentReplicas × (currentMetricValue / desiredMetricValue)]
例如当前 3 个副本、CPU 平均利用率 90%、目标 60%,则期望副本数为 ceil(3 × 90/60) = ceil(4.5) = 5。为避免抖动,当比值与 1 的差距在 10%(默认容差) 以内时不做任何调整。
HPA 依赖 metrics-server 提供 CPU/内存指标。没有部署 metrics-server 时,kubectl top 会报错,HPA 的 TARGETS 列会显示 <unknown>,且不会执行任何扩缩容。这是 HPA「不生效」最常见的原因。
HPA 只能作用于提供 scale 子资源的对象,因此可以用于 Deployment、StatefulSet、ReplicaSet,也支持自定义资源;DaemonSet 不支持。
kubectl [command] hpa [flags]
HPA 的常用简写为 hpa(无更短别名):
kubectl get hpa
kubectl describe hpa nginx-hpa
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 自签证书的集群需要放宽 kubelet 证书校验
kubectl patch deployment metrics-server -n kube-system --type=json \
-p '[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'
# 验证指标是否可用
kubectl top nodes
kubectl top pods
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization # 相对于 requests 的百分比
averageUtilization: 60
使用 Utilization 时,目标工作负载必须设置 resources.requests.cpu,否则 HPA 无法计算利用率,会一直报 missing request for cpu。
创建与查看:
kubectl apply -f hpa.yaml
# 也可以用命令直接创建
kubectl autoscale deployment nginx --min=2 --max=10 --cpu-percent=60
kubectl get hpa
kubectl get hpa -o wide
kubectl describe hpa nginx-hpa
kubectl get hpa nginx-hpa -o yaml
spec:
metrics:
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 75
内存指标需要 resources.requests.memory。需要注意:内存不像 CPU 那样会被回收,基于内存的扩缩容易产生震荡,通常只在明确知道应用内存模型时才使用。
配置多个指标时,HPA 会分别计算每个指标的期望副本数,并取最大值执行,保证所有指标都被满足:
spec:
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "100"
- type: External
external:
metric:
name: sqs_queue_length
selector:
matchLabels:
queue: critical
target:
type: AverageValue
averageValue: "30"
behavior 用于抑制抖动:扩容可以激进,缩容必须保守。
spec:
behavior:
scaleUp:
stabilizationWindowSeconds: 0 # 立即响应
policies:
- type: Percent
value: 100 # 每次最多翻一倍
periodSeconds: 60
- type: Pods
value: 4 # 或每次最多加 4 个
periodSeconds: 60
selectPolicy: Max # 多策略时取变化最大的
scaleDown:
stabilizationWindowSeconds: 300 # 缩容前观察 5 分钟
policies:
- type: Percent
value: 10 # 每分钟最多减少 10%
periodSeconds: 60
selectPolicy: Min
stabilizationWindowSeconds 表示「回看窗口内所有推荐值中的极端值才是最终决策」:缩容窗口内取最大推荐值,扩容窗口内取最小推荐值。默认缩容窗口是 300 秒,扩容窗口是 0 秒。
# 查看当前指标与副本数
kubectl get hpa
# 查看 HPA 的决策事件(最有用的排障手段)
kubectl describe hpa nginx-hpa
# 修改副本数范围
kubectl patch hpa nginx-hpa -p '{"spec":{"maxReplicas":20}}'
# 删除 HPA 后手动 scale 的副本数才会被保留
kubectl delete hpa nginx-hpa
# 用 busybox 制造 CPU 压力
kubectl run -it --rm load-generator --image=busybox:1.36 --restart=Never -- \
/bin/sh -c "while true; do wget -q -O- http://nginx.default.svc.cluster.local; done"
# 另开一个终端观察副本数上升
kubectl get hpa nginx-hpa -w
kubectl get pods -l app=nginx -w
TARGETS 显示 <unknown>。这是 HPA 排障的第一检查项。resources.requests。使用 Utilization 类型时缺少 requests 会导致 HPA 报错并停止扩缩容。kubectl scale 的结果。手工扩容后,下一个同步周期 HPA 就会把副本数改回它计算出的值。replicas,会与 HPA 持续冲突,应当在清单中移除 replicas 字段。minReplicas 之前,如果 Pod 处于 NotReady 或正在启动,HPA 的计算会被跳过,避免在滚动更新期间误判。autoscaling/v2beta2 在 v1.26 已被移除,请一律使用 autoscaling/v2。maxReplicas 仍扛不住流量,需要人工提高上限或优化单副本性能。kubectl — Kubernetes集群管理工具deployment — 无状态工作负载控制器statefulset — 有状态工作负载控制器replicaset — Pod 副本控制器pod — 最小调度单元