EKS 集群成本失控的六个常见原因

集群账单每月上涨但业务量没变?这六个原因覆盖了我们排查过的绝大多数情况。

为什么容器集群的成本特别容易失控

虚拟机时代,加一台机器是个需要审批的动作。容器时代,开发提个 PR 改一下 replicas 就能多占几倍资源,而且没人会察觉。加上资源请求(requests)的设置往往靠拍脑袋,浪费就这样累积起来。

下面六个原因按我们排查的出现频率排序。

六个原因与排查方法

  1. 01

    资源请求远高于实际用量

    最常见。开发怕 OOM 就把 requests 设得很大,调度器按 requests 占位,节点看起来满了实际 CPU 只用了 15%。排查:对比 Pod 的 requests 与实际 usage,比值超过 3 倍的都是候选优化项。

    交付物:requests vs usage 对比表、调整建议清单

  2. 02

    节点规格与 Pod 规格不匹配

    比如 Pod 需要 3 vCPU,节点是 4 vCPU,一个节点只能放一个 Pod,剩下 1 核浪费。排查:看节点的资源碎片率。Karpenter 能自动挑合适规格,Cluster Autoscaler 不行。

    交付物:节点碎片分析、规格调整方案

  3. 03

    没用 Spot

    无状态服务跑在按需实例上,是最直接的浪费。排查:统计各 NodePool 的 capacity-type 分布,无状态负载的 Spot 占比应该在 60% 以上。

    交付物:Spot 占比统计、可迁移负载清单

  4. 04

    僵尸负载

    早就没人用的服务还在跑,测试环境的临时部署忘了删,废弃的 CronJob 每天还在执行。排查:看各 Namespace 的入口流量,长期零流量的服务找负责人确认。

    交付物:零流量服务清单、清理确认单

  5. 05

    跨可用区流量费

    服务间调用随机跨可用区,流量费在大流量场景下相当可观。排查:看 VPC Flow Logs 里的跨 AZ 流量占比。解法是拓扑感知路由(Topology Aware Routing),优先同 AZ 调用。

    交付物:跨 AZ 流量统计、拓扑路由配置

  6. 06

    日志与监控成本

    容易被忽略但金额不小。DEBUG 级别日志全量入 CloudWatch,Prometheus 指标基数爆炸(label 里放了 user_id 这种高基数字段)。排查:看 CloudWatch Logs 的 IncomingBytes 和 Prometheus 的时间序列数量。

    交付物:日志量分析、指标基数报告

requests 与实际用量对比

bash check-requests-vs-usage.sh
#!/usr/bin/env bash
# 对比 Pod 的资源请求与实际用量,找出超配严重的负载
# 依赖:kubectl、metrics-server、jq
set -euo pipefail

NS="${1:---all-namespaces}"

printf '%-24s %-38s %10s %10s %8s\n' NAMESPACE POD REQ_CPU USE_CPU RATIO
printf '%s\n' "$(printf '=%.0s' {1..96})"

# 取当前用量
kubectl top pods $NS --no-headers 2>/dev/null > /tmp/top.txt

kubectl get pods $NS -o json | jq -r '
  .items[]
  | select(.status.phase == "Running")
  | . as $p
  | [$p.metadata.namespace, $p.metadata.name,
     ([$p.spec.containers[].resources.requests.cpu // "0"]
       | map(if test("m$") then (sub("m$";"") | tonumber)
             else (tonumber * 1000) end)
       | add)] | @tsv
' | while IFS=$'\t' read -r ns pod req_m; do
  use_m=$(awk -v n="$ns" -v p="$pod" '
    $0 ~ p { gsub(/m$/,", $2); print $2; exit }
  ' /tmp/top.txt)
  [[ -z "${use_m:-}" ]] && continue
  [[ "$use_m" -eq 0 ]] && use_m=1
  ratio=$(awk -v r="$req_m" -v u="$use_m" 'BEGIN { printf "%.1f", r/u }')
  # 只输出超配 3 倍以上的
  if (( $(awk -v x="$ratio" 'BEGIN { print (x >= 3) }') )); then
    printf '%-24s %-38s %9sm %9sm %7sx\n' "$ns" "${pod:0:38}" "$req_m" "$use_m" "$ratio"
  fi
done

echo
echo "提示:ratio 高不代表一定要降。先确认是否有周期性峰值或启动瞬时高峰。"

kubectl top 只看当前瞬时值,正式评估要用 Prometheus 查一段时间的 p95,避免把有周期性峰值的服务误判成超配。

优化动作优先级

动作预期收益风险建议顺序
清理僵尸负载5%-20%低(需确认无人使用)1
调整 requests15%-35%中(需观察 OOM)2
引入 Karpenter10%-25%3
无状态服务上 Spot30%-50%(该部分)中(需容错设计)4
Graviton 迁移15%-25%中(需兼容验证)5
日志级别与采样治理5%-15%并行做
拓扑感知路由跨 AZ 流量降 60%+并行做
购买 Savings Plans覆盖部分降 30%+低(但有承诺)最后(等用量稳定)

顺序很重要。先把浪费挤掉再买承诺折扣,否则会为浪费的资源锁三年价格。

怎么让优化不反弹

技术手段之外,最有效的是把成本数据推到团队面前。我们的做法是用 Kubecost 或标签方案按 Namespace 算成本,每月自动推送给各团队负责人。看得见就会有人管。

下一步

把云的复杂度交给我们,你只管做业务

留下需求,沐杉云的解决方案架构师会在一个工作日内联系你,提供免费的现状评估、迁移方案草案与 TCO 测算表。