你有没有算过,每个月花在云上Kubernetes集群的钱,有多少是在为“空气”买单?
上个月,我帮一个团队做了一次集群健康检查。他们抱怨云账单涨得飞快,但业务量其实很平稳。结果一查,好家伙,集群整体资源利用率长期徘徊在15%左右。这意味着,有超过80%的CPU和内存资源,在大部分时间里只是静静地躺在那里,然后准时从你的账户里扣钱。
这太常见了。我们往往忙于部署、发布、扩缩容,却很少回头看看:那些我们申请的资源,真的被用上了吗?
第一刀:精准定位“僵尸”与“胖子”
优化成本,第一步不是调参数,而是做审计。你得知道钱花哪儿了。
1. 识别闲置资源
- 未被调度的Pod: 检查那些长期处于
Pending状态的Pod。通常是因为资源请求(requests)设置过高,没有节点能满足。它们不运行,但定义还在,占用着你的思维内存,也是技术债。 - 低利用率的工作负载: 这是重灾区。用
kubectl top pod结合监控工具(如Prometheus),找出那些CPU/内存使用率长期(比如过去7天)低于其请求(request)30%的Deployment或StatefulSet。我习惯叫它们“胖子应用”——申请了大房子,只住一个小角落。 - 孤立的资源: 那些没有对应Pod的Service、Ingress?被遗忘的PVC?特别是LoadBalancer类型的Service,每一个都可能对应着一笔不小的云网络费用。定期清理:
kubectl get deployments,svc,ingress,pvc --all-namespaces并核对。
2. 审视资源请求与限制(Requests & Limits)
这是Kubernetes资源管理的核心,也是最容易出问题的地方。
- Requests(请求): 这是Pod向调度器“预订”的资源,决定了Pod能被调度到哪里。设置过高是浪费的根源。
- Limits(限制): 这是Pod能使用的资源上限,防止单个Pod吃光节点资源。
一个经典的反模式是:requests 和 limits 设置成相同的值。这看似“安全”,实则僵化。它剥夺了应用在需要时利用节点闲置资源的能力,也使得调度不够灵活。
我的建议是: 基于监控数据(P99值是个好参考),将 requests 设置为一个能保证应用稳定运行的下限值,而 limits 可以适当放宽,比如是 requests 的1.5-2倍。这为突发流量留出了缓冲,又不影响调度。
第二刀:让调度器为你省钱
搞清楚了资源现状,接下来就让调度器更智能地工作。
1. 启用并善用节点亲和性/反亲和性
别让Pod满世界乱跑。通过节点亲和性(nodeAffinity),你可以把特定的工作负载(比如计算密集型)引导到具有特定标签(如 instance-type=compute-optimized)的节点上。反过来,用Pod反亲和性(podAntiAffinity)把同一服务的多个实例分散到不同节点或可用区,这既能提高容灾能力,有时也能利用不同的计费模型。
2. 玩转污点与容忍度(Taints and Tolerations)
这是创建“专用节点池”的利器。比如,你可以给一些配置较低、价格便宜的节点打上 taint: spot=true:NoSchedule。然后,只让那些可以容忍中断的、无状态的应用(通过添加对应的 toleration)调度上去。这在配合使用AWS Spot实例或GCP Preemptible VM时,能省下一大笔钱。
3. 垂直扩缩容(VPA)与水平扩缩容(HPA)结合
HPA大家很熟悉,根据CPU/内存等指标扩缩Pod副本数。但别忘了VPA(垂直扩缩容)。它可以自动调整Pod的 requests 和 limits。两者结合威力巨大:
- VPA负责“让每个Pod的身材变得标准”,不浪费资源。
- HPA负责“根据客流调整服务员数量”,应对流量变化。
注意: VPA在更新Pod资源时会导致Pod重建,对于有状态服务要慎用。通常先用在无状态服务上。
实战策略:从“救火”到“常态”
优化不是一次性的,得形成机制。
- 建立成本监控仪表盘: 把集群资源利用率、闲置成本、各命名空间/团队的资源消耗放在醒目位置。让数据说话。
- 将资源审核纳入CI/CD: 可以在Pipeline中加入检查,对新增或修改的Deployment YAML中的资源请求值进行合理性检查(比如,不允许内存request超过2Gi,除非有特批)。
- 设定资源配额(ResourceQuota): 在命名空间级别设置配额,迫使开发团队思考资源使用。这能有效防止“资源蔓延”。
- 考虑集群自动扩缩容(Cluster Autoscaler): 当资源不足时自动加节点,当节点利用率低时自动缩容节点。这是应对潮汐负载、节省成本的大杀器。
坦白讲,没有银弹
成本优化是一个平衡艺术。在压榨资源和保证稳定性、预留缓冲之间,需要不断权衡。过于激进的优化可能会在流量高峰时导致应用不稳定,省下的钱可能还不够处理一次故障。
我的经验是,从最明显的浪费下手(比如那些利用率极低的“胖子应用”),逐步推进。每调整一个参数,观察一段时间。跟业务团队沟通,了解他们的应用特性。
最终目标不是把利用率拉到100%,而是让每一分钱的花费都清晰、合理、可控。当你能清楚地告诉业务方:“这个服务每天的成本是X元,因为它的资源配置是Y”,优化工作就成功了一大半。
你的集群里,最大的“闲置资源”藏在哪儿呢?是时候动手查一查了。