原力注入

Kubernetes HPA 原理与实践

HPA 自定义指标架构图

自定义指标架构支持业务级别的指标监控,通过 Prometheus 生态系统提供丰富的自定义指标能力。

1.2.2 资源指标架构详解

核心组件:

1. Metrics Server:

  • • Kubernetes 官方提供的集群级别资源监控组件
  • • 从 kubelet 的 cAdvisor 收集 CPU 和内存使用数据
  • • 提供 metrics.k8s.io/v1beta1 API 接口
  • • 数据采集频率:默认 15 秒¹

2. kubelet & cAdvisor:

  • • kubelet:节点代理,负责 Pod 生命周期管理
  • • cAdvisor:容器监控组件,内置于 kubelet 中
  • • 实时收集容器的资源使用情况

3. HPA Controller:

  • • 查询 Metrics Server 获取资源指标
  • • 基于 CPU/内存利用率计算期望副本数
  • • 执行扩缩容决策

资源指标数据流:

cAdvisor → kubelet → Metrics Server → HPA Controller → Deployment

1.2.3 自定义指标架构详解

核心组件:

1. Prometheus 监控栈:

  • • Prometheus Server:时序数据库,存储和查询指标数据
  • • ServiceMonitor/PodMonitor:定义监控目标的 CRD 资源
  • • 支持多维度标签和复杂查询语言 PromQL

2. Prometheus Adapter:

  • • 将 Prometheus 指标转换为 Kubernetes API 格式
  • • 提供 custom.metrics.k8s.io/v1beta1 API 接口
  • • 支持指标聚合和标签映射

3. Custom Metrics API:

  • • Kubernetes API 聚合层的扩展
  • • 为 HPA 提供统一的自定义指标查询接口
  • • 支持 Pod 级别和对象级别的指标

4. 应用程序:

  • • 通过 /metrics 端点暴露 Prometheus 格式的指标
  • • 包含业务相关的自定义指标(如请求速率、队列长度等)

自定义指标数据流:

应用 /metrics → Prometheus → Prometheus Adapter → Custom Metrics API → HPA Controller → Deployment

1.2.4 两种架构的对比分析

特性
资源指标架构
自定义指标架构
部署复杂度
简单(Metrics Server)
复杂(Prometheus 生态)
指标类型
CPU、内存
业务指标、基础设施指标
扩展性
有限
高度可扩展
资源消耗
低
中等到高
适用场景
通用应用、快速部署
复杂业务、精细化控制
学习成本
低
中等到高

1.2.5 混合架构模式

在生产环境中,通常采用混合架构模式,同时使用资源指标和自定义指标:

apiVersion:autoscaling/v2
kind:HorizontalPodAutoscaler
metadata:
name:mixed-metrics-hpa
spec:
scaleTargetRef:
apiVersion:apps/v1
kind:Deployment
name:web-app
minReplicas:2
maxReplicas:20
metrics:
# 资源指标
-type:Resource
resource:
name:cpu
target:
type:Utilization
averageUtilization:70
# 自定义指标
-type:Pods
pods:
metric:
name:http_requests_per_second
target:
type:AverageValue
averageValue:"100"

1.2.6 架构选择指导原则

选择资源指标架构的场景:

  • • ✅ 应用负载主要受 CPU/内存限制
  • • ✅ 需要快速部署和简单维护
  • • ✅ 团队对 Kubernetes 经验有限
  • • ✅ 成本敏感的环境

选择自定义指标架构的场景:

  • • ✅ 需要基于业务指标进行扩缩容
  • • ✅ 应用有复杂的性能特征
  • • ✅ 需要精细化的监控和告警
  • • ✅ 团队具备 Prometheus 运维能力

架构演进路径:

资源指标架构 → 混合架构 → 完全自定义指标架构

参考资料:

  1. 1. Kubernetes Metrics Server 官方文档:默认采集间隔为 15 秒

1.3 HPA 工作原理

1.3.1 控制循环机制

HPA 的工作流程遵循经典的控制循环模式,每 15 秒执行一次:

