Kubernetes HPA 完整指南:基于自定义指标实现自动弹性伸缩

# Kubernetes HPA 完整指南:基于自定义指标实现自动弹性伸缩

## 背景介绍

云原生架构中,应用流量波动是常态。白天高峰期可能需要 10 个 Pod,凌晨低谷期 2 个 Pod 就够了。人工扩容响应滞后,既可能因资源不足导致服务降级,也可能因资源过剩造成成本浪费。

Kubernetes 提供了 Horizontal Pod Autoscaler(HPA)来解决这个问题。HPA 能够根据 CPU、内存等资源指标自动调整 Pod 副本数。然而,内置的 CPU 和内存指标往往不能满足复杂业务场景的需求——你可能需要根据业务相关指标(如消息队列积压数、请求延迟、活跃用户数等)来指导扩容决策。

这篇文章会带你掌握 Kubernetes HPA 的高级用法,重点讲解如何基于自定义指标实现精确的弹性伸缩。

## 问题描述

实际生产环境中,常见以下场景:

**场景一:消息队列消费者扩容**
订单处理服务需要消费 Kafka 消息。如果仅根据 CPU 扩容,当消息积压增多但消费者 CPU 使用率不高时,扩容无法及时响应,可能导致订单处理延迟。

**场景二:HTTP 服务基于 QPS 扩容**
对于 API 服务,我们希望根据每秒请求数来决定扩容策略。当 QPS 突然飙升时,即使 CPU 还没来得及飙升,也应该提前扩容以保证响应时间。

**场景三:基于业务指标的多维度扩容**
某些场景需要综合考虑多个指标,比如同时考虑 CPU 使用率和数据库连接池使用率。

这些场景的共同特点是:业务指标比资源指标更能准确反映真实的负载情况。Kubernetes HPA 支持自定义指标,正是为了解决这类问题。

## 详细步骤

### 第一步:安装 Prometheus 和 Adapter

要使用自定义指标,我们需要一个能够收集并提供自定义指标的监控系统,以及一个能够将指标格式转换为 HPA 可用格式的适配器。

最常见的组合是 Prometheus + Prometheus Adapter。

“`bash
# 安装 Prometheus Operator
kubectl create namespace monitoring
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring
“`

Prometheus Adapter 会作为 API Service 注册到 Kubernetes API Server,提供 `custom.metrics.k8s.io` API。

### 第二步:部署示例应用

用 Go 写一个简单的 HTTP 服务作为示例,暴露一个模拟业务负载的端点:

“`go
package main

import (
“fmt”
“net/http”
“sync/atomic”
“time”
)

var requestCount int64

func handler(w http.ResponseWriter, r *http.Request) {
atomic.AddInt64(&requestCount, 1)
time.Sleep(50 * time.Millisecond)
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, “OK”)
}

func metricsHandler(w http.ResponseWriter, r *http.Request) {
count := atomic.LoadInt64(&requestCount)
fmt.Fprintf(w, “# HELP http_requests_total Total HTTP requests\n”)
fmt.Fprintf(w, “# TYPE http_requests_total counter\n”)
fmt.Fprintf(w, “http_requests_total %d\n”, count)
}

func main() {
http.HandleFunc(“/”, handler)
http.HandleFunc(“/metrics”, metricsHandler)
http.ListenAndServe(“:8080”, nil)
}
“`

打包成镜像后,部署到 Kubernetes:

“`yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app
spec:
replicas: 2
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
containers:
– name: demo-app
image: your-registry/demo-app:latest
ports:
– containerPort: 8080
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi

apiVersion: v1
kind: Service
metadata:
name: demo-app
spec:
selector:
app: demo-app
ports:
– port: 80
targetPort: 8080
“`

### 第三步:配置 ServiceMonitor

让 Prometheus 自动抓取应用的指标:

“`yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: demo-app
labels:
release: prometheus
spec:
selector:
matchLabels:
app: demo-app
endpoints:
– port: web
path: /metrics
interval: 15s
“`

### 第四步:配置 Prometheus Adapter 规则

编辑 Prometheus Adapter 的 ConfigMap,添加自定义指标规则:

“`yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-adapter-config
namespace: monitoring
data:
config.yaml: |
rules:
– seriesQuery: “http_requests_total{namespace!=\”\”,pod!=\”\”}”
resources:
overrides:
namespace: {resource: “namespace”}
pod: {resource: “pod”}
name:
matches: “^(.*)$”
as: “http_requests_per_second”
metricsQuery: “sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)”
“`

这段配置做了这些事:
– 从 `http_requests_total` 指标中计算每秒请求速率
– 将结果重命名为 `http_requests_per_second`
– 按 pod 和 namespace 分组

### 第五步:创建 HPA 资源

现在可以基于自定义指标创建 HPA:

“`yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: demo-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: demo-app
minReplicas: 2
maxReplicas: 20
metrics:
– type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: 100
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
– type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
– type: Percent
value: 100
periodSeconds: 15
– type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
“`

配置说明:
– 每个 Pod 平均 QPS 超过 100 时开始扩容
– 扩容时最多增加 100% 的副本数或 4 个 Pod(取较大值)
– 缩容时每分钟最多减少 10% 的副本数,有 5 分钟的稳定窗口

## 运行结果

部署完成后,验证 HPA 是否正常工作。

先查看 HPA 状态:

“`bash
kubectl get hpa demo-app-hpa
“`

正常情况下会显示类似:

“`
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
demo-app-hpa Deployment/demo-app 50/100 2 20 2 5m
“`

`TARGETS` 列显示当前值是 50,目标是 100。当前值低于目标,所以副本数维持在最小值 2。

现在用负载测试工具来增加请求量:

“`bash
# 安装 hey 压测工具
go install github.com/rakyll/hey@latest

# 发起持续负载
hey -z 5m -c 200 http://demo-app.default.svc.cluster.local/
“`

几分钟后再次查看 HPA:

“`bash
kubectl get hpa demo-app-hpa -w
“`

你会看到类似输出:

“`
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
demo-app-hpa Deployment/demo-app 150/100 2 20 4 10m
demo-app-hpa Deployment/demo-app 200/100 2 20 8 11m
demo-app-hpa Deployment/demo-app 250/100 2 20 12 12m
“`

HPA 根据自定义指标(QPS)自动扩容了副本数。负载降低后,副本数会自动减少回到最小值。

查看 Pod 详情:

“`bash
kubectl get pods -l app=demo-app
“`

Pod 数量已经增加到 12 个。

## 总结

通过这篇文章,掌握了 Kubernetes HPA 基于自定义指标实现弹性伸缩的核心技能:

1. **Prometheus + Prometheus Adapter** 是实现自定义指标扩容的标准组合
2. **ServiceMonitor** 让 Prometheus 自动发现并抓取应用指标
3. **Adapter 配置** 将原始指标转换为 HPA 可用的标准化格式
4. **HPA behavior** 配置可以精细控制扩容和缩容策略

这种方案的优势在于:业务团队可以根据自己业务的特定指标来定义扩容规则,而不必局限于 CPU 和内存这些基础设施指标。当你的应用需要更精细的弹性伸缩策略时,这套方案值得尝试。

实际生产环境中,还需要注意以下几点:合理设置指标采集间隔以平衡精度和开销;为 HPA 设置合适的副本数上下限以控制成本;利用 stabilizationWindowSeconds 避免频繁的扩缩容抖动;最后为关键业务设置多指标联合扩容以提高可靠性。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