Kubernetes HPA为什么需要自定义指标
Kubernetes原生的Horizontal Pod Autoscaler默认只支持CPU和内存两种资源指标触发扩缩容。对于Web服务来说,CPU利用率并不是最佳的伸缩信号——当请求队列积压时CPU可能仍然空闲(等待IO),而当CPU飙高时延迟已经恶化。基于请求延迟(Latency)、队列深度(Queue Depth)、QPS等业务指标的HPA才是生产级自动伸缩的正确姿势。
自定义指标HPA的实现链路为:应用暴露指标到Prometheus采集到Prometheus Adapter转换到Kubernetes API Server注册到HPA Controller消费。这条链路中任何一个环节配置错误都会导致HPA无法工作。
Prometheus Adapter部署与配置
Prometheus Adapter的核心作用是将Prometheus中的时序数据转换为Kubernetes自定义指标API格式。HPA Controller通过Kubernetes API查询这些指标,而Adapter充当了API聚合层的后端。
使用Helm部署:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus-adapter prometheus-community/prometheus-adapter \
--set prometheus.url=http://prometheus-server.monitoring.svc \
--set prometheus.port=80 \
--set rules.default=false \
--namespace monitoring --create-namespace
关键配置在于自定义指标发现规则(rules),通过ConfigMap定义PromQL到Kubernetes指标的映射:
rules:
custom:
- seriesQuery: 'http_requests_total{namespace!="",pod!=""}'
resources:
overrides:
namespace: {resource: "namespace"}
pod: {resource: "pod"}
name:
matches: "^(.*)_total"
as: "${1}_per_second"
metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>},1m)) by (<<.GroupBy>>)'
这段配置做了以下映射:从Prometheus的http_requests_total指标中提取namespace和pod标签,转换为Kubernetes的Pod级别自定义指标http_requests_per_second,值取1分钟速率的sum。
HPA自定义指标伸缩策略编写
Adapter部署完成后,编写HPA资源:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-api-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-api
minReplicas: 3
maxReplicas: 50
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "1000"
- type: Pods
pods:
metric:
name: http_request_duration_seconds
selector:
matchLabels:
quantile: "0.99"
target:
type: AverageValue
averageValue: "500m"
该策略定义了两个触发条件:单Pod平均QPS超过1000时扩容,P99延迟超过500ms时扩容。两个条件取最大值,任何一个触发都会执行扩容。
排错:自定义指标HPA的常见故障
故障一:HPA显示unable to get metric
这是最常见的错误。排查步骤:
# 检查Adapter是否注册了自定义指标API
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | jq .
# 检查特定指标是否可查询
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/production/pods/*/http_requests_per_second" | jq .
# 查看Adapter日志
kubectl logs -n monitoring deploy/prometheus-adapter | grep -i error
如果API注册成功但指标为空,说明PromQL查询返回了空结果。在Prometheus中直接执行该PromQL确认数据存在,常见原因是标签名不匹配或namespace标签缺失。
故障二:指标可查询但HPA不触发扩容
检查指标值是否真的超过阈值,以及HPA的tolerance(默认10%)。如果指标值仅超出阈值5%,在tolerance范围内不会触发。另外检查scaleTargetRef指向的Deployment是否设置了resources.requests,HPA依赖requests计算利用率百分比。
KEDA:事件驱动的自动伸缩方案
当伸缩信号不来自Prometheus而是来自消息队列、数据库等外部系统时,Prometheus Adapter方案链路过长。KEDA(Kubernetes Event-Driven Autoscaling)直接对接数据源,无需中间转化层。
以Kafka消费者延迟为例:
# 安装KEDA
helm repo add kedacore https://kedacore.github.io/charts
helm install keda kedacore/keda --namespace keda --create-namespace
# 定义ScaledObject
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: order-processor-scaler
spec:
scaleTargetRef:
name: order-processor
minReplicaCount: 2
maxReplicaCount: 30
triggers:
- type: kafka
metadata:
bootstrapServers: kafka:9092
consumerGroup: order-group
lagThreshold: "100"
offsetResetPolicy: latest
KEDA的Kafka Trigger直接查询Broker的consumer lag,当lag超过100条时触发扩容。相比Prometheus Adapter方案,少了PromQL到Adapter再到API Server的转换链路,延迟降低数秒。
KEDA已原生支持70+种数据源触发器,包括RabbitMQ、Redis Stream、PostgreSQL、AWS SQS、阿里云MQ等。对于消息驱动型微服务架构,KEDA比Prometheus Adapter方案更适合。
混合伸缩策略:资源指标加业务指标加事件驱动
生产环境中单一伸缩信号容易误判。推荐组合策略:
1. CPU/内存作为保底伸缩信号,防止资源耗尽。
2. 业务指标(QPS/延迟)作为主伸缩信号,对业务流量精确响应。
3. 事件驱动(KEDA)作为补充,对异步任务队列深度响应。
4. 设置scaleDownStabilizationWindowSeconds=300,避免指标波动导致频繁缩容。
5. 对关键服务设置minReplicas=3和PodDisruptionBudget,确保缩容不破坏可用性。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/kubernetes-zi-ding-yi-zhi-biao-hpa-shen-suo-shi-zhan/