Kubernetes - HPA(水平 Pod 自动扩缩容)的部署与配置
大家好欢迎来到我的技术博客 在这里我会分享学习笔记、实战经验与技术思考力求用简单的方式讲清楚复杂的问题。 本文将围绕Kubernetes这个话题展开希望能为你带来一些启发或实用的参考。 无论你是刚入门的新手还是正在进阶的开发者希望你都能有所收获文章目录Kubernetes - HPA水平 Pod 自动扩缩容的部署与配置 一、HPA 基础概念与工作原理 1.1 什么是水平扩缩容1.2 HPA 的核心组件1.3 HPA 的算法原理1.4 HPA 支持的指标类型二、环境准备部署 Metrics Server ️2.1 检查是否已安装2.2 安装 Metrics ServerKubernetes 1.20三、Java 微服务示例构建可扩缩的订单服务 3.1 项目结构3.2 Maven 依赖pom.xml3.3 主启动类3.4 控制器模拟高负载接口3.5 配置文件application.yml3.6 构建 Docker 镜像四、部署服务 HPA实战第一弹 4.1 部署 Deployment4.2 创建 Service 暴露端口4.3 配置 HPA基于 CPU 使用率4.4 部署资源4.5 验证 HPA 状态五、压力测试见证 HPA 的“智能”响应 5.1 启动压测工具5.2 实时监控扩缩容5.3 停止压测观察缩容六、进阶实战基于自定义指标的 HPAPrometheus AdapterKubernetes - HPA水平 Pod 自动扩缩容的部署与配置 在现代云原生架构中应用的弹性与高可用性是系统稳定运行的核心诉求。随着微服务架构的普及服务负载呈现出显著的波动性白天流量高峰、促销活动爆发、定时任务集中触发……这些场景若依赖人工干预扩缩容不仅效率低下更可能引发服务雪崩或资源浪费。Kubernetes 的水平 Pod 自动扩缩容Horizontal Pod Autoscaler简称 HPA正是为解决这一痛点而生的自动化利器。HPA 能够根据预设的指标如 CPU 使用率、内存占用、自定义 Prometheus 指标等动态调整应用的 Pod 副本数量实现“流量多则多启流量少则少停”的智能调度。它不依赖任何外部调度器完全集成于 Kubernetes 控制平面是 DevOps 团队实现“无人值守运维”的关键组件之一。本文将带你从零开始系统掌握 HPA 的原理、配置、实战与调优技巧。我们将结合真实 Java 微服务项目模拟高并发场景观察 HPA 如何精准响应负载变化并深入分析其底层工作机制。你将学会如何配置基于自定义指标的 HPA如何避免常见陷阱如何与 Metrics Server、Prometheus、KEDA 等组件协同工作最终构建一个真正“懂流量”的弹性服务架构。一、HPA 基础概念与工作原理 在深入配置之前我们必须先理解 HPA 的核心逻辑。它不是一个“魔法按钮”而是一个基于反馈控制理论的闭环系统。1.1 什么是水平扩缩容Kubernetes 中的扩缩容分为两类垂直扩缩容VPA改变单个 Pod 的资源请求如 CPU 从 500m → 1000m需重启 Pod。水平扩缩容HPA增减 Pod 副本数量不改变单个 Pod 的资源配置无需重启。HPA 的优势在于快速、无损、可并行。当流量激增时它能秒级新增 5 个 Pod 分担压力当流量回落又能优雅缩容节省成本。 想象一下你的电商网站在“双11”凌晨 1 点订单量从每秒 10 笔飙升到 500 笔。HPA 就像一位敏锐的经理看到排队人数暴涨立刻多开 10 个收银窗口而不需要你去重新采购收银机垂直扩缩容。1.2 HPA 的核心组件HPA 的运行依赖三个关键组件组件作用Metrics Server集群内指标采集器负责收集 CPU、内存等标准指标由 kubelet 通过 Summary API 上报HPA ControllerKubernetes 控制平面中的核心控制器持续轮询 Metrics Server 获取指标计算所需副本数Deployment / StatefulSetHPA 的操作对象HPA 通过修改其.spec.replicas字段实现扩缩容⚠️ 注意如果你的集群未安装 Metrics ServerHPA 将无法工作会提示unable to get metrics for resource cpu: no metrics returned。1.3 HPA 的算法原理HPA 的扩缩容逻辑基于一个简单但强大的公式desiredReplicas ceil[currentReplicas × (currentMetricValue / desiredMetricValue)]举个例子当前副本数3当前 CPU 使用率75%目标 CPU 使用率50%desiredReplicas ceil[3 × (75 / 50)] ceil[4.5] 5HPA 会将副本数从 3 扩容到 5。这个算法看似简单但背后有诸多保护机制冷却时间扩缩容后 5 分钟内不再响应同类型指标变化避免震荡。最小/最大副本限制防止误配置导致“扩到 1000 个 Pod”或“缩到 0 个”。延迟采样默认每 15 秒采集一次指标避免瞬时抖动误触发。 更多算法细节可参考官方文档https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/1.4 HPA 支持的指标类型指标类型描述适用场景ResourceCPU、内存最常见适合大多数无状态服务Pods自定义 Pod 级别指标如每秒请求数需要自定义指标适配器如 Prometheus AdapterExternal集群外指标如 Kafka 消费延迟、RDS 连接数适合与外部系统强耦合的服务 在本篇中我们将重点使用ResourceCPU和Pods自定义 HTTP QPS两种指标进行实战。二、环境准备部署 Metrics Server ️在部署 HPA 前必须确保集群已安装Metrics Server。它是一个轻量级聚合器负责从每个节点的 kubelet 收集资源使用数据。2.1 检查是否已安装kubectl get pods-nkube-system|grepmetrics-server若无输出说明未安装。2.2 安装 Metrics ServerKubernetes 1.20# metrics-server.yamlapiVersion:v1kind:ServiceAccountmetadata:name:metrics-servernamespace:kube-system---apiVersion:apps/v1kind:Deploymentmetadata:name:metrics-servernamespace:kube-systemlabels:k8s-app:metrics-serverspec:selector:matchLabels:k8s-app:metrics-servertemplate:metadata:name:metrics-serverlabels:k8s-app:metrics-serverspec:serviceAccountName:metrics-servervolumes:-name:tmp-diremptyDir:{}containers:-name:metrics-serverimage:k8s.gcr.io/metrics-server/metrics-server:v0.6.5args:---cert-dir/tmp---secure-port4443---kubelet-insecure-tls---kubelet-preferred-address-typesInternalIP,ExternalIP,Hostname---metric-resolution15sports:-containerPort:4443name:httpsvolumeMounts:-name:tmp-dirmountPath:/tmp---apiVersion:v1kind:Servicemetadata:name:metrics-servernamespace:kube-systemlabels:k8s-app:metrics-serverspec:ports:-port:443protocol:TCPtargetPort:httpsselector:k8s-app:metrics-server---apiVersion:rbac.authorization.k8s.io/v1kind:ClusterRolemetadata:name:system:metrics-serverrules:-apiGroups:-resources:-pods-nodes-namespacesverbs:-get-list-watch-apiGroups:-extensionsresources:-deploymentsverbs:-get-list-watch---apiVersion:rbac.authorization.k8s.io/v1kind:ClusterRoleBindingmetadata:name:system:metrics-serverroleRef:apiGroup:rbac.authorization.k8s.iokind:ClusterRolename:system:metrics-serversubjects:-kind:ServiceAccountname:metrics-servernamespace:kube-system---apiVersion:apiregistration.k8s.io/v1kind:APIServicemetadata:name:v1beta1.metrics.k8s.iospec:service:name:metrics-servernamespace:kube-systemgroup:metrics.k8s.ioversion:v1beta1insecureSkipTLSVerify:truegroupPriorityMinimum:100versionPriority:100部署kubectl apply-fmetrics-server.yaml验证是否就绪kubectl get apiservices|grepmetrics.k8s.io# 输出应为v1beta1.metrics.k8s.io True 3m检查指标是否可用kubectltopnodes kubectltoppods-A如果能正常输出 CPU 和内存使用情况说明 Metrics Server 已成功部署 若使用云厂商托管集群如 EKS、GKE、ACK通常默认已安装 Metrics Server无需手动部署。三、Java 微服务示例构建可扩缩的订单服务 现在我们来构建一个真实的 Java 微服务用于模拟负载波动场景。3.1 项目结构我们使用 Spring Boot 构建一个简单的订单服务提供/order/create接口该接口会模拟 100~500ms 的处理延迟以制造 CPU 负载。order-service/ ├── src/ │ └── main/ │ ├── java/com/example/orderservice/ │ │ ├── OrderServiceApplication.java │ │ └── controller/ │ │ └── OrderController.java │ └── resources/ │ └── application.yml └── pom.xml3.2 Maven 依赖pom.xml?xml version1.0 encodingUTF-8?projectxmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.example/groupIdartifactIdorder-service/artifactIdversion1.0.0/versionnameorder-service/namepackagingjar/packagingparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion3.1.5/versionrelativePath//parentpropertiesjava.version17/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-validation/artifactId/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project3.3 主启动类// OrderServiceApplication.javapackagecom.example.orderservice;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplicationpublicclassOrderServiceApplication{publicstaticvoidmain(String[]args){SpringApplication.run(OrderServiceApplication.class,args);}}3.4 控制器模拟高负载接口// OrderController.javapackagecom.example.orderservice.controller;importorg.springframework.web.bind.annotation.*;importjava.util.concurrent.ThreadLocalRandom;importjava.util.concurrent.TimeUnit;RestControllerRequestMapping(/api/order)publicclassOrderController{PostMapping(/create)publicStringcreateOrder(RequestParamStringuserId,RequestParamStringproductId){// 模拟业务处理随机延迟 100~500ms制造 CPU 负载intdelayMsThreadLocalRandom.current().nextInt(100,501);try{TimeUnit.MILLISECONDS.sleep(delayMs);}catch(InterruptedExceptione){Thread.currentThread().interrupt();returnError: Interrupted;}// 模拟返回结果returnString.format(Order created for user %s, product %s (delay: %dms),userId,productId,delayMs);}// 健康检查端点GetMapping(/health)publicStringhealth(){returnOK;}}3.5 配置文件application.ymlserver:port:8080spring:application:name:order-servicemanagement:endpoints:web:exposure:include:health,info,prometheusendpoint:health:show-details:always⚠️ 注意我们启用了 Prometheus 指标暴露为后续自定义指标 HPA 做准备。3.6 构建 Docker 镜像创建DockerfileFROM eclipse-temurin:17-jre-slim WORKDIR /app COPY target/order-service-1.0.0.jar app.jar EXPOSE 8080 ENTRYPOINT [java, -Djava.security.egdfile:/dev/./urandom, -jar, /app/app.jar]构建并推送假设你有私有镜像仓库dockerbuild-tregistry.example.com/order-service:v1.dockerpush registry.example.com/order-service:v1 实际生产中建议使用多阶段构建、非 root 用户、镜像扫描等安全实践此处为简化演示。四、部署服务 HPA实战第一弹 现在我们部署服务并为其配置基于 CPU 的 HPA。4.1 部署 Deployment# deployment.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:order-servicelabels:app:order-servicespec:replicas:2selector:matchLabels:app:order-servicetemplate:metadata:labels:app:order-servicespec:containers:-name:order-serviceimage:registry.example.com/order-service:v1ports:-containerPort:8080resources:requests:cpu:200mmemory:256Milimits:cpu:500mmemory:512MilivenessProbe:httpGet:path:/healthport:8080initialDelaySeconds:30periodSeconds:10readinessProbe:httpGet:path:/healthport:8080initialDelaySeconds:5periodSeconds:54.2 创建 Service 暴露端口# service.yamlapiVersion:v1kind:Servicemetadata:name:order-servicespec:selector:app:order-serviceports:-protocol:TCPport:80targetPort:8080type:ClusterIP4.3 配置 HPA基于 CPU 使用率# hpa-cpu.yamlapiVersion:autoscaling/v2kind:HorizontalPodAutoscalermetadata:name:order-service-hpaspec:scaleTargetRef:apiVersion:apps/v1kind:Deploymentname:order-serviceminReplicas:2maxReplicas:10metrics:-type:Resourceresource:name:cputarget:type:UtilizationaverageUtilization:60behavior:scaleUp:stabilizationWindowSeconds:60policies:-type:Percentvalue:100periodSeconds:15scaleDown:stabilizationWindowSeconds:300policies:-type:Percentvalue:10periodSeconds:154.4 部署资源kubectl apply-fdeployment.yaml kubectl apply-fservice.yaml kubectl apply-fhpa-cpu.yaml4.5 验证 HPA 状态kubectl get hpa# 输出示例# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE# order-service-hpa Deployment/order-service 0%/60% 2 10 2 2mkubectl describe hpa order-service-hpa你会看到类似输出Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale True SucceededGetScale the HPA controller was able to get the targets current scale ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request) ScalingLimited False DesiredWithinRange the desired count is within the acceptable range✅ 关键点ScalingActive为True表示 HPA 已正常工作。五、压力测试见证 HPA 的“智能”响应 现在我们模拟真实流量观察 HPA 如何自动扩容。5.1 启动压测工具我们使用heyGo 编写的 HTTP 压测工具向服务发送高并发请求hey-z5m-c50-q10http://order-service/api/order/create?userId123productId456参数说明-z 5m持续 5 分钟-c 50并发 50 个客户端-q 10每秒 10 个请求QPS10如果你没有hey可用wrk、ab或 Python 脚本替代。推荐安装brew install heymacOS或从 https://github.com/rakyll/hey 下载二进制。5.2 实时监控扩缩容打开另一个终端持续观察watch-n2kubectl get pods -l apporder-service kubectl get hpa order-service-hpa你会看到类似输出Every 2.0s: kubectl get pods -l apporder-service kubectl get hpa order-service-hpa NAME READY STATUS RESTARTS AGE order-service-7b8c9d6f5-2x4m7 1/1 Running 0 12m order-service-7b8c9d6f5-9z9p2 1/1 Running 0 12m order-service-7b8c9d6f5-b4n6c 1/1 Running 0 2m order-service-7b8c9d6f5-f8m7q 1/1 Running 0 1m order-service-7b8c9d6f5-g5t9x 1/1 Running 0 1m NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE order-service-hpa Deployment/order-service 78%/60% 2 10 5 15m现象分析初始副本2压测开始后 1~2 分钟CPU 使用率突破 60%HPA 触发扩容2 → 3 → 55 分钟后副本稳定在 5~7 之间5.3 停止压测观察缩容停止hey命令后继续观察NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE order-service-hpa Deployment/order-service 25%/60% 2 10 5 20mCPU 使用率下降但副本数不会立即减少。这是因为 HPA 有缩容冷却期默认 5 分钟避免“抖动”。5 分钟后副本数将逐步回落至 2。为什么缩容比扩容慢缩容太快可能导致服务雪崩如突然缩到 1 个 Pod流量突增业务容忍度用户对“响应慢”比“服务不可用”更宽容成本考量启动新 Pod 有冷启动开销缩容节省的是持续成本六、进阶实战基于自定义指标的 HPAPrometheus AdapterCPU 指标虽然通用但有时不够精准。比如你的服务是消息队列消费者瓶颈在 Kafka 消费延迟你的服务是 API 网关瓶颈在每秒请求数QPS你的服务是数据库代理瓶颈在连接池使用率此时基于 Pod 的自定义指标Pods更合适。 感谢你读到这里 技术之路没有捷径但每一次阅读、思考和实践都在悄悄拉近你与目标的距离。 如果本文对你有帮助不妨 点赞、收藏、分享给更多需要的朋友 欢迎在评论区留下你的想法、疑问或建议我会一一回复我们一起交流、共同成长 关注我不错过下一篇干货我们下期再见✨