1. 指标收集 → 2. 目标计算 → 3. 决策制定 → 4. 执行操作
     ↑                                              ↓
     ←←←←←←←←←←←← 5. 状态反馈 ←←←←←←←←←←←←←←←←←←

详细步骤:

  1. 1. 指标收集:从 Metrics Server 或自定义指标源获取当前指标值
  2. 2. 目标计算:基于目标值计算期望的副本数
  3. 3. 决策制定:考虑扩缩容策略和稳定性窗口
  4. 4. 执行操作:更新目标资源的副本数
  5. 5. 状态反馈:监控扩缩容结果,为下次决策提供依据

1.3.2 核心算法详解

基础扩缩容算法:

期望副本数 = ceil(当前副本数 × (当前指标值 / 目标指标值))

算法参数说明:

  • • 当前副本数:当前正在运行的 Pod 实例数量
  • • 当前指标值:从 Metrics API 获取的实时指标值
  • • 目标指标值:HPA 配置中设定的期望指标阈值
  • • ceil()函数:向上取整,确保副本数为正整数

实际计算案例:

场景:CPU 利用率扩容
- 当前副本数:3
- 当前 CPU 利用率:85%
- 目标 CPU 利用率:70%

计算过程:
期望副本数 = ceil(3 × (85 / 70)) = ceil(3 × 1.214) = ceil(3.642) = 4

结果:扩容 1 个副本(3 → 4)

1.3.3 多指标决策算法

当配置多个指标时,HPA 采用最大值策略确保系统稳定性:

最终副本数 = max(指标1计算结果, 指标2计算结果, ..., 指标N计算结果)

多指标计算示例:

场景:
- 当前副本数:4
- CPU 指标:当前 60%,目标 70% → 期望副本数 = ceil(4 × 60/70) = 4
- 请求指标:当前 450 req/s,目标 100 req/s per pod → 期望副本数 = ceil(4 × 450/400) = 5

最终结果:max(4, 5) = 5 副本

1.3.4 安全机制与边界控制

1. 容忍度机制:

HPA 使用容忍度避免微小波动引起的频繁扩缩容:

默认容忍度:10%

扩容条件:当前指标值 > 目标指标值 × (1 + 容忍度)
缩容条件:当前指标值 < 目标指标值 × (1 - 容忍度)

示例:
- 目标 CPU 利用率:70%
- 扩容触发点:70% × 1.1 = 77%
- 缩容触发点:70% × 0.9 = 63%

2. 扩缩容速率限制:

扩容限制:
- 单次扩容不超过当前副本数的 2 倍
- 扩容冷却期:3 分钟内不再扩容

缩容限制:
- 单次缩容不超过当前副本数的 50%
- 缩容冷却期:5 分钟内不再缩容

3. 边界条件控制:

spec:
minReplicas:2# 最小副本数
maxReplicas:10# 最大副本数

1.4 指标体系分类

1.4.1 资源指标 (Resource Metrics)

资源指标是 HPA 最基础的扩缩容依据,通过 Metrics Server 收集 Pod 的 CPU 和内存使用情况。

基于 Pod 的 CPU 和内存使用率:

metrics:
-type:Resource
resource:
name:cpu
target:
type:Utilization
averageUtilization:70# 70% CPU 利用率阈值
-type:Resource
resource:
name:memory
target:
type:Utilization
averageUtilization:80# 80% 内存利用率阈值

适用场景:

  • • 计算密集型应用
  • • 内存密集型服务
  • • 通用 Web 应用

1.4.2 Pod 级别自定义指标 (Pods Metrics)

基于每个 Pod 的业务指标:

metrics:
-type:Pods
pods:
metric:
name:http_requests_per_second
target:
type:AverageValue
averageValue:"100"# 每个 Pod 100 req/s

适用场景:

  • • 高并发 API 服务
  • • 消息队列处理
  • • 实时数据处理

1.4.3 对象级别自定义指标 (Object Metrics)

基于 Kubernetes 对象的指标:

