首页 / 资讯中心 / 文章详情

ASK Serverless Kubernetes弹性伸缩实战:从HPA配置到降本增效

ASK Serverless Kubernetes弹性伸缩实战:从HPA配置到降本增效 ★ FEATURED ARTICLE
干了这么多年容器运维以前最烦的就是半夜收到告警说节点资源不够。手动加机器慢半拍提前备机器又烧钱尤其碰上流量像心电图一样的业务扩缩容那点事能把人折腾得够呛。后来我把服务迁到阿里云 ASKServerless Kubernetes上弹性伸缩这件事才算真正省心了。这篇文章就是一次 ASK 集群从创建、部署到弹性伸缩配置的完整实战记录不搞虚的全是能直接抄作业的步骤和参数顺便把我在这个过程中踩过的坑也一起抖出来。不管你是刚接触容器的小白还是已经被自建 K8s 节点维护搞烦了的老手这篇都能给你一个切实可行的降本增效方案。1. ASK 的定位与弹性伸缩的整体设计思路1.1 ASK 和标准 Kubernetes 到底差在哪先说清楚 ASK 是个什么东西。它是阿里云上的 Serverless Kubernetes 服务你不需要管理任何 worker 节点只需要创建集群然后直接部署 Pod 就行了。底层那套 ECS 实例、操作系统补丁、节点健康检查之类的脏活累活全由平台替你做。普通 Kubernetes 集群里Pod 要跑起来得先有节点节点上得有足够的内存和 CPU。如果节点资源不足扩容要先买 ECS 或已有资源池里有富余这个流程少则几分钟多则十几分钟赶上是业务高峰就非常被动。ASK 的逻辑是反过来的你提交一个 DeploymentPod 直接通过底层弹性资源调度起来按 Pod 的规格和运行时长计费不用关心调度到哪个物理节点——说白了它就是“按 Pod 用量付费 免运维节点”的 K8s。这个差别对弹性伸缩影响非常大。传统 K8s 的伸缩要分成节点伸缩和 Pod 伸缩两层Pod 扩容完了还得看节点够不够不够要等节点池伸缩组启动新机器。而 ASK 天然把节点层抹平了扩容就是提交多少个 Pod 副本的问题底层资源由平台保障伸缩链路上少了一环速度自然就上来了。1.2 为什么 ASK 天生适合做弹性伸缩我之所以把弹性伸缩实战放在 ASK 上来讲核心原因是它的计费模型和资源模型完全匹配了弹性场景的需求。按 Pod 维度计费意味着低谷期可以缩到很少的副本甚至缩到 0高峰期再迅速拉起来。这种“用多少付多少”的方式放在弹性伸缩的语境下是真正的降本。另外一个原因在于它和阿里云的监控体系是深度打通的。ASK 集群里可以直接使用 metrics-server 采集资源指标HPAHorizontal Pod Autoscaler开箱即用。你不需要额外搭建 Prometheus 来采集节点层面的数据Pod 的 CPU、内存指标天然上报配上阿里云的云监控也能看到控制台的伸缩记录。从设计思路上讲我们的目标很明确让无状态业务服务具备根据 CPU、内存、QPS 等指标自动扩缩容的能力让有固定周期峰值的业务比如每天早上九点的报表任务使用定时伸缩来提前扩容让低频或批处理类的任务能够缩到 0彻底消除闲置成本。这三条目标分别对应了 ASK 的 HPA 能力、CronHPA 能力和缩容到 0 的能力。下面每一章都会把对应的配置过程拆开细讲。2. ASK 集群创建与部署前的关键准备2.1 账号开通与集群创建的基础步骤创建 ASK 集群的入口在阿里云容器服务 ACK 控制台里。登录控制台后在“集群”页面选择“Serverless 集群”然后填写集群名称、选择地域、配置 VPC 和交换机基本上就能完成创建。这里有几个细节值得注意。地域和可用区如果你的业务同时用了阿里云 RDS、SLB 等产品集群一定要和这些产品创建在同一地域最好能在同一可用区因为跨可用区访问 RDS 会有额外的延迟虽然通常只有几毫秒但对于高并发接口来说累计影响不可忽略。我踩过一次跨地域访问 RDS 的坑接口 P99 延迟直接涨了 20%。VPC 规划如果是新建 VPC建议把 Pod 的网段和 VPC 的网段分开规划避免将来网段冲突导致无法和自建机房或其他云产品内网互通。后端的 RDS、Redis 通常也在同一个 VPC 里Pod 直接用内网地址访问它们是最稳妥的路径不用绕公网既安全又省流量费。系统盘与数据盘ASK 集群创建时不需要你关心节点规格但有一个选项要注意如果开启了“集群级镜像缓存”平台会为常用镜像做预热这个对冷启动有优化作用后面讲常见问题的时候我再展开。创建过程一般在一两分钟内完成比标准 K8s 集群动辄十到二十分钟的创建时间快很多效果立竿见影。2.2 连接集群与配置 kubectl 环境集群创建完成后下一步就是让本地 kubectl 能连上它。在集群详情页找到“连接信息”或“kubeconfig”入口下载对应的 kubeconfig 文件放到你本机的~/.kube/config位置或者通过KUBECONFIG环境变量指定路径。export KUBECONFIG/path/to/your-ask-kubeconfig kubectl get ns如果你配置过多个集群的 kubeconfig建议用kubectl config use-context切换当前上下文避免操作错了集群。我习惯把所有云厂商的 kubeconfig 放到一个目录里然后用KUBECONFIG一次性引用多个配置文件再用kubectl config get-contexts查看所有可用的上下文这样多集群管理会清晰很多。这里顺带提一个热词很多人在本机做 Java 开发时配置 Maven 阿里云仓库来加速依赖下载而部署到容器里会用到私有镜像仓库。ASK 默认集成了阿里云容器镜像服务 ACR建议把项目镜像推到 ACR 的私有仓库里因为 ASK 拉取同一账号下的 ACR 镜像时走的是内网链路速度快且不会产生公网流量费用。如果镜像在 Docker Hub 上拉取速度就会明显慢冷启动时间也会拉长。2.3 部署一个用于验证的示例应用为了后面验证弹性伸缩效果我在集群里先部署一个简单的 nginx 应用作为目标负载方便做压测和观察副本数量变化。apiVersion: apps/v1 kind: Deployment metadata: name: web-server-demo namespace: default spec: replicas: 2 selector: matchLabels: app: web-server-demo template: metadata: labels: app: web-server-demo spec: containers: - name: nginx image: nginx:1.24-alpine ports: - containerPort: 80 resources: requests: cpu: 250m memory: 256Mi limits: cpu: 500m memory: 512Mirequests这一节必须写否则后面配置 HPA 时指标不会生效——这是新手最容易踩的坑HPA 计算的是“当前副本的实际使用量除以每个副本的 request 值”不写 requests 等于没有分母。我见过不少同事把 HPA 配好了却不生效排查了半天发现是 Deployment 里的资源声明缺失这种低级错误非常耽误时间。部署完成之后再用kubectl get pod确认 Pod 都进入了 Running 状态。这个 nginx 服务后续会用到kubectl run临时压测工具来打流量对服务本身没有任何侵入。3. 弹性伸缩的核心配置实战3.1 基于指标的 HPACPU 与内存伸缩配置HPA 是 Kubernetes 官方的 Pod 水平伸缩机制。ASK 里默认启用 metrics-server所以直接用kubectl autoscale命令或者写 YAML 就能配置。我一般会写成 YAML 提交因为方便后续维护apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: web-server-demo-hpa namespace: default spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: web-server-demo minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80HPA 的扩容逻辑本质上是一个比例计算期望副本数 当前副本数 ×当前指标值 / 期望指标值。举个例子当前 4 个副本每个副本 CPU 使用率是 80%期望是 50%那么期望副本数就是 4 ×80% / 50%≈ 6.4向上取整为 7 个副本。注意 HPA 的默认行为是先以其中一个指标计算出来的较大副本数为准所以如果 CPU 和内存同时配置它会取更激进的那个值。在实际操作里CPU 的averageUtilization建议设置在 40% 到 60% 之间。设低了扩容太敏感Pod 数量频繁波动设高了则对突发流量的反应迟钝。我一般先用 50% 跑一个业务周期看伸缩记录再做微调。配置完成之后用kubectl get hpa可以看到当前的指标和期望副本数这个输出会在后续压测环节派上用场。3.2 应对固定高峰CronHPA 定时伸缩配置很多业务负载是有规律的比如每天早上 9 点到 11 点是高峰期或者月底有一波结算类任务。HPA 虽然能伸缩但它是对“已经发生的负载”做出反应扩容有几十秒的迟滞。对于这种可预见的峰值最好提前把容量准备好。阿里云 ASK 提供了 CronHPA 能力本质上就是在指定时间把 Deployment 的副本数调到预设值到时间再缩回来。我通常会把它和 HPA 配合使用CronHPA 保证高峰开始前副本数已经就位HPA 负责高峰期间根据实际负载继续扩或者高峰期启动后按需扩。CronHPA 配置示例apiVersion: autoscaling.alibabacloud.com/v1beta1 kind: CronHorizontalPodAutoscaler metadata: name: web-server-demo-cronhpa namespace: default spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: web-server-demo jobs: - name: scale-up-at-8 schedule: 0 0 8 * * * targetSize: 5 - name: scale-down-at-11 schedule: 0 0 11 * * * targetSize: 2schedule字段用的是标准 cron 表达式这里0 0 8 * * *表示每天早上 8 点整把副本调整到 5 个11 点再调回 2 个。如果你有更复杂的时序需求比如工作日和非工作日不同也可以多配几条规则CronHPA 会把它们全部纳入管理但要注意两条规则的执行时间不要重叠否则会出现预期外的副本数覆盖。我实际建议是定时伸缩的副本数不要设置得太死比如高峰期预测需要 5 个副本可以设成 4 到 6 之间留一点余量。因为 CronHPA 在设置 targetSize 时如果同时存在 HPA它和 HPA 的联动逻辑是“定时伸缩先设置基线HPA 在这个基线上继续扩”这个联动需要被正确理解。如果 HPA 的 minReplicas 设为 2CronHPA 高峰期设为 5那么高峰期过后 CronHPA 把副本缩回 2HPA 的 minReplicas 也正好是 2二者一致就不会打架。3.3 VPA 与 HPA 同时存在的协作机制这里再补充一个容易被忽略的组件VPAVertical Pod Autoscaler。VPA 和 HPA 解决的不是同一个问题——HPA 调整副本数VPA 调整单个 Pod 的 CPU/内存规格。在 ASK 集群里VPA 可以自动修改 Pod 的 requests 和 limits 值让每个 Pod 的资源规格贴合实际负载。理论来说VPA 和 HPA 不能同时作用在同一组指标上否则会互相干扰。VPA 改的是 Pod 的 request 值而 HPA 的分母就是 request分子不变、分母变了伸缩结果也会变两个控制器同时改来改去会引发振荡。实际项目中我建议的用法是无状态且负载波动大的业务优先使用 HPA副本数量和规格保持稳定负载稳定但有资源浪费的业务用 VPA 一次性调整到合适的 request/limit观察几天再固化配置VPA recommended 值可以作为手动调优的参考不一定非要让它处于自动模式我一般用Off模式配合kubectl get vpa -o yaml查看推荐值。3.4 缩容策略与优雅停机细节很多人都关心弹性伸缩怎么“扩”而忽略了“缩”才是最容易出问题的环节。HPA 默认 5 分钟才触发一次缩容这是为了防止负载抖动导致副本数频繁变化。想要缩短周期可以在 HPA 的behavior字段里配置scaleDown的stabilizationWindowSeconds。behavior: scaleDown: stabilizationWindowSeconds: 120 policies: - type: Pods value: 1 periodSeconds: 60 scaleUp: stabilizationWindowSeconds: 0 policies: - type: Percent value: 100 periodSeconds: 15这个配置的含义是缩容时稳定窗口期设为 120 秒即负载下降后至少要等两分钟且持续处于低水位才允许缩容扩容则没有稳定窗口并且允许最快以 100% 的步长在 15 秒内翻倍。如果你的业务有突发流量可以适当缩短scaleUp的周期但不要设成 0否则一个瞬时抖动就会把副本数推到最大值造成不必要的成本开销。Pod 被缩掉的时候还要注意优雅停机。每个 Pod 在被删除之前会收到 SIGTERM 信号然后等待容器里的进程自行结束如果进程处理完当前请求需要 10 秒而你的terminationGracePeriodSeconds只有默认的 30 秒倒还好但有些长连接业务处理完一个请求可能要 40 秒以上这个参数必须按业务实际调大。spec: terminationGracePeriodSeconds: 60还有一点很关键Pod 的preStop钩子。对 nginx 这类进程我一般让它在收到 SIGTERM 前先 sleep 一小会儿比如 5 秒好让 ingress 或 SLB 的摘流逻辑完成同时启动脚本里处理完剩余请求再退出。这样缩容就不会导致线上出现零星 5xx 错误。4. 突发流量验证与成本控制实操4.1 用压测模拟流量高峰观察 HPA 实际效果配置写好了不压测一遍你永远不知道它会不会真的按预期工作。我用kubectl run创建一个简单的压测 Pod对刚才部署的 nginx 服务发起并发请求当然你也可以直接在本机对 SLB 的 IP 压测但从集群内部发起压测可以避免走公网带宽的干扰数据更干净。kubectl run load-generator --imagebusybox --rm -it --restartNever \ -- sh -c while true; do wget -q -O /dev/null http://web-server-demo.default.svc.cluster.local; done这个命令会让一个容器的循环不断访问服务把 CPU 使用率拉上去。压测开始后我会另开一个终端执行kubectl get hpa -w观察 HPA 的输出。正常情况下指标会从 5% 一路涨到 60% 以上HPA 的副本数会跟着变化NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE web-server-demo-hpa Deployment/web-server-demo 72%/50% 2 10 7 3d如果命中扩容规则Pod 数量会在几十秒内从 2 个变为 7 个这个速度普通 K8s 很难做到因为 ASK 省掉了节点调度和初始化那一步。压测结束后随着 CPU 下降HPA 会等稳定窗口期过后再缩容不会一掉下来就立刻缩。4.2 缩容到 0 与低成本运行批处理任务的思路ASK 有一个非常大的优势是不使用的 Pod 可以直接缩到 0 副本这在标准 K8s 集群里很难做到因为节点在那里就是成本。但 ASK 按 Pod 计费所以如果业务是低频的批处理任务比如每天只有凌晨跑一次的报表任务完全可以把replicas设为 0然后用 CronJob 定时拉起 Pod 执行任务执行完自动释放。这种方式对应到弹性伸缩里其实是把“伸缩”做到了极致——不用的时间不跑跑的时间按秒计费。在阿里云 ACK 产品家族里ASK 的按 Pod 计费模式天然适合这种工作负载比起长期保留 ECS 节点能省下相当可观的固定成本。另外需要注意一个热词关联场景很多应用要连 RDS。如果任务只是每天跑一次RDS 那边连接数不用太高ASK Pod 缩到 0 时自然也不占连接数这对控制 RDS 的规格和成本也有帮助。我在做这个架构的时候把原来每天挂在 ECS 上的定时任务全部切到了 ASK 的 CronJob费用从一台机器的包月成本变成任务每次运行几毛钱差距肉眼可见。4.3 与 SLB、RDS、DNS 的打通细节在实际业务中Pod 通常不会直接暴露公网而是通过 SLB 做负载均衡。ASK 部署 Service 时如果类型选 LoadBalancer它会自动帮你创建 SLB并绑定 Pod 作为后端。这里有几个细节值得记一下SLB 后端配额ASK 的 SLB 后端服务器有配额上限如果 Pod 副本数缩容后远低于服务实例总数一般来说没有问题但如果副本数超过配额新增的 Pod 会加入失败表现为部分流量 5xx。建议提前计算好 maxReplicas 和 SLB 配额的匹配关系。会话保持如果业务依赖 Session需要到 SLB 上开启会话保持否则 HPA 扩容后流量会分散到新 Pod用户登录态丢失。DNS 解析Pod 访问其他服务时优先用服务名而不是 IP因为 IP 会随 Pod 重建而变化而服务名在集群内自动解析。另外如果你用自定义域名访问服务别忘了在 ASK 集群里配置 Ingress。ASK 支持 ALB Ingress 和 Nginx Ingress我用 ALB Ingress 比较多因为它能把负载均衡和弹性伸缩的联动做得更顺手比如按 QPS 或连接数配置伸缩指标兼容性也比传统 SLB Nginx Ingress 更好。5. 常见问题与排查实录5.1 HPA 配置了但始终不生效怎么办这是问得最多的问题。HPA 不生效第一步先看kubectl describe hpa里的事件信息。最常见的原因包括Deployment 里没有写 resources.requestsHPA 拿不到基准值事件里会提示 missing requestmetrics-server 没有部署或工作异常可以kubectl get apiservices | grep metrics检查指标收集正常但 HPA 计算出的期望副本数和当前一样属于配置太保守比如 CPU 阈值设了 90%平时负载根本到不了命名空间不对HPA 和 Deployment 不在同一个 namespace我见过有人把 HPA 创建在了 default 空间却想管 production 空间的 Deployment这自然不生效。另外注意 ASK 里默认 HPA 的指标刷新周期是 15 秒到 30 秒之间不是即时生效所以压测后等一分钟左右再观察数据属于正常现象不用急着怀疑配置。5.2 冷启动导致扩容后请求失败ASK 的弹性扩虽然快但镜像拉取和容器启动仍然需要时间。如果容器镜像体积很大比如带了一堆应用依赖的 Java 镜像扩容瞬间流量已经打过来了新 Pod 却还没拉完镜像这种错位会造成部分请求超时。解决方案我实际试下来比较靠谱的有三个优化镜像体积用多阶段构建把编译环境和运行环境分开JRE 基础镜像替代 JDK镜像能瘦身一半以上开启 DAG 镜像缓存如果确认用了 ACR可以在 ASK 集群配置镜像缓存平台会提前把镜像加载到本地缓存节点冷启动时间从几十秒降到 3 到 5 秒给新 Pod 预留就绪探针让新 Pod 完全启动后再接入流量虽然会稍微延后扩容生效时间但至少不会导致请求 5xx。readinessProbe: httpGet: path: /healthz port: 80 initialDelaySeconds: 5 periodSeconds: 55.3 CronHPA 和 HPA 同时配置后副本数混乱这类坑比较隐蔽。如果你同时创建了 CronHPA 和普通 HPA它们可能会对同一个 Deployment 的目标副本数有不同期望CronHPA 想缩到 2HPA 想扩到 7最后谁赢取决于控制器的更新顺序副本数会来回跳动像在拔河。阿里云对此的兼容方案是如果检测到 CronHPA 和 HPA 同时管理一个 DeploymentCronHPA 会尝试协调但最稳妥的做法还是在 CronHPA 触发期间让 HPA 的扩展逻辑以 CronHPA 设置的 targetSize 为基线。所以在配置时就该规划好高峰期 CronHPA 把副本基线调到 5HPA 的 minReplicas 也设为 5低谷期 CronHPA 把基线调回 2HPA 的 minReplicas 依然为 2两者始终对齐就不会出现“Cron 已经缩了HPA 因为负载还高又扩了”的内耗。5.4 常见问题速查表现象可能原因解决办法HPA 不显示指标metrics-server 未运行或 Deployment 缺 requests检查 apiservice补全资源声明扩容后请求 5xx镜像拉取慢 / 探针未就绪优化镜像体积开启 DAG 缓存配置 readinessProbeCronHPA 和 HPA 冲突二者目标不一致统一 minReplicas 和 CronHPA 的 targetSizePod 频繁重建资源 limit 过小导致 OOMKilled调高 limit或参考 VPA 推荐值缩容后仍有流量异常会话保持未开或优雅退出时间不够SLB 开启会话保持调大 terminationGracePeriodSeconds内网访问 RDS 超时集群与 RDS 地域或可用区不一致统一地域检查 VPC 与安全组白名单5.5 排查命令清单最后整理一份我每次排查 ASK 弹性伸缩问题时必用的命令清单直接复制到终端就能用# 查看 HPA 状态与事件 kubectl get hpa -n namespace kubectl describe hpa hpa-name -n namespace # 查看 Pod 资源使用 kubectl top pod -n namespace # 查看 Deployment 实时副本与镜像 kubectl get deployment deployment-name -n namespace -o wide # 查看 CronHPA 规则 kubectl get cronhpa -n namespace kubectl describe cronhpa cronhpa-name -n namespace # 查看节点/底层事件ASK 中主要是 Pod 事件 kubectl get events -n namespace --sort-by.lastTimestamp这些命令能覆盖九成以上的故障定位场景。遇到问题时先看事件再查资源请求最后确认伸缩目标的一致性99% 的问题都能找到根源。结尾这套方案上线后我最大的感受是弹性的瓶颈早就不是技术了而是你有没有把“节点”这两个字从脑子里扔掉。ASK 把节点层抽象掉之后扩缩容直接反应到 Pod 数量上配合 HPA、CronHPA 和按量计费原来那些半夜加机器、季度末对账单的日子算是彻底到头了。最后再分享一个小经验不要急着在生产环境一上来就配置最复杂的多指标 HPA。先从一个 Deployment、一个 CPU 指标开始把基础链路跑通观察一周的伸缩记录再逐步加内存指标、定时伸缩、缩容策略。弹性伸缩不是配置一次就完事它更像是一个需要持续观察和微调的过程每次调整之后记录一下副本数变化和成本曲线你会越来越懂自己业务的节奏。
阅读完成 · 觉得有帮助?
咨询建站