Kubernetes 自动伸缩与成本优化实战

2026-05-06 22:47 Kubernetes 自动伸缩与成本优化实战已关闭评论

Kubernetes 自动伸缩与成本优化实战:我踩过的坑和最终方案

结论:自动伸缩不是万能药,组合使用 HPAVPACluster Autoscaler 并配合成本监控,才能真正省钱又省心。

1. 为什么自动伸缩反而让成本飙升?

我接手过一个项目,团队已经配置了 HPA(水平 Pod 自动伸缩),但月底账单出来时,成本比预期高了 40%。分析后发现:

  • HPA 基于 CPU 使用率触发,但业务高峰只是短暂的,伸缩后 Pod 数量一直维持在高位
  • 没有设置最小/最大 Pod 限制,导致无限制扩容
  • 节点数没有自动缩减,Cluster Autoscaler 配置不当

核心教训:自动伸缩不是“自动省钱”,而是“自动调整资源”。省钱需要额外的策略。

2. 实战配置:HPA + VPA + Cluster Autoscaler 三件套

2.1 水平自动伸缩(HPA)—— 最基础也最容易出问题

我的典型配置:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 70
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300  # 5分钟稳定窗口
      policies:
      - type: Percent
        value: 50
        periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 60

踩坑点
- 只配 CPU 指标:内存突增时不会扩容,导致 OOM
- 稳定窗口太短:频繁扩缩容,Pod 重建开销大
- 缩容策略太激进:突然缩掉大量 Pod,影响用户体验

注意:behavior 字段是 v2 API 的关键,务必配置稳定窗口,避免“震荡”。

2.2 垂直自动伸缩(VPA)—— 小心重启

VPA 用于调整 Pod 的 CPU/内存请求和限制。我踩过的坑:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: web-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: web-app
  updatePolicy:
    updateMode: "Auto"  # 自动模式会导致 Pod 重启
  resourcePolicy:
    containerPolicies:
    - containerName: '*'
      minAllowed:
        cpu: 100m


![节点组配置:预留实例和Spot实例混合使用](imgs/预留实例 + Spot 混合.png)

        memory: 100Mi
      maxAllowed:
        cpu: 2
        memory: 2Gi
      controlledResources: ["cpu", "memory"]

血泪教训
- updateMode: "Auto" 会重启 Pod 来应用新资源限制,导致服务中断
- 对于无状态服务,使用 Initial 模式,只在 Pod 创建时调整
- 必须设置 minAllowedmaxAllowed,否则 VPA 可能给 Pod 分配过大资源

我的建议:VPA 主要用于“推荐”而非“自动调整”。先用 Off 模式收集建议,再手动调整。

2.3 Cluster Autoscaler —— 节点层面的省钱关键

这是最容易被忽视的部分。配置:

# 安装 Cluster Autoscaler(AWS EKS 示例)
helm install cluster-autoscaler autoscaler/cluster-autoscaler \
  --namespace kube-system \
  --set autoDiscovery.clusterName=my-cluster \
  --set awsRegion=us-west-2 \
  --set rbac.create=true \
  --set podPriorityThreshold=-10

关键参数:
- --scale-down-enabled=true:默认开启
- --scale-down-delay-after-add=10m:节点添加后等待 10 分钟再考虑缩容
- --scale-down-unneeded-time=10m:节点空闲 10 分钟后缩容
- --max-node-provision-time=15m:节点启动超时时间

踩坑
- 节点组配置了 spot 实例,但没设置 nodeSelector,导致关键服务被调度到 spot 节点,被回收时中断
- 没有配置 podDisruptionBudget,缩容时 Pod 被强制删除

3. 成本优化实战策略

3.1 预留实例 + Spot 混合

我的节点组配置:

# 节点组 A:预留实例,运行关键服务
nodeGroups:
- name: on-demand-group
  instanceType: t3.medium
  minSize: 2
  maxSize: 10
  labels:
    workload-type: critical

# 节点组 B:Spot 实例,运行批处理任务
- name: spot-group
  instanceType: t3.medium
  spotInstancePools: 4
  spotAllocationStrategy: "capacity-optimized"
  minSize: 0
  maxSize: 20
  labels:
    workload-type: batch
  taints:
  - key: "spot"
    value: "true"
    effect: "NoSchedule"

部署时使用 nodeSelector 和 tolerations:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: batch-processor
spec:
  template:
    spec:
      tolerations:
      - key: "spot"
        operator: "Exists"
        effect: "NoSchedule"
      nodeSelector:
        workload-type: batch

3.2 成本监控:用 Kubecost 看清每一分钱

安装 Kubecost:

helm install kubecost kubecost/cost-analyzer \
  --namespace kubecost \
  --set kubecostToken="your-token" \
  --set prometheus.nodeExporter.enabled=false

关键指标:
- 集群成本:按命名空间、Deployment、Pod 查看
- 闲置资源:查看未被使用的 CPU/内存
- Spot 使用率:检查 spot 节点利用率

我从 Kubecost 发现的典型问题:
- 某个命名空间占用了 60% 的集群资源,但实际流量只有 5%
- 开发环境有 30 个 Pod 处于 Running 但无流量状态
- 某个 Deployment 的 requests 设置过高(2 CPU 但实际只用 0.1)

3.3 成本优化三板斧

第一板斧:设置资源配额

apiVersion: v1
kind: ResourceQuota
metadata:
  name: dev-quota
  namespace: dev
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    count/pods: 50

第二板斧:使用 LimitRange 强制限制

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: dev
spec:
  limits:
  - max:
      cpu: "2"
      memory: 2Gi
    min:
      cpu: "0.1"
      memory: 100Mi
    default:
      cpu: "0.5"
      memory: 512Mi
    defaultRequest:
      cpu: "0.2"
      memory: 256Mi
    type: Container

第三板斧:定期清理闲置资源

我的脚本(每周运行):

#!/bin/bash
# 查找 7 天内没有流量的 Pod
kubectl get pods --all-namespaces -o json | jq -r '
  .items[] | select(.metadata.creationTimestamp < (now - 7*86400)) | 
  .metadata.namespace + "/" + .metadata.name
' | while read line; do
  echo "检查闲置 Pod: $line"
  # 这里可以检查日志或监控指标
done

4. 最终效果

实施上述方案后,我的集群成本变化:
- 节点数:从 15 个降到 8 个(节省 46%)
- Pod 密度:从平均 3 Pod/节点提升到 6 Pod/节点
- Spot 使用率:从 0% 提升到 35%
- 月度成本:降低约 40%

5. 延伸思考

  • GPU 场景:对于 ML 训练任务,HPA 不适用,考虑 KEDA 基于队列长度伸缩
  • 无服务器方案:考虑 Karpenter(比 Cluster Autoscaler 更智能的节点自动伸缩)
  • 成本模型:不只是看云厂商账单,还要考虑运维成本(Pod 重建、服务中断)

最后一句:自动伸缩是工具,成本优化是目标。别让工具控制你,而是要驾驭工具。

你可能感兴趣的文章

来源:每日教程每日一例,深入学习实用技术教程,关注公众号TeachCourse
转载请注明出处: https://teachcourse.cn/4105.html ,谢谢支持!

资源分享

对象系列化两种方法Serializable和Parcelable 对象系列化两种方法Serializabl
Android项目使用到的正则表达式详细介绍和示例说明 Android项目使用到的正则表达式
Eclipse开发项目中红色感叹号问题解决办法 Eclipse开发项目中红色感叹号问
002-实现多个Fragment切换方法封装及各子生命周期执行情况分析 002-实现多个Fragment切换方法封

评论已关闭!