metrics:
-type:Object
object:
metric:
name:http_requests_per_second_by_app
describedObject:
apiVersion:v1
kind:Namespace
name:production
target:
type:Value
value:"1000"# 命名空间级别 1000 req/s

适用场景:

  • • 多租户应用
  • • 服务网格环境
  • • 跨服务协调扩容

第二部分:安装与配置

2.1 环境准备与兼容性检查

2.1.1 系统要求

  • • Kubernetes 版本:1.23+ (推荐 1.25+)
  • • Metrics Server:v0.6.4+
  • • Prometheus:v2.30.0+
  • • Prometheus Adapter:v0.12.0+

2.1.2 验证集群状态

# 检查 Kubernetes 版本
kubectl version --short

# 验证 Metrics Server 状态
kubectl get deployment metrics-server -n kube-system

# 检查 API 服务可用性
kubectl get apiservice v1beta1.metrics.k8s.io

2.2 Metrics Server 部署

2.2.1 快速部署

# 部署 Metrics Server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# 验证部署状态
kubectl get pods -n kube-system -l k8s-app=metrics-server

2.2.2 配置调整(如需要)

# metrics-server-config.yaml
apiVersion:apps/v1
kind:Deployment
metadata:
name:metrics-server
namespace:kube-system
spec:
template:
spec:
containers:
-name:metrics-server
args:
---cert-dir=/tmp
---secure-port=4443
---kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
---kubelet-use-node-status-port
---metric-resolution=15s
---kubelet-insecure-tls# 仅用于测试环境

2.3 Prometheus 监控栈部署

2.3.1 使用 Helm 快速部署

# 添加 Prometheus 社区 Helm 仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# 部署 kube-prometheus-stack
helm install prometheus prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace \
  --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false \
  --set prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues=false

2.3.2 验证 Prometheus 部署

# 检查 Prometheus 组件状态
kubectl get pods -n monitoring

# 验证 Prometheus 服务
kubectl get svc -n monitoring prometheus-kube-prometheus-prometheus

2.4 Prometheus Adapter 配置

2.4.1 部署 Prometheus Adapter

# 使用 Helm 部署
helm install prometheus-adapter prometheus-community/prometheus-adapter \
  --namespace monitoring \
  --set prometheus.url=http://prometheus-kube-prometheus-prometheus.monitoring.svc \
  --set prometheus.port=9090

2.4.2 自定义指标配置

# prometheus-adapter-config.yaml
apiVersion:v1
kind:ConfigMap
metadata:
name:adapter-config
namespace:monitoring
data:
config.yaml:|
    rules:
    - seriesQuery: 'http_requests_per_second{namespace!="",pod!=""}'
      resources:
        overrides:
          namespace: {resource: "namespace"}
          pod: {resource: "pod"}
      name:
        matches: "^(.*)_per_second"
        as: "${1}_per_second"
      metricsQuery: 'sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)'

-seriesQuery:'http_request_duration_seconds{namespace!="",pod!=""}'
resources:
overrides:
namespace: {resource:"namespace"}
pod: {resource:"pod"}
name:
matches:"^(.*)_duration_seconds"
as:"${1}_duration"
metricsQuery:'avg(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)'

2.5 验证 HPA 环境

2.5.1 检查 Custom Metrics API

# 验证自定义指标 API 可用性
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | jq .

# 检查可用的自定义指标
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests_per_second" | jq .

2.5.2 基础 HPA 功能测试

# 创建测试 Deployment
kubectl create deployment test-app --image=nginx --replicas=1

# 创建基础 HPA
kubectl autoscale deployment test-app --cpu-percent=50 --min=1 --max=10

# 验证 HPA 状态
kubectl get hpa test-app
kubectl describe hpa test-app

第三部分:基于 Spring Boot App 的实践

3.1 Spring Boot 应用开发

3.1.1 项目结构与依赖

创建一个支持 HPA 的 Spring Boot 微服务:

<!-- pom.xml -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
</dependencies>

3.1.2 业务指标暴露

