AWS EKS中Pod未利用多节点调度导致单节点CPU过载问题咨询
现有配置的核心问题点
- 完全缺失容器资源(CPU/内存)的requests与limits声明,这是导致单节点CPU被打满、负载分布不均的最核心原因。没有资源声明时,K8s调度器无法准确判断每个Pod需要的算力大小,既可能盲目把多个高负载Pod堆到同一节点,也无法限制容器对节点CPU的无限制抢占,最终出现单节点资源被打满、整机响应变慢的问题。
- 没有配置Pod分散调度约束,Deployment的2个副本完全可能被调度器全部分配到同一个节点上,剩下的节点算力完全闲置,配置两个节点的投入根本发挥不了作用。
- 滚动更新策略在无资源配置的场景下存在放大风险的问题:设置
maxSurge:1、maxUnavailable:0时,每次发版会临时多启动1个新Pod,整个集群临时承载3个backend实例。如果新Pod被调度到本来就负载偏高的节点,很容易直接把节点CPU占满,甚至触发旧Pod因节点资源不足、探针检测超时的连锁重启。
为什么两个节点却始终只有一个在扛负载
- K8s的调度决策逻辑是基于Pod声明的资源需求做节点匹配,因为没有给Pod配置资源requests,调度器对Pod的资源消耗判断是模糊的,默认会低估Pod的实际资源占用,哪怕某节点实际负载已经很高,只要剩余的名义资源够,就会把新Pod塞过去,根本不会考虑全局负载均衡。
- 没有反亲和规则时,调度器的默认轮转逻辑不保证副本均匀跨节点。完全可能因为某节点有镜像缓存、没有其他亲和规则冲突,把两个backend副本全调度到同一台节点,另一台节点根本接不到该应用的流量,算力直接浪费。
- 就算副本真的分散在两个节点上,没有配置CPU limit的话,容器的cgroup没有做资源硬隔离,某节点上的backend进程会无限制抢占CPU时间片,把同节点上的系统组件、其他业务进程的可用CPU挤走,表现为单节点CPU100%、另一节点低负载的不均衡状态。
落地调整方案
- 第一,先压测拿到单实例的真实资源消耗水平,给backend容器补上资源配置:
这组配置的作用有两个:一是给调度器提供准确的资源判断依据,避免把多个高负载Pod堆到同一个节点;二是通过limit给容器加硬资源配额,就算应用出现CPU异常飙升,最多也只能用到预设的CPU额度,不会把整个节点的CPU资源占满拖垮整机。resources: requests: cpu: "按压测值填写,比如300m" memory: "按压测值填写,比如512Mi" limits: cpu: "按压测峰值的1.5倍填写,比如500m" memory: "按压测峰值的1.2倍填写,比如1Gi" - 第二,在Deployment的Pod模板里加上Pod反亲和规则,强制同应用的副本跨节点分散:
这个规则会告诉调度器,优先把带affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - root topologyKey: "kubernetes.io/hostname"app: root标签的Pod调度到没有同标签Pod的节点上,保证2个副本分别落在两个不同的节点上,不会出现单节点跑两份backend实例、另一台完全闲置的情况。 - 第三,临时优化发版策略降低风险:在资源配置和反亲和规则刚上线的初期,可以把滚动更新的参数临时调整为
maxSurge: 0、maxUnavailable: 1,发版时先停旧Pod再启动新Pod,避免临时多出的Pod把节点资源占满。等连续几个版本运行稳定后,再改回原来的滚动参数即可。 - 上线后验证:执行
kubectl get pods -n backend -o wide,确认两个backend副本分别落在两个不同的节点上,同时通过节点监控面板观察两个节点的CPU负载是否趋于均衡。如果还是出现Pod全堆在同一节点的情况,检查对应节点是否有特殊taint、或者是否有其他配置的亲和规则把Pod约束在了固定节点上。
内容的提问来源于stack exchange,提问作者NooBskie
相关产品推荐
相关产品推荐

