K8s集群资源不足排查:从节点压力到Pod驱逐的完整定位流程
K8s集群提示资源不足,通常不是单一原因,而是节点真实压力、Pod requests设置、调度策略或配额限制共同作用的结果。
排查的核心顺序是:先确认哪个节点或哪个命名空间出现压力,再区分是CPU、内存、磁盘还是PID耗尽,最后判断是临时扩容、调整requests还是清理无用负载。
先看节点状态和资源水位
登录到能执行kubectl的机器,确认当前上下文和节点列表。
kubectl config current-context
kubectl get nodes -o wide
如果节点状态是NotReady或SchedulingDisabled,先看节点详情中的Conditions。
kubectl describe node <节点名>
重点看这几项:
MemoryPressure、DiskPressure、PIDPressure是否为True。只要有一项为True,kubelet就会开始驱逐Pod。Allocatable和Allocated resources的对比。如果CPU或内存的requests已经接近100%,新Pod就会Pending。Events区域是否有Eviction、NodeHasInsufficientMemory等记录。
快速看各节点实际使用率可以用:
kubectl top nodes
如果提示metrics不可用,
说明metrics-server没装或没就绪,
此时只能依靠 describe node 里的requests和节点系统命令(如 free -h、df -h、top)辅助判断。
用Events和驱逐记录锁定触发源
节点级资源不足往往先在事件里暴露。
按时间排序查看全集群事件:
kubectl get events -A --sort-by=.lastTimestamp | tail -n 50
常见关键字包括:
Evicted:Pod被kubelet驱逐,通常伴随The node was low on resource: memory或ephemeral-storage。FailedScheduling:调度器找不到满足requests的节点,提示Insufficient cpu或Insufficient memory。OOMKilled:容器进程被内核OOM Killer终止,退出码通常是137。
查看被驱逐Pod的详情:
kubectl describe pod -n <命名空间>
在 Status 和 Last State 中确认退出原因。
如果是OOMKilled,说明容器实际内存超过limit;
如果是Evicted,说明节点整体资源紧张。
两者处理方式不同,不要混为一谈。
区分requests、limits和实际使用量
K8s调度看的是requests,不是实际使用量。
很多“资源不足”其实是requests设置过大导致节点被占满,但实际使用率很低。
查看某个命名空间下所有Pod的requests和limits:
kubectl get pods -n <命名空间> -o custom-columns=NAME:.metadata.name,CPU_REQ:.spec.containers[*].resources.requests.cpu,MEM_REQ:.spec.containers[*].resources.requests.memory
如果发现大量Pod的requests明显高于实际使用,可以在业务低峰期逐步下调requests,让调度器重新计算可分配资源。
调整后观察新Pod是否能正常调度。
如果实际使用量确实接近limit,优先考虑扩容节点或提高limit,而不是盲目下调requests。
检查配额和限制范围
命名空间级别的ResourceQuota和LimitRange也会造成“资源不足”的假象。
kubectl get resourcequota -A
kubectl describe resourcequota <配额名> -n <命名空间>
kubectl get limitrange -A
如果配额中 used 已经等于 hard,新Pod会直接被拒绝创建,事件里会出现 exceeded quota。
此时要么提高配额,要么清理该命名空间下不再使用的Pod和PVC。
临时缓解与长期优化
确认是节点真实资源耗尽后,可以按以下顺序处理:
- 清理已完成或长期不用的Job、Evicted状态的Pod:
kubectl get pods -A | grep Evicted
kubectl delete pod -n <命名空间>
- 如果磁盘压力来自日志或镜像,登录节点检查:
df -h
crictl images
du -sh /var/log
清理无用镜像和大日志文件,但不要直接删除正在使用的镜像层。
- 短期扩容:增加节点或临时调大节点规格,让调度器有可用资源。
- 长期优化:为关键业务设置合理的requests和limits,配置HPA按CPU或内存自动扩缩,并给系统组件预留足够的节点资源。
验证排查是否生效
处理完成后,用以下命令复查:
kubectl get nodes
kubectl top nodes
kubectl get pods -A | grep -v Running
确认节点Conditions恢复为False,Pending和Evicted的Pod数量下降,新Pod能正常调度并稳定运行。
如果问题反复出现,建议持续观察节点资源曲线,而不是只处理单次告警。
常见疑问
为什么节点还有空闲内存,Pod却被驱逐?
K8s驱逐看的是节点整体可分配资源,包括系统保留部分。Allocatable 小于物理内存,且kubelet会为系统进程预留资源。
当可用量低于驱逐阈值时就会触发,即使 free -h 看起来还有余量。
requests设置多少比较合理?
没有统一数值。
建议先观察业务稳定运行时的实际使用量,requests可以设为略高于日常峰值,limits设为requests的1.5到2倍,再根据监控数据微调。
metrics-server没装能排查吗?
可以。
用 kubectl describe node 看requests和Conditions,登录节点用 free、df、top 看真实使用率,结合Events判断驱逐原因,只是缺少集群级别的历史趋势。
排查K8s集群资源不足,关键是先把节点压力、Pod驱逐和调度失败三类信号分开,再结合requests、配额和实际用量判断根因。
按上面的顺序逐层定位,多数资源不足问题都能找到明确入口。