// MetricsController.java
@RestController
@RequestMapping("/api")
publicclassMetricsController {

privatefinal MeterRegistry meterRegistry;
privatefinal Counter requestCounter;
privatefinal Timer requestTimer;

publicMetricsController(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.requestCounter = Counter.builder("http_requests_total")
            .description("Total HTTP requests")
            .register(meterRegistry);
this.requestTimer = Timer.builder("http_request_duration_seconds")
            .description("HTTP request duration")
            .register(meterRegistry);
    }

@GetMapping("/process")
public ResponseEntity<String> processRequest() {
return requestTimer.recordCallable(() -> {
            requestCounter.increment();

// 模拟业务处理
try {
                Thread.sleep(100 + (int)(Math.random() * 200));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
return ResponseEntity.status(500).body("Request interrupted");
            }

return ResponseEntity.ok("Request processed successfully");
        });
    }

@GetMapping("/health")
public ResponseEntity<Map<String, Object>> health() {
        Map<String, Object> status = newHashMap<>();
        status.put("status", "UP");
        status.put("timestamp", System.currentTimeMillis());
        status.put("requests_per_second", getCurrentRequestsPerSecond());
return ResponseEntity.ok(status);
    }

privatedoublegetCurrentRequestsPerSecond() {
// 计算每秒请求数
return meterRegistry.get("http_requests_total").counter().count() / 
               (System.currentTimeMillis() / 1000.0);
    }
}

#### 3.1.3 应用配置

