尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

K8s生产环境故障排查实战:从API Server不健康到资源耗尽

K8s生产环境故障排查实战:从API Server不健康到资源耗尽 K8s这个系列写到第六篇按我自己的规划该聊点生产环境真正会疼的东西了。前几篇我们更多是在讲概念、搭集群、部署服务但一个集群真正跑起来之后你会发现80%的时间都耗在一件事上排查故障。网上搜k8s相关的内容热度高的除了安装部署教程就是各种报错比如k8s控制节点master初始化显示the api server is not healthy、k8s生产环境中常见的故障影响到用户这些词条的火爆程度本身就说明大家遇到的坑高度集中。这篇文章我不会去翻译官方文档也不打算写那种收藏了等于学会了的清单而是把我在实际工作中处理过的故障、踩过的坑、以及事后总结出来的排查套路完整拆开讲给你听。适合几类读者刚把集群搭起来准备上生产的运维同学已经被Pod驱逐、节点NotReady折磨过的朋友以及想搞清楚k8s和docker在故障场景下到底有什么区别、namespace和GPU这类资源怎么隔离和调度的人。就算你目前只是在学k8s、在记k8s学习笔记这篇也能帮你把零散的知识点串成一条实战链路。先说清楚一件事k8s的学习曲线陡陡不在概念多而在故障链长。一个服务不可用可能是业务代码问题可能是Pod被驱逐可能是节点磁盘满了可能是CoreDNS挂了可能是网络插件抽风甚至可能是etcd慢了一下。任何一层出问题最终都会表现为用户访问失败了。所以故障排查的核心不是背命令而是建立一套分层定位的思维框架。1. 生产环境的故障全景先搞清楚K8s到底会坏在哪里1.1 故障分层控制面、数据面、应用面我一直喜欢把K8s集群在逻辑上切成三层来看控制面、数据面、应用面。控制面就是etcd、kube-apiserver、kube-scheduler、controller-manager这几个核心组件它们负责存储状态、提供API、调度Pod。数据面是每台节点上的kubelet、容器运行时和网络插件它们负责真正把容器拉起来、跑起来、连起来。应用面则是你部署的业务Pod、Service、Ingress、PVC这些业务资源。生产环境里的故障绝大多数不是单一层面的问题而是层与层之间的连锁反应。举个例子节点磁盘使用率超过85%kubelet会根据驱逐阈值把Pod赶走应用层看到的就是Pod被删了、服务闪断但根因其实在数据面。再比如etcd性能变差apiserver响应变慢所有kubectl命令都卡业务层反而是最后感知到的。所以我排障的第一反应永远是问一句用户侧到底看到了什么然后顺着这条线索往前推先定层再定位。k8s和docker的区别很多人从技术角度能说出一堆但在故障排查里这个区别会非常直观docker daemon是一个独立的守护进程容器归它管出了问题你看docker的日志基本能找到答案。K8s的容器运行时虽然是containerd这类组件但真正负责要不要重启、要不要驱逐的决策者是kubelet。你习惯了用docker ps去看容器状态上到k8s之后一定要改掉这个习惯因为kubelet不会直接告诉你这个Pod为什么起不来你得去看它的事件、看API Server里的状态。1.2 用户视角的故障影响面热词里有k8s生产环境中常见的故障影响到用户这句话其实点破了排障的优先级。业务跑在K8s上用户不关心你用的是Deployment还是StatefulSet不关心你的节点是不是NotReady他们关心的只有一件事页面还能不能打开接口响应快不快数据会不会丢。所以我的故障分级从来不是按照组件重要性来的而是按照用户影响面来排的影响所有用户的功能肯定先处理影响单个用户的可以缓一缓服务完全不可用比响应变慢更紧急但响应从200ms涨到3秒其实比偶发5xx更隐蔽也更容易被忽略。生产环境最常见的几类用户侧表现一是白屏和5xx说明服务不可用二是超时和重试说明链路里有瓶颈三是数据不一致说明有状态服务出了问题。每一种表现对应的排查入口完全不同。这里特别想提醒一句不要让命名空间namespace成为故障盲区。很多线上事故不是集群坏了而是业务团队把测试环境和生产环境放在同一个集群的不同namespace里某个测试服务占满了节点资源把生产Pod挤爆了。namespace是隔离逻辑隔离不是资源隔离如果你不配ResourceQuota和LimitRange它什么都拦不住。我见过不止一次因为namespace里没加资源配额导致一个跑批任务把整台节点内存吃光、同节点其它生产Pod全部被驱逐的事故。1.3 GPU资源是另一套玩法顺带提一下热词里的k8s调用gpu。普通CPU和内存资源kubelet调度时就看requests和limits就可以。GPU不一样它要通过Device Plugin机制把GPU作为一种扩展资源上报给kubelet然后在Pod里声明nvidia.com/gpu的limits才能被调度到。排查GPU相关故障时很多人第一步就跑偏了去查Pod日志报什么CUDA错误实际上大多数情况的根因是GPU节点没打上nvidia.com/gputrue的label、device plugin没跑起来、或者Pod的limits里没声明nvidia.com/gpu。后面第三章我会专门拆一个相关的案例。2. the api server is not healthymaster初始化踩坑实录2.1 复现现场与报错背后逻辑先把这个高频报错单独拿出来讲因为搜索热词里出现最多的就是k8s控制节点master初始化显示the api server is not healthy after 4m0.00747357s。这行信息我太熟悉了几乎每个用kubeadm装集群的人都见过尤其在Rocky这类系统上装新版K8s不管你是装1.28还是1.30还是网上流传的所谓1.36踩坑套路基本一样。第一次见到这行报错的人会慌因为kubeadm init在前面一直显示节点初始化步骤突然卡了几分钟然后抛出这么一句看起来像系统出了什么不可挽回的问题。其实这句话的本质非常简单kubeadm init执行到最后会通过健康检查接口去访问kube-apiserver也就是执行curl -k https://localhost:6443/healthz如果这个接口在4分钟之内一直返回失败kubeadm就说the api server is not healthy after 4m0.00747357s。4m是它默认等待的超时时间0.00747357s只是程序自己计的精度这两部分合在一起构成了报错文本。关键问题就变成apiserver为什么起不来记住kubeadm init创建的kube-apiserver是一个静态Pod配置写在/etc/kubernetes/manifests/kube-apiserver.yaml里由kubelet直接拉起。所以apiserver起不来的根因要么是kubelet本身没有正常运行要么是容器的静态Pod被创建了但容器启动失败要么是启动之后连不上etcd或者健康检查没通过。排查链路就顺着这三条走。2.2 排查链路kubelet到静态Pod再到容器运行时排查的第一步永远是看kubelet的状态而不是去看apiserver的日志。kubelet是整个静态Pod的执行者如果它在报错后面全白搭。执行systemctl status kubelet看状态如果显示active (running)就继续看日志如果显示failed直接journalctl -u kubelet -f -n 100看最近的报错。然后不管kubelet状态如何我都习惯用crictl而不是docker去查容器因为K8s新版本默认用containerd作为运行时。crictl ps -a看一下节点上所有容器重点看有没有kube-apiserver、etcd、kube-controller-manager、kube-scheduler这几个静态Pod对应的容器以及它们的状态是不是Exited。如果容器已经退出crictl logs 直接看容器日志这里的报错往往才是真正的根因。比如我遇到过的几次情况日志明确显示apiserver创建证书时找不到/etc/kubernetes/pki/ca.key或者etcd因为数据目录权限不对起不来这些问题只看kubeadm的输出是永远看不出来的。如果容器还没被创建那就去看/etc/kubernetes/manifests/目录下的几个yaml文件是否完好。有时候用户手欠改了里面的配置或者之前的集群reset不干净残留了旧配置都会导致kubelet一直崩溃循环镜像拉不下来容器永远处于ContainerCreating。2.3 实操命令与参数修正把一套标准的排查命令整理出来以后照着敲就行swapoff -a sed -i / swap / s/^/#/ /etc/fstab systemctl status kubelet --no-pager journalctl -u kubelet -f -n 100 crictl ps -a crictl logs container-id cat /etc/kubernetes/manifests/kube-apiserver.yaml cat /etc/kubernetes/manifests/etcd.yaml df -h free -h除了命令之外有几个高频参数要格外留意。第一是cgroup driverKubelet默认期望SystemdCgroup而containerd的默认配置往往是cgroupfs这两边不一致时容器能创建但运行态会异常。修改/etc/containerd/config.toml里SystemdCgroup true重启containerd然后kubeadm reset之后重新init问题多半就解决了。第二是容器镜像仓库的访问初始化需要拉取十来个镜像包括registry.k8s.io下的kube-apiserver、kube-controller-manager、kube-scheduler、etcd、pause等如果节点处在内网环境、访问不了外网镜像仓库kubelet日志里会反复出现镜像拉取超时容器一直拉不下来。解决思路是配置registry mirror或者提前离线导入镜像而不是死等4分钟超时。第三是swap没有完全关闭很多系统里执行swapoff -a只是临时的重启之后swap又起来了kubelet会因为检测到swap直接拒绝启动这类报错特征非常明显日志里会写unexpected swap。2.4 4m0.00747357s只是表象顺便说一句网上的教程里总有人把这个4分钟当成一个神秘现象反复猜测是不是系统性能不行。真不是。kubeadm的默认超时就是4分钟它是故意给你时间看日志的。所以你看到这行报错时千万别再去初始化一次然后就盯着屏幕等它再次失败。正确做法是立刻开另一个终端去查日志查完再决定是kubeadm reset重来还是修好问题等它自己恢复。这个报错还有一个衍生场景集群明明昨天还好好的今天突然kubectl get nodes显示master节点NotReady然后你去控制台上看到kube-apiserver容器反复重启。这种和初始化时的问题经常是同一个根源——节点上磁盘写满了或者kubelet又因为cgroup配置被系统更新覆盖而挂掉。所以初始化踩过的坑在生产环境里还会以另一种面目出现提前理解这套逻辑后面能省很多事。3. 生产环境常见故障案例拆解3.1 资源耗尽型故障OOMKilled、Eviction、节点NotReady如果说生产环境K8s故障里只能选一类代表那一定是资源耗尽型。它覆盖了热词里的k8s生产环境中常见的故障影响到用户这个大方向而且表现形式五花八门。最常见的现象是Pod被杀你去kubectl describe pod看到Last State: Terminated, Reason: OOMKilled。很多人第一反应是业务代码内存泄漏了这当然是一种可能但更常见的原因是Pod的内存limit设得太小或者压根没设limit。我遇过一个大坑有个Java服务JVM堆内存初始给了4G但Pod的limits.memory只有2Gi结果JVM启动没一会儿就整容器被内核OOM杀掉重启了又杀陷入CrashLoopBackOff。这个问题的本质是JVM参数和容器资源声明互相矛盾不是代码的问题。比OOMKilled更难受的是节点级驱逐。当节点内存或磁盘空间触发了kubelet的驱逐阈值默认memory压力是100Mi或5%磁盘是85%kubelet会先尝试回收回收不了就按优先级驱逐Pod。这时候有多少个Pod在跑根本不重要重要的是节点的总资源容量已经被打满。比如一台32C64G的节点上面20个Pod的requests加起来刚好是60G看着还有4G余量但某个Pod突然内存涨到12G节点立刻进入MemoryPressure状态所有Pod的QoS优先级重新洗牌低优先级的BestEffort Pod第一批被赶走。所以给业务配置合理的requests和limits不是字面意义上的限定资源而是给kubelet一个该杀谁、该留谁的决策依据。另一个与此相关的经典现象是节点NotReady。节点上的kubelet如果在持续报磁盘压力、内存压力或者长时间没有上报心跳控制面会把节点标记为NotReady。排查时先df -h看磁盘、free -h看内存再用kubectl describe node确认Condition里写了什么。我处理过一个案例/var/lib/containerd所在的根分区被日志塞满kubelet自己都打不出日志了节点状态当然也是NotReady。清理日志、把容器日志放到独立分区并配置logrotate之后才彻底解决。3.2 网络与DNS故障的连锁反应网络类故障是用户感知最直接的。应用层最常见的现象是服务间调用偶发超时、接口响应变慢但业务代码没有报错。这种软故障比硬宕机更让人头疼因为现场往往已经过去了你只能靠监控日志回放。我处理过一个印象很深的案例一个微服务调用另一个服务的成功率从99.99%掉到了98%看起来不致命但用户侧明显感知到了卡顿。排查K8s层面时发现CoreDNS只有一个副本而且那个副本所在节点的网络插件重启过一次Pod漂移后DNS解析偶尔超时。业务方在配置里使用了主机名而不是Service域名解析动作全压在CoreDNS上单点故障被放大了。后来我们把CoreDNS扩到两个副本加了podAntiAffinity让两个副本落在不同节点又顺手配了node-local-dns做缓存此后再没出过同类问题。朋友这里有个值得记住的规律几乎所有的应用偶发超时都可以按这个顺序排查——先看业务日志有没有上游超时和连接拒绝再看Pod重启次数再看CoreDNS实例状态再看网络插件Pod状态最后看节点网卡和负载。90%的所谓玄学网络问题都能在链路里找到具体的慢点。3.3 有状态服务Redis集群在K8s里的坑热词里有个k8s redis集群这个主题太容易踩坑了值得单独聊。Redis Cluster在物理机上部署节点标识是固定的IP和端口但在K8s里Pod的IP是漂移的重启一次IP就变了。很多人第一次在K8s里跑Redis集群直接用Deployment管Redis Pod数据一挂就全乱了根本没有固定标识可用。正确玩法必须用StatefulSet每个Pod有稳定的序号和稳定的域名比如redis-0.redis-headless.namespace.svc.cluster.local然后通过headless service暴露集群节点之间用这个稳定域名互相通信。但我遇到过比这更隐蔽的问题有状态的集群和K8s的驱逐机制天生有摩擦。Redis节点一旦被节点级驱逐数据可能没来得及刷盘就丢了即使Pod自动拉起来也是带着旧数据的内存镜像重启主从同步差异很难收敛。生产环境里如果业务数据重要我不建议让K8s自动管理Redis的持久化目录混乱问题——PVC一定要绑定到独立存储用local PV或者云盘不要用宿主机本地目录否则Pod一旦被调度到别的节点数据就读不到了。等到真发生数据丢失、从节点落后主节点几万条命令这种事故时你就会明白什么叫有状态服务的分量。3.4 GPU调度故障设备明明在Pod就是起不来再拆一个高频点k8s调用gpu。这个场景在AI训练和推理服务里非常常见。典型的故障表现是Pod状态卡在Pending事件里写Failed to schedule原因是0/4 nodes are available and 4 node(s) didnt match pod anti-affinity rules或者明明GPU节点上有设备但调度器认为这个节点不满足nvidia.com/gpu1的资源要求。排查步骤我一般固定这么走先到GPU节点上执行nvidia-smi确认物理驱动正常显示不了设备那就是宿主机层面的问题和K8s无关。然后确认device plugin是否以DaemonSet方式运行在所有GPU节点上kubectl get pods -n kube-system | grep nvidia看Pod状态是不是Running。再然后看节点资源是否上报kubectl describe node 在Capacity里找nvidia.com/gpu字段如果没找到说明device plugin上报失败常见原因是nvidia-container-runtime没装好或者kubelet没有开放扩展资源API。都正常之后再检查你的Pod定义里limits是否声明了nvidia.com/gpu: 1注意GPU资源只能放到limits里不能混用requests和limits不一致的配置。最后分享一个只有在生产环境才会遇到的细节GPU资源的超卖问题。Nvidia的device plugin是按照物理卡数量上报资源的一张卡就是1个nvidia.com/gpu所以它在K8s眼里是整卡粒度的调度。如果你想两个Pod共享一张卡靠K8s原生机制做不到需要引入显存虚拟化方案或者MIG切分。否则就会出现在同一张卡上跑了两个任务但显存互相挤爆的黑天鹅。这种问题排起来非常痛苦因为K8s没有任何一个层面会告诉你你的Pod在物理设备上互相干扰。4. 一次生产故障的完整排查复盘4.1 从用户投诉出发的现场还原有些故障不是监控先报警而是用户先炸了。我经历的一次典型事故早上八点刚过客服那边传来消息说订单接口开始报错用户下单成功但页面一直转圈然后陆续有人反馈支付回调失败。当时值班的人下意识去看数据库压力因为接口频繁报超时这种直觉不能说错但方向偏了。我接手后第一步不是去数据库而是先看两个东西kubectl get pods -A看全局Pod状态再kubectl get events -A看最近有没有异常事件。结果发现核心订单服务有3个副本其中2个处于CrashLoopBackOff1个还勉强Running但性能已经严重劣化。问题非常清晰了服务只剩一个副本在干活还扛着所有流量不超时才有鬼。4.2 排查看板与验证顺序当时我的验证顺序大致是这样的先kubectl describe pod确认了两个CrashLoopBackOff的Pod事件里写的是OOMKilled还是Error如果是OOMKilled直接看内存limits有没有设置、业务占用为什么超了如果是其他错误看业务日志定位具体异常。那次事件显示是OOMKilled我立刻kubectl top node看整机内存和每台节点的实际用量发现订单服务所在节点的内存使用率已经到92%kubelet早就发出了MemoryPressure事件但我们的告警规则里没有覆盖MemoryPressure所以没人看见。继续往下追了一层订单服务的requests.memory只写了1Gi但limits.memory是4Gi两者差距过大。Kubernetes调度只看requests来判断节点能不能装下这个Pod所以调度器认为这台节点内存非常充裕一口气把多个Pod调度了上去但Pod真正运行时的内存上限却是4Gi。结果多个Pod同时涨内存节点物理内存被打爆kubelet按优先级驱逐了一批Pod订单服务直接被殃及。这个机制很多人不理解简单说requests是调度依据limits是运行时资源上限两者的差距越大节点资源的真实水位越不可控。优先级低的业务的requests写得小、limits写得大就会成为生产环境的吸血鬼。4.3 恢复动作与止血措施故障恢复阶段我没有直接去改那3个Pod的资源声明因为改动Deployment后Pod会重建重建期间可能把仅剩的那个Running副本也搞挂。我先选择把订单服务的副本数临时扩到5个让流量分散到更多节点同时调整了节点的驱逐阈值让kubelet更早介入磁盘和内存回收避免等到物理内存真正耗尽。等线上稳定下来之后才动刀改资源声明把requests.memory从1Gi提升到2Gilimits.memory保持在4Gi不变这样节点不会被看起来还剩很多、实际上随时会爆的假象欺骗。同时给订单服务所在的namespace加了ResourceQuota限制总内存上限防止跑批任务再把资源挤爆。这些操作听起来不复杂但每一步都要想清楚动了之后会影响什么——比如ResourceQuota如果设得太紧可能新的Pod直接无法创建所以我先设了一个比较宽的数值观察一周后再收紧。4.4 事后复盘这个故障本来可以避免复盘时我发现两件事。第一集群里已经配置了Prometheus监控但告警规则只有CPU使用率、内存使用率和节点状态完全没有Pod OOMKilled事件、节点MemoryPressure事件这类间接异常指标。结果硬件还没到上限集群的调度状态已经病了很久监控却一片绿。后来我补了一组事件类规则Pod重启次数5分钟超过5次告警节点MemoryPressure持续30秒告警etcd同步延迟超过50ms告警。第二订单服务的JVM堆参数是开发团队直接从物理机部署时代拷贝过来的启动参数-Xmx4g和容器limit完全脱节这在容器化改造过程中非常普遍隐蔽性极高。排查时看到容器limit是4Gi但JVM实际可能因为识别不到cgroup限制而使用了宿主机内存总量一启动就吃掉几个G这是k8s与docker在底层资源视图上的经典区别。5. 故障预防体系别等事故发生了再学排查5.1 监控指标与告警阈值的选择故障排查做得再好也只是事后补救。生产环境真正拉开差距的是预防体系。我自己的监控指标清单经过好几年迭代现在基本稳定不需要特别多但要覆盖关键路径。节点层我监控的是CPU使用率、内存使用率、根分区磁盘使用率、inode使用率以及节点的MemoryPressure和DiskPressure状态。Pod和容器层监控的是重启次数、OOMKilled事件、ImagePullBackOff事件、CrashLoopBackOff事件。网络层重点盯CoreDNS的请求错误率、网络插件PodCalico或Cilium的健康状态、节点网卡丢包率。存储层盯PVC的Pending事件和卷的IO延迟。有状态服务额外盯etcd的同步延迟指标etcd_server_leader_applied_index等。应用层我一般不去Prometheus里折腾响应时间直接用业务自带的链路追踪和中台监控。告警阈值我踩过太多坑太灵敏会被噪音淹没太迟钝等于没设。目前的一套经验值供参考CPU使用率75%持续15分钟、内存使用率80%持续10分钟、根分区磁盘75%持续15分钟触发警告85%持续5分钟触发严重节点NotReady持续30秒必须触发严重Pod单次OOMKilled即触发Pod重启次数5次/10分钟触发严重CoreDNS错误率超过1%持续5分钟触发严重。每个阈值都要根据业务调但大方向是可以接受短时间毛刺不能容忍长时间恶化。5.2 容量规划预留空间怎么算才合理容量规划这块我强烈建议在集群设计阶段就算清楚而不是等报警了再补。以一个8节点集群为例每个节点32C64G总共256C512G。系统组件每节点预留2C4Gkubelet和容器运行时每节点再预留1G内存这是硬性开销。剩下的可用计算量大约是240C480G。然后看业务侧的requests总和我个人习惯是控制在集群总容量的60%到70%之间极限不超过75%。为什么留这么多因为Pod的实际使用量会超过requests再加上突发流量、节点故障时的Pod重调度、以及未来业务的自然增长不留40%的缓冲就是在赌博。如果你算完发现requests总需求已经占到80%那别犹豫要么扩节点要么推动业务优化资源声明。另外Pod的requests与limits比例也要治理我见过最夸张的是一个业务requests写1m、limits写1000m它自己倒是永远不会被驱逐但一台节点上能堆出几千个这种Pod把节点负载打到天上。建议在每个namespace配置LimitRange强制要求limits与requests的比值不得超过某个上限比如3倍否则拒绝创建Pod。这种规则一开始推起来总有业务方抱怨但出事之后所有团队都会觉得真香。5.3 演练与巡检清单预防体系里第三块是演练。每年至少做一次节点故障模拟把一台核心节点直接shutdown观察控制面几分钟内完成Pod的重调度服务是否恢复正常。再做一次网络故障模拟停掉一个节点的网络插件DaemonSet看同节点的CoreDNS、业务Pod是否跟着异常验证网络拓扑的容错边界。这类演练不需要复杂的混沌工程工具K8s原生就有节点drain、cordon机制本质上和真实故障的干扰程度接近。巡检清单我固定每周过一遍kubectl get nodes看所有节点是否Readykubectl top nodes看资源水位kubectl get pods -A快速扫一遍有没有非Running状态的Pod再看kube-system里核心组件的Pod是否都在运行、镜像版本是否一致。巡检不是走过场我要求值班的人必须对发现异常后第一步做什么有肌肉记忆而不是把问题截图发群里就完事。5.4 别把宝押在单个组件上最后给一个偏架构层面的建议任何自认为核心的组件都不要以单体方式跑在集群里。etcd如果是单节点整个集群的命脉就悬在一根线上CoreDNS如果只有单副本全集群的域名解析就存在单点Ingress Controller如果只部署了一个副本入口流量全压在一个容器上。生产环境的哲学是在成本允许的范围内把关键路径上所有可能单点的东西都拆掉。这不是让基础设施无脑冗余而是说在性能允许的前提下多一个副本、多一层隔离就能把很多潜在故障的影响面缩小一半。6. 常见问题速查表把前面所有内容沉淀成一张速查表我平时也贴在自己工位上遇到类似问题直接对照着查。故障现象可能原因首选排查命令解决思路kubeadm init报apiserver not healthykubelet异常、静态Pod起不来、镜像拉取失败journalctl -u kubelet -f -n 100; crictl ps -a按cgroup driver、swap、镜像源顺序排查节点NotReady资源压力、kubelet宕了、网络插件异常kubectl describe node; df -h; free -h解除资源压力修复网络插件必要时重启kubeletPod一直Pending调度资源不足、PVC未绑定kubectl describe pod检查节点资源水位、PVC状态、污点和容忍度Pod反复CrashLoopBackOff业务启动异常、OOMKilled、配置错误kubectl logs; kubectl describe pod先确认是OOM还是业务错误分别处理镜像一直ImagePullBackOff镜像不存在、仓库认证失败、拉取超时kubectl describe pod检查image名称、registry配置、镜像源应用偶发超时CoreDNS问题、网络插件抖动、节点负载高kubectl get pods -n kube-system; kubectl top nodes排查DNS与网络链路扩副本与缓存Service访问不通选择器不匹配、endpoints为空、Ingress配置错kubectl get endpoints; kubectl describe svc核对service selector与Pod标签PVC一直Pending存储类不存在、容量不足、驱动未安装kubectl describe pvc检查StorageClass和存储插件状态GPU资源不生效device plugin未运行、label缺失、limits未声明kubectl describe node; nvidia-smi确认驱动、插件、资源上报、Pod声明etcd leader频繁切换IO延迟高、网络抖动、etcd存储压力大kubectl logs -n kube-system etcd检查磁盘IO与网络限流规避Pod被驱逐、节点MemoryPressure节点内存总量不足、requests与limits差距过大kubectl describe node; kubectl top nodes治理资源声明配置驱逐阈值和ResourceQuota我个人的一点收尾关于网上下载各种k8s权威指南第五版pdf这类资源我这么看书可以当字典查但真正让你长本事的一定是线上故障。我学K8s这几年最明显的进步都发生在处理完一个棘手的故障之后那种原来这个报错背后是这个机制的感觉是看多少PDF都换不来的。所以如果你正在学K8s我的建议是把基础概念过一遍之后赶紧找一套环境去部署、去制造故障、去修复故障踩坑越早代价越小。另一个小技巧也是我最后想分享的排障时把时间线记下来。几点几分出现什么现象、几点几分执行了什么命令、几点几分做了什么变更全部写到记事本里。这个习惯在故障发生的时候看不出价值但在复盘的时候价值巨大——因为你会发现很多所谓莫名其妙的故障其实是某个时间点的一个小操作埋下的地雷时间线会直接指到那颗雷的位置。很多时候高度紧张的排查现场是记不住这么多细节的但白纸黑字的时间线会替你的记忆兜底。这篇文章里讲的所有排查思路说到底就是这一件事冷静、分层、记录、再动手。
返回列表