4、工作负载资源优化:Pod资源规格调整、HPA/VPA配置、闲置资源回收
说到工作负载的资源优化,我其实挺有感触的。早期做Kubernetes迁移时,团队最常问的就是:“这个Pod到底该给多少资源?” 给少了,OOMKill;给多了,老板看账单心疼。说白了,这就是个精细活。
这一章,咱们就聊聊怎么把Pod的资源规格调准,怎么用HPA和VPA让系统自动伸缩,以及怎么把那些“占着茅坑不拉屎”的闲置资源给回收掉。
4.1 Pod资源规格调整:别拍脑袋,要讲数据
我见过太多团队,给Pod配资源全靠“感觉”。Java应用一律给4C8G,Node.js服务给1C2G。结果呢?一大半资源都在空转。
正确的做法是什么? 先跑起来,再看数据。
4.1.1 理解requests和limits
这两个概念,我再说一遍,因为太重要了。
- requests:调度时的“承诺”。K8s根据这个值决定把Pod放在哪个节点上。说白了,这是“最低保障”。
- limits:运行时的“天花板”。Pod最多能用这么多,超过就会被限流或杀掉。
我个人习惯,生产环境里requests和limits不要设成一样的。为什么?你想想看,如果所有Pod的requests都等于limits,节点资源利用率会非常低。因为Pod实际用不了那么多,但K8s以为它全占了。
4.1.2 基于历史数据的资源调整
别靠猜。用数据说话。
我一般会用 kubectl top pod 或者Prometheus + Grafana来观察Pod的实际资源消耗。观察周期至少一周,覆盖业务高峰期和低谷期。
举个例子,一个Web服务,过去7天的CPU平均使用率是200m,峰值是500m。那requests设250m,limits设600m,就挺合理。
# 查看Pod资源使用
kubectl top pod -n production
# 输出示例
NAME CPU(cores) MEMORY(bytes)
web-service-7d9f8c6b9 250m 128Mi
web-service-7d9f8c6b9 180m 110Mi
web-service-7d9f8c6b9 320m 145Mi
嗯,这里要注意:内存是“不可压缩资源”。一旦超过limits,Pod会被OOMKill。所以内存的limits我通常会留20%-30%的buffer。
4.2 HPA配置:让Pod数量自动“呼吸”
HPA(Horizontal Pod Autoscaler)是K8s里最常用的弹性手段。它的逻辑很简单:根据CPU、内存或自定义指标,自动调整Pod的副本数。
但配置HPA,有几个坑我得提醒你。
4.2.1 指标选择与阈值设定
很多人只配CPU指标。这其实不够。我遇到过好几次,CPU没上去,但请求延迟已经飙升了。为什么?因为瓶颈可能在数据库连接池或外部API调用上。
我建议: 至少配两个指标。CPU + 请求QPS,或者CPU + 内存。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-service-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: 1000
你看,这个配置里,CPU利用率超过70%或者每秒请求数超过1000,都会触发扩容。
--horizontal-pod-autoscaler-downscale-stabilization 设成了5分钟,情况就好多了。扩容要快,缩容要慢,这是铁律。
4.2.2 自定义指标与Prometheus适配
内置的CPU/内存指标,说实话,太粗糙了。真正精细的弹性,得靠自定义指标。
比如,我想根据“队列深度”来扩容。队列里的任务超过100个,就加Pod。这需要Prometheus Adapter把Prometheus里的指标暴露给K8s。
# Prometheus Adapter配置示例
seriesQuery: 'rabbitmq_queue_messages_ready{namespace="production"}'
resources:
overrides:
namespace:
resource: "namespace"
queue:
resource: "service"
name:
matches: "rabbitmq_queue_messages_ready"
as: "queue_messages_ready"
metricsQuery: 'sum(rabbitmq_queue_messages_ready{<<.LabelMatchers>>}) by (<<.GroupBy>>)'
这样,HPA就能根据 queue_messages_ready 这个指标来决策了。
4.3 VPA配置:自动调整Pod规格
HPA管的是“数量”,VPA(Vertical Pod Autoscaler)管的是“大小”。VPA会自动调整Pod的requests和limits。
说实话,VPA在生产环境里,我用的比较谨慎。因为它调整规格时需要重建Pod,这会导致服务中断。
4.3.1 VPA的三种模式
| 模式 | 行为 | 适用场景 |
|---|---|---|
| Off | 只给出建议,不自动调整 | 刚接触VPA,先看看建议值 |
| Auto | 自动调整,Pod会重建 | 无状态服务,可以接受短暂中断 |
| Initial | 只在Pod创建时调整 | 有状态服务,不想频繁重建 |
我个人习惯,先用Off模式跑一周,看看VPA给出的建议值是否合理。确认没问题后,再切换到Auto模式。
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: web-service-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: web-service
updatePolicy:
updateMode: "Off" # 先看建议
resourcePolicy:
containerPolicies:
- containerName: '*'
minAllowed:
cpu: 100m
memory: 100Mi
maxAllowed:
cpu: 2
memory: 2Gi
4.4 闲置资源回收:别让钱打水漂
这是我最想强调的一点。很多团队只关注“怎么给够资源”,却忽略了“怎么回收资源”。
你想想看,一个测试环境的Pod,跑了一个月没人用,是不是在烧钱?一个Job跑完了,Pod还在那里挂着,是不是浪费?
4.4.1 使用Cluster Autoscaler回收节点
当节点利用率低时,Cluster Autoscaler会把节点上的Pod驱散,然后缩容节点。这能省下不少云资源费用。
但要注意,不是所有Pod都能被驱散。你需要给Pod加上合适的 PodDisruptionBudget。
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-service-pdb
spec:
minAvailable: 2 # 至少保留2个Pod
selector:
matchLabels:
app: web-service
这样,Cluster Autoscaler在缩容时,会保证你的服务至少还有2个Pod在运行。
4.4.2 使用KubeCost或开源工具分析闲置资源
我推荐用 KubeCost 或 Goldilocks 来分析集群里的资源浪费情况。
KubeCost能告诉你:哪个命名空间最费钱?哪个Deployment的资源利用率最低?
Goldilocks则能给出VPA建议,告诉你哪些Pod的资源规格可以下调。
4.4.3 设置资源配额与限制范围
别让开发者随意创建Pod。用 ResourceQuota 和 LimitRange 来约束。
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: development
spec:
hard:
requests.cpu: "10"
requests.memory: "20Gi"
limits.cpu: "20"
limits.memory: "40Gi"
pods: "50"
---
apiVersion: v1
kind: LimitRange
metadata:
name: dev-limits
namespace: development
spec:
limits:
- default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "200m"
memory: "256Mi"
type: Container
这样,开发者在dev命名空间里,最多只能用10核CPU和20Gi内存。每个Pod默认的requests是200m CPU和256Mi内存。想超?没门。
4.5 总结与最佳实践
好了,这一章的内容不少。我帮你捋一下核心要点:
- Pod规格调整:别靠猜,用
kubectl top或Prometheus看实际数据。requests和limits要有合理差距。 - HPA配置:至少配两个指标,扩容快、缩容慢。自定义指标更精准。
- VPA配置:先用Off模式看建议,再切Auto。别和HPA同时用。
- 闲置资源回收:用Cluster Autoscaler、KubeCost、ResourceQuota来“挤水分”。
最后说一句:资源优化不是一次性工作。业务在变,流量在变,你的资源策略也得跟着变。定期复盘,持续优化,这才是FinOps的精髓。
下一章,咱们聊聊集群层面的成本控制,包括节点选型、Spot实例和混合部署策略。到时候见。