```yaml
# application.yml
server:
  port: 8080

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      show-details: always
    metrics:
      enabled: true
    prometheus:
      enabled: true
  metrics:
    export:
      prometheus:
        enabled: true
    web:
      server:
        request:
          autotime:
            enabled: true

logging:
  level:
    com.example: INFO
    org.springframework.web: DEBUG

3.2 容器化与 Kubernetes 部署

3.2.1 Dockerfile 优化

# Dockerfile
FROM openjdk:17-jre-slim

# 创建应用目录
WORKDIR /app

# 复制应用 JAR
COPY target/spring-boot-hpa-demo-*.jar app.jar

# 设置 JVM 参数以支持容器环境
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"

# 暴露端口
EXPOSE8080

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
  CMD curl -f http://localhost:8080/actuator/health || exit 1


# 启动应用
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

3.2.2 Kubernetes 部署配置

# deployment.yaml
apiVersion:apps/v1
kind:Deployment
metadata:
name:spring-boot-hpa-demo
namespace:default
labels:
app:spring-boot-hpa-demo
spec:
replicas:2
selector:
matchLabels:
app:spring-boot-hpa-demo
template:
metadata:
labels:
app:spring-boot-hpa-demo
annotations:
prometheus.io/scrape:"true"
prometheus.io/port:"8080"
prometheus.io/path:"/actuator/prometheus"
spec:
containers:
-name:app
image:spring-boot-hpa-demo:latest
ports:
-containerPort:8080
name:http
resources:
requests:
cpu:100m
memory:256Mi
limits:
cpu:500m
memory:512Mi
livenessProbe:
httpGet:
path:/actuator/health
port:8080
initialDelaySeconds:60
periodSeconds:30
readinessProbe:
httpGet:
path:/actuator/health
port:8080
initialDelaySeconds:30
periodSeconds:10
env:
-name:SPRING_PROFILES_ACTIVE
value:"production"

---
apiVersion:v1
kind:Service
metadata:
name:spring-boot-hpa-demo
namespace:default
labels:
app:spring-boot-hpa-demo
spec:
selector:
app:spring-boot-hpa-demo
ports:
-port:80
targetPort:8080
name:http
type:ClusterIP

3.3 HPA 配置与测试

3.3.1 多指标 HPA 配置

# hpa-multi-metrics.yaml
apiVersion:autoscaling/v2
kind:HorizontalPodAutoscaler
metadata:
name:spring-boot-hpa-demo
namespace:default
spec:
scaleTargetRef:
apiVersion:apps/v1
kind:Deployment
name:spring-boot-hpa-demo
minReplicas:2
maxReplicas:20
metrics:
# CPU 利用率指标
-type:Resource
resource:
name:cpu
target:
type:Utilization
averageUtilization:70

# 内存利用率指标
-type:Resource
resource:
name:memory
target:
type:Utilization
averageUtilization:80

# 自定义指标:每秒请求数
-type:Pods
pods:
metric:
name:http_requests_per_second
target:
type:AverageValue
averageValue:"100"

# 自定义指标:请求响应时间
-type:Pods
pods:
metric:
name:http_request_duration_seconds
target:
type:AverageValue
averageValue:"200m"# 200ms

behavior:
scaleUp:
stabilizationWindowSeconds:60
policies:
-type:Percent
value:100
periodSeconds:60
-type:Pods
value:2
periodSeconds:60
selectPolicy:Max
scaleDown:
stabilizationWindowSeconds:300
policies:
-type:Percent
value:50
periodSeconds:60
selectPolicy:Min

3.3.2 负载测试脚本

#!/bin/bash
# load-test.sh

APP_URL="http://spring-boot-hpa-demo.default.svc.cluster.local"
DURATION=600  # 10 分钟测试
CONCURRENT_USERS=50

echo"开始负载测试..."
echo"目标 URL: $APP_URL"
echo"测试时长: $DURATION 秒"
echo"并发用户: $CONCURRENT_USERS"

# 使用 Apache Bench 进行负载测试
ab -n 100000 -c $CONCURRENT_USERS -t $DURATION"$APP_URL/api/process"

# 或使用 wrk 进行更精确的负载测试
# wrk -t12 -c$CONCURRENT_USERS -d${DURATION}s --latency "$APP_URL/api/process"

echo"负载测试完成"

3.3.3 监控 HPA 行为

# 实时监控 HPA 状态
watch -n 5 'kubectl get hpa spring-boot-hpa-demo'

# 查看 HPA 详细信息
kubectl describe hpa spring-boot-hpa-demo

# 监控 Pod 扩缩容
watch -n 5 'kubectl get pods -l app=spring-boot-hpa-demo'

# 查看指标值
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests_per_second" | jq .

3.4 实践结果分析

3.4.1 扩缩容行为观察

通过负载测试,可以观察到以下 HPA 行为:

  1. 1. 扩容阶段:
  • • 负载增加时,CPU 和请求指标同时上升
  • • HPA 根据最大值策略选择最激进的扩容建议
  • • Pod 数量从 2 个逐步扩展到 8-12 个
  • 2. 稳定阶段:
    • • 系统达到平衡状态,指标稳定在目标值附近
    • • HPA 停止扩容,维持当前副本数
  • 3. 缩容阶段:
    • • 负载减少后,HPA 等待稳定窗口期(5分钟)
    • • 逐步缩减 Pod 数量,避免过度缩容

    3.4.2 性能指标总结

    指标类型
    目标值
    实际表现
    扩缩容效果
    CPU 利用率
    70%
    65-75%
    稳定
    内存利用率
    80%
    60-70%
    良好
    请求速率
    100 req/s/pod
    95-105 req/s/pod
    精确
    响应时间
    200ms
    150-250ms
    可接受

    总结

    本文通过理论阐述、环境配置和实际案例,全面展示了 Kubernetes HPA 的工作原理和实践应用。通过基于 Spring Boot 的完整示例,验证了 HPA 在真实业务场景中的有效性和可靠性。

    核心收获:

    1. 1. HPA 提供了强大的自动扩缩容能力,能够根据多种指标智能调整应用规模
    2. 2. 合理的指标选择和阈值设置是 HPA 成功的关键
    3. 3. 监控和观测是优化 HPA 性能的重要手段

    最佳实践建议:

    1. 1. 从简单的 CPU/内存指标开始,逐步引入业务指标
    2. 2. 设置合理的扩缩容策略,避免频繁波动
    3. 3. 建立完善的监控体系,持续优化 HPA 配置

    参考文献

    1. 1. Kubernetes HPA 官方文档
    2. 2. Prometheus Adapter 配置指南
    3. 3. Spring Boot Actuator 监控指南