首页 / 资讯中心 / 文章详情

kubectl故障诊断四步穿刺法:Kubernetes分层排查实战

kubectl故障诊断四步穿刺法:Kubernetes分层排查实战 ★ FEATURED ARTICLE
1. 这不是命令清单而是 Kubernetes 故障现场的“听诊器”使用手册你有没有遇到过这样的时刻Pod 状态卡在 Pending 十分钟不动describe 输出密密麻麻几百行却找不到那句真正关键的报错Service 明明配置了 ClusterIPcurl 却直接超时日志里连请求影子都看不到Ingress 突然 503但后端所有 Pod 都是 Running 和 Ready——这时候翻文档、查 Stack Overflow、挨个试命令像在迷雾森林里徒手摸路。我带过的几个刚转云原生的运维同学第一周平均每天要问三次“kubectl get pods -n xxx 返回空是不是集群挂了”其实不是集群挂了是他们还没摸清 kubectl 这套诊断工具的真实逻辑它根本不是“查状态”的命令集而是一套分层穿透式故障定位系统——从资源编排层YAML、调度执行层Scheduler/Kubelet、网络通信层CNI/Service、到应用运行层容器进程/日志每一层都有专属的“听诊点”和“叩击音”。今天这篇不讲“kubectl get”“kubectl describe”怎么拼写而是拆解真实压测环境、灰度发布、跨集群迁移中高频复现的 7 类典型故障场景告诉你每条命令背后到底在读取哪个组件的哪块内存、调用哪个 API 的哪个字段、为什么加-o wide能救命、为什么--v6日志比describe更早暴露问题。核心关键词就三个kubectl 诊断链路、Kubernetes 分层故障模型、生产级排查节奏。适合正在搭建 SRE 工具链的平台工程师、需要快速响应线上告警的 DevOps 同学以及准备 CKAD/CKA 认证但总在实操题卡壳的备考者——因为考试不会考你“describe 命令语法”但一定会给你一个 CrashLoopBackOff 的 Pod要求你在 3 分钟内定位到是镜像拉取失败、还是 InitContainer 超时、抑或是 SecurityContext 权限拒绝。2. 诊断命令不是孤立动作而是按故障层级递进的“四步穿刺法”很多人把 kubectl 诊断当成随机组合技Pod 不起先get pods再describe pod接着logs最后exec进去翻/proc。这就像医生不问病史、不量血压、不听心音上来就开 CT——效率低、成本高、还容易漏掉关键线索。真正的 Kubernetes 诊断必须遵循分层穿透原则从最外层的资源声明层开始逐层向内验证每层只解决本层该管的问题绝不越界。我们团队在某金融客户核心交易链路的稳定性保障中将这套方法固化为“四步穿刺法”过去一年线上 P0 故障平均定位时间从 28 分钟压缩到 6 分钟以内。这个方法不是凭空设计而是严格对应 Kubernetes 架构的四层控制面2.1 第一穿刺资源编排层YAML 层——验证“你写的是否被正确接收”这是最容易被忽略的第一关。很多故障根本不是运行时问题而是 YAML 写错了但 Kubernetes 并不报错而是静默降级或跳过某些字段。比如你写了resources.limits.memory: 2Gi但忘了写requests.memoryKubernetes 会允许创建但调度器可能因无法评估资源需求而将 Pod 挂起又比如affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution里少了个nodeSelectorTerms整个亲和性规则直接失效Pod 被调度到不合规节点。此时kubectl get只能看到 Pod 名称和状态describe也只显示“Scheduled”但真相藏在kubectl get pod name -o yaml的输出里——你需要对比原始 YAML 和集群实际存储的 YAML看哪些字段被丢弃、哪些被自动补全、哪些值被强制转换。提示kubectl get默认只返回 API Server 缓存的摘要信息而kubectl get -o yaml会触发一次完整的对象序列化返回 etcd 中存储的完整对象。这就是为什么get -o yaml能发现describe看不到的字段丢失问题。实操中我们固定用这条命令做第一穿刺kubectl get pod nginx-7c85b4d9d-2xq9f -o yaml | grep -A 5 -B 5 resources\|affinity\|tolerations注意不是describe而是get -o yaml加精准grep。因为describe会对输出做大量格式化处理隐藏原始字段结构而故障往往就藏在字段嵌套层级或空值处理逻辑里。比如tolerations字段如果为空数组[]describe会显示“Tolerations: ”但get -o yaml会明确写出tolerations: []这直接决定了 Pod 是否能容忍污点。我们曾在一个混合架构集群中遇到 Node 有keyvalue:NoSchedule污点但 Pod 的 tolerations 是空对象{}而非空数组[]导致调度失败——这个差异describe完全不提示只有get -o yaml能暴露。2.2 第二穿刺调度执行层Scheduler/Kubelet 层——验证“谁决定它在哪跑谁负责把它跑起来”当 Pod 卡在 Pending 或 ContainerCreating问题大概率出在这层。kubectl describe pod就是专为此设计的第二穿刺工具但它绝不是简单罗列事件。关键在于读懂事件流的时间轴和因果链。比如以下典型事件序列Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m default-scheduler Successfully assigned default/nginx-7c85b4d9d-2xq9f to node-03 Warning FailedCreatePodSandBox 1m kubelet, node-03 Failed create pod sandbox: rpc error: code Unknown desc failed to set up sandbox container a1b2c3 network for pod nginx-7c85b4d9d-2xq9f: networkPlugin cni failed...表面看是 CNI 失败但注意Scheduled事件发生在 2 分钟前而FailedCreatePodSandBox在 1 分钟前——说明调度器早已完成工作问题出在 Kubelet 启动沙箱阶段。此时你应该立刻切到目标节点node-03用kubectl get node node-03 -o wide查看其 Conditions重点看Ready和NetworkUnavailable状态再用kubectl describe node node-03 | grep -A 10 Conditions看详细原因。我们曾在一个升级 CNI 插件的集群中发现NetworkUnavailableCondition 为 True但describe node显示原因是CNI plugin not initialized这直接指向 CNI DaemonSet 未部署或 Crash而非网络策略配置错误。注意describe node的 Events 区域永远为空因为 Node 事件不记录在 API Server必须用kubectl get events --field-selector involvedObject.kindNode,involvedObject.namenode-03才能看到 Kubelet 上报的底层事件。2.3 第三穿刺网络通信层CNI/Service 层——验证“它能否被找到能否被访问”Pod Running 且 Ready但服务不可达这是第三层的典型战场。这里kubectl get endpoints是黄金命令它直击 Service 到 Pod 的映射关系。很多人以为get svc显示 ClusterIP 就万事大吉但 ClusterIP 只是 iptables/ipvs 规则的入口真正决定流量走向的是 Endpoints 对象。执行kubectl get endpoints nginx-service如果输出是none说明 Service 的 selector 根本没匹配到任何 Pod——这时你要立刻检查 Pod 的 labels 是否与 Service 的 selector 一致注意大小写、连字符、版本号等细节。我们曾在线上遇到一个诡异问题Service selector 是app: nginx-v2而 Pod label 是app: nginx-v2.1看似接近但 Kubernetes 的 label selector 是精确匹配v2.1不等于v2Endpoints 为空流量完全无法进入。更深层的网络诊断要用kubectl get svc -o wide它会显示每个 Service 关联的 Endpoint IPs。如果看到 IP 是10.244.1.5,10.244.2.7这类 Pod IP说明 Endpoints 正常如果显示None或127.0.0.1则可能是 kube-proxy 异常或 iptables 规则损坏。此时不要急着重启 kube-proxy先用kubectl get pods -n kube-system | grep kube-proxy确认其状态再用kubectl logs -n kube-system kube-proxy-pod查看日志中是否有Failed to list *v1.Service等同步错误——这往往指向 RBAC 权限缺失而非网络本身故障。2.4 第四穿刺应用运行层容器进程/日志层——验证“它是否真在干活干得是否正常”当以上三层都通过Pod 仍 CrashLoopBackOff就必须深入容器内部。kubectl logs是第四穿刺的起点但关键在参数组合。默认logs只返回最新容器的日志而很多应用启动失败会在 InitContainer 阶段就退出。所以必须加--all-containerstrue和--previoustruekubectl logs nginx-7c85b4d9d-2xq9f --all-containerstrue --previoustrue--all-containerstrue确保不遗漏 InitContainer 和 Sidecar--previoustrue获取上一次崩溃容器的日志——因为当前容器可能刚启动就挂了日志为空。我们曾在一个 Java 应用中发现主容器日志全是Starting...毫无错误但--previoustrue日志显示java.lang.OutOfMemoryError: Metaspace这才是根因。如果日志仍无有效信息就要kubectl exec进入容器。但注意exec默认进入主容器而有些故障需要检查 InitContainer 的文件系统。此时用kubectl exec nginx-7c85b4d9d-2xq9f -c init-config -- ls /config指定容器名。更关键的是exec后不要只ps aux而要结合cat /proc/1/cmdline看进程真实启动命令注意\x00分隔符用lsof -i :8080检查端口监听状态——很多应用配置了错误的监听地址如127.0.0.1:8080而非0.0.0.0:8080导致 Service 流量无法到达。3. 七条高频诊断命令的“暗黑参数”与生产级用法网上教程教的kubectl get podskubectl describe pod都是表层用法真正决定排查效率的是那些藏在文档角落、但能瞬间定位问题的“暗黑参数”。这些参数不是炫技而是针对生产环境复杂性的精准设计。下面逐条拆解我们团队在金融、电商、游戏三大业务线中验证过的七条核心命令及其不可替代的参数组合。3.1kubectl get不只是“查”而是“过滤投影聚合”的数据透视kubectl get常被当作最简单的命令但它在诊断中的价值远超想象。关键在于三个参数-llabel selector、-o custom-columns自定义列、--sort-by排序。比如排查某个微服务的所有实例是否都 Readykubectl get pods -l apppayment-service --sort-by.status.phase -o custom-columnsNAME:.metadata.name,STATUS:.status.phase,READY:.status.containerStatuses[*].ready,RESTARTS:.status.containerStatuses[*].restartCount,NODE:.spec.nodeName这条命令做了四件事-l apppayment-service精准筛选避免在上千个 Pod 中大海捞针--sort-by.status.phase按 Phase 排序Pending、Running、Succeeded 会自动分组一眼看出异常状态聚集区-o custom-columns只显示关键字段READY列用[*]展开所有容器状态避免单容器 Pod 的误判NODE列直接显示调度节点方便后续describe node快速切入。实操心得custom-columns的字段路径必须精确到 JSON 结构。.status.containerStatuses[*].ready中的[*]表示遍历数组而.status.phase是单值字段。如果写成.status.containerStatuses.ready会返回none因为containerStatuses是数组不是对象。另一个高频场景是查资源配额超限。kubectl get quota -n production只显示配额对象但真正要看的是已使用量。用-o jsonpath投影kubectl get quota -n production -o jsonpath{range .items[*]}{.metadata.name}{\t}{.status.hard}{\t}{.status.used}{\n}{end}输出类似compute-resources {limits.cpu:4,limits.memory:8Gi,requests.cpu:2,requests.memory:4Gi} {limits.cpu:3800m,limits.memory:6240Mi,requests.cpu:1900m,requests.memory:3120Mi}。对比hard和used就能判断是 CPU 还是 Memory 先触顶。我们曾在一个批处理任务集群中发现requests.cpu使用率达 95%但limits.cpu仅 40%这说明调度器因 Request 不足而拒绝新 Pod而非容器被 OOM Kill。3.2kubectl describe事件流的“时间机器”与因果链分析describe的核心价值不在字段罗列而在 Events 时间轴。但默认describe只显示最近 10 条事件而故障链可能跨越数小时。必须用--show-eventsfalse关闭默认事件再用kubectl get events单独查询kubectl get events --sort-by.lastTimestamp --field-selector involvedObject.namenginx-7c85b4d9d-2xq9f,involvedObject.kindPod --all-namespaces--sort-by.lastTimestamp按事件发生时间倒序最新事件在最前--field-selector精准过滤避免被其他 Pod 事件干扰。更重要的是lastTimestamp是事件聚合后的时间而firstTimestamp是首次发生时间——如果lastTimestamp和firstTimestamp相差很大说明该事件反复发生比如FailedMount持续 30 分钟意味着存储卷一直挂载失败。我们曾用此法定位一个顽固故障describe pod显示ContainerCreatingEvents 里只有FailedCreatePodSandBox但get events发现firstTimestamp是 2 小时前lastTimestamp是 1 秒前且count字段显示127。这说明 Kubelet 每 10 秒重试一次但每次都失败。此时立刻查kubectl describe node的 Conditions果然发现DiskPressure为 Truekubectl df -h显示/var/lib/kubelet分区 100% 满——根因是日志轮转配置错误而非网络或镜像问题。3.3kubectl logs多容器、多实例、多时间点的日志“三维检索”logs命令的威力在于三维检索能力容器维度-c、实例维度-l、时间维度--since。生产环境中一个微服务通常有数十个 Pod 副本每个 Pod 有主容器、init 容器、sidecar 容器。盲目logs某个 Pod可能错过真正出问题的实例。正确姿势是# 查所有 payment-service Pod 的主容器最近 5 分钟错误日志 kubectl logs -l apppayment-service --since5m --prefix --all-containerstrue 21 | grep -i error\|exception\|fail # 查指定 Pod 的所有容器含 init的上一次崩溃日志 kubectl logs nginx-7c85b4d9d-2xq9f --all-containerstrue --previoustrue --tail100--prefix参数会在每行日志前加上pod-name/container-name前缀避免日志混杂无法溯源--tail100限制行数防止大日志阻塞终端。我们在线上压测时用--since30s配合watch -n 1实时监控新错误watch -n 1 kubectl logs -l appapi-gateway --since30s 21 | grep -i 500\|timeout这相当于给日志流装上了实时报警器。3.4kubectl exec不只是“进容器”而是“进程级诊断探针”exec最危险也最有用。很多人exec进去就lscat但真正的诊断要直击进程本质。三个必用技巧查进程树ps auxf比ps aux多显示父子进程关系能发现僵尸进程或异常子进程查文件描述符lsof -p 1 | wc -l统计 PID 1主进程打开的文件数超过 65535 很可能触发Too many open files错误查网络连接ss -tulnp | grep :8080比netstat更快显示监听端口及对应进程。我们曾在一个 Node.js 应用中exec进去发现ps aux显示主进程在但curl localhost:3000超时。执行ss -tulnp发现没有进程监听3000端口再查cat /proc/1/cmdline发现启动命令是node server.js --port3001原来配置文件被覆盖应用监听了错误端口。exec的价值就是把黑盒变成白盒。3.5kubectl top资源使用的“热力图”而非静态快照top命令依赖 Metrics Server但它提供的不是绝对数值而是相对热力。kubectl top nodes显示各节点 CPU/Memory 使用率但要注意Memory 使用率是working_set工作集不是 RSS它反映的是进程实际活跃内存比free -h更准确。而kubectl top pods的关键在于-l参数kubectl top pods -l apporder-service --sort-bymemory --no-headers | head -10按内存使用排序找出 Top 10 内存消耗者。我们曾用此法发现一个订单服务 Pod 内存使用达 3.2Gi而 Request 只有 512Mi立即触发kubectl describe pod查QoS Class确认是 Burstable 类型再结合kubectl logs查 GC 日志最终定位到内存泄漏。3.6kubectl port-forward本地调试的“隧道协议”绕过所有网络策略当 Ingress 或 Service 不可用port-forward是最安全的调试通道。它不经过集群网络平面直接建立本地端口到 Pod 的 TCP 隧道。关键参数是--addresskubectl port-forward svc/payment-service 8080:80 --address0.0.0.0--address0.0.0.0允许外部设备如手机、测试机通过宿主机 IP 访问这对跨设备联调至关重要。我们曾在一个银行客户现场防火墙严格限制集群内外通信但port-forward因走本地回环完美绕过所有策略让测试团队直接用 Postman 调试。3.7kubectl wait自动化诊断的“守门人”让脚本具备人类判断力wait命令常被忽视但它让自动化脚本拥有了“等待条件满足”的智能。比如滚动更新后等待所有 Pod Readykubectl wait --forconditionready pod -l appweb-ui --timeout300s --all--timeout300s设置超时避免无限等待--all作用于所有匹配 Pod。更强大的是复合条件kubectl wait --forconditionavailable deployment/web-ui --forconditionprogressing deployment/web-ui --timeout120s同时等待 Deployment 的available有足够副本提供服务和progressing更新进行中两个条件确保更新既成功又未卡住。我们将其集成到 CI/CD 流水线在kubectl apply后自动执行失败则立即回滚将人工介入从“必须”变为“可选”。4. 生产环境故障排查的“黄金两分钟”实战流程再好的命令没有节奏也是乱拳。我们在多个千万级用户 App 的 SRE 实践中提炼出一套“黄金两分钟”标准化排查流程。这不是理论框架而是写进 OnCall 手册、经受过上百次 P0 故障检验的操作 SOP。流程核心是用最短路径排除 80% 的常见故障把深度分析留给剩余 20% 的疑难杂症。4.1 第 0-30 秒状态快扫——用三条命令建立全局视图接到告警第一反应不是describe而是并行执行三条命令30 秒内获取集群健康快照# 1. 节点状态看是否有 NotReady 节点 kubectl get nodes -o wide # 2. 核心组件看 kube-system 下关键 Pod 是否 Running kubectl get pods -n kube-system | grep -E (coredns|kube-proxy|calico-node|metrics-server) # 3. 告警服务用 label 快速定位目标服务所有 Pod 状态 kubectl get pods -l appyour-app-name --sort-by.status.phase这三步能快速区分故障范围如果get nodes显示某个节点 NotReady问题在节点层如果kube-system里 coredns 是 CrashLoopBackOff整个 DNS 解析瘫痪所有服务都会连带失败如果目标服务 Pod 全部 Pending则是资源不足或调度器问题。我们曾在一个电商大促期间30 秒内通过get nodes发现node-05状态为NotReady,SchedulingDisabled立刻 ssh 登录该节点执行systemctl status kubelet发现磁盘满导致 kubelet 退出清理后 2 分钟恢复——整个过程比等describe输出快 5 倍。4.2 第 30-90 秒聚焦穿透——根据状态选择“四步穿刺”路径基于快扫结果立即选择穿透路径。这里给出决策树Pod 状态为 Pending→ 直接kubectl describe pod name重点看 Events 中FailedScheduling原因。常见原因0/5 nodes are available: 5 node(s) had taints that the pod didnt tolerate.污点不兼容或0/5 nodes are available: 5 Insufficient cpu.CPU 不足。此时kubectl describe node查具体节点资源或kubectl get nodes -o wide看 Allocatable。Pod 状态为 ContainerCreating→kubectl describe pod看FailedCreatePodSandBox或FailedMount。前者查节点 CNI后者查kubectl describe pv/pvc看存储卷状态。Pod 状态为 Running 但 NotReady→kubectl logs name --previoustrue查上一次崩溃日志若无日志kubectl exec name -- cat /proc/1/status | grep -E State|voluntary_ctxt_switches看进程状态和上下文切换次数过高说明 CPU 争抢严重。Pod 状态为 CrashLoopBackOff→kubectl logs name --previoustrue --tail20090% 的问题在这里暴露。如果日志为空kubectl exec name -- ps auxf看进程是否真的启动。注意CrashLoopBackOff的 BackOff 时间是指数退避的第一次失败后等 10 秒第二次 20 秒第三次 40 秒……所以logs --previoustrue必须在 BackOff 间隙执行否则会拿到空日志。4.3 第 90-120 秒交叉验证——用两条命令锁定根因当单条命令无法确定时必须交叉验证。最常用的是get endpointsget pods组合# 查 Service 关联的 Endpoint IPs kubectl get endpoints service-name # 查这些 IP 对应的 Pod 是否存在且 Ready kubectl get pods -o wide | grep endpoint-ip如果endpoints有 IP但get pods查不到对应 Pod说明 Pod 已被删除但 Endpoint 未及时清理etcd 事件延迟如果endpoints为空但get pods有匹配 Pod则是 label selector 错误。我们曾用此法在一小时内定位一个跨集群同步故障主集群endpoints正常灾备集群endpoints为空但get pods显示灾备集群 Pod 存在——最终发现是灾备集群的 Service YAML 中selector写成了主集群的 label。另一组交叉验证是top nodestop podskubectl top nodes --sort-bycpu kubectl top pods -l appapp-name --sort-bycpu --no-headers | head -5如果某节点 CPU 使用率 95%而该节点上的 Pod CPU 使用率总和仅 30%说明问题在系统进程如 kubelet、dockerd如果 Pod CPU 总和达 90%则问题在应用层。这种交叉能快速区分是基础设施问题还是应用问题。4.4 超过 120 秒深度挖掘——启用高级诊断模式如果两分钟内未定位说明进入深度故障区。此时启用“高级诊断模式”核心是开启 API Server 和 Kubelet 的详细日志# 查看 API Server 最近 5 分钟错误日志需有权限 kubectl logs -n kube-system api-server-pod --since5m | grep -i error\|warn # 查看目标节点 Kubelet 日志需 ssh 到节点 journalctl -u kubelet --since 2 minutes ago | grep -i pod.*nginx\|sandbox同时用kubectl get --raw直接调用 API# 获取 Pod 的完整 API 对象绕过 kubectl 缓存 kubectl get --raw /api/v1/namespaces/default/pods/nginx-7c85b4d9d-2xq9f | jq .status # 查看 Scheduler 的调度决策日志需开启 --v4 kubectl logs -n kube-system scheduler-pod --since10m | grep nginx-7c85b4d9d-2xq9f--raw参数是 kubectl 的隐藏武器它直接透传 HTTP 请求到 API Server返回原始 JSON不受 kubectl 版本或缓存影响。我们曾用此法在一个版本混乱的集群中确认describe pod显示的NodeName是缓存旧值而--raw返回的spec.nodeName才是真实调度结果。5. 那些文档不会写的“踩坑实录”与独家技巧所有教程都教你命令怎么写但没人告诉你为什么这么写、什么情况下会失效、以及如何从失败中反推真相。这些才是十年一线踩出来的真金。下面分享我们在金融、政务、IoT 三大严苛场景中总结出的 5 条血泪经验。5.1kubectl describe的“幻觉陷阱”Events 不是真相只是调度器的“一面之词”describe pod的 Events 区域有个致命陷阱它只显示调度器Scheduler和 Kubelet 上报的事件而不显示 API Server 的校验失败事件。比如你提交了一个 YAML其中spec.containers[0].ports[0].containerPort写成了字符串8080而非整数8080API Server 会拒绝创建返回Invalid value: 8080: spec.containers[0].ports[0].containerPort: Invalid value: 8080: must be of type int但这个错误永远不会出现在describe pod的 Events 里因为 Pod 根本没创建成功。此时kubectl get pods返回空describe pod报错Error from server (NotFound)。正确做法是kubectl apply -f nginx.yaml --dry-runclient -o yaml先做客户端校验或kubectl apply -f nginx.yaml --validatetrue强制服务端校验Kubernetes 1.19 已废弃但原理相同。实操心得当kubectl apply报错但get pods为空时90% 的概率是 YAML 语法或类型错误。用yamllint预检 YAML用kubectl convert检查 API 版本兼容性比在describe里找不存在的事件高效十倍。5.2kubectl logs的“时间错位”容器重启后--previous日志可能不属于你--previoustrue参数有个隐蔽行为它获取的是上一个容器实例的日志但这个“上一个”可能不是你认为的那个。比如一个 Pod 有主容器和 init 容器init 容器先失败退出主容器从未启动此时logs --previoustrue返回的是 init 容器的日志而非主容器的。更复杂的是如果 Pod 被驱逐Evicted后重建--previous日志属于被驱逐的旧 Pod而新 Pod 的日志是空的。我们曾在一个日志分析平台中因误读--previous日志将 init 容器的配置错误当成主应用的启动失败浪费 3 小时。解决方案是永远用kubectl get pod name -o wide查RESTARTS列。如果RESTARTS为 0--previous无意义如果RESTARTS 0再结合kubectl get pod name -o jsonpath{.status.containerStatuses[?(.namemain)].restartCount}精确查主容器重启次数确保--previous针对正确容器。5.3kubectl exec的“权限幻觉”你能exec进去不代表你能诊断exec成功只证明 Pod 的容器运行时Docker/containerd正常但容器内部可能处于“半死”状态。比如一个 Java 应用JVM 进程在但 Spring Boot Actuator 的/actuator/health接口返回DOWN因为数据库连接池耗尽。此时exec进去ps aux看到 java 进程netstat看到端口监听但服务实际不可用。必须用应用层探针验证kubectl exec nginx-7c85b4d9d-2xq9f -- curl -s http://localhost:8080/actuator/health | jq .status如果返回UP说明应用层健康如果返回DOWN再查kubectl exec name -- curl -s http://localhost:8080/actuator/metrics | jq .names看指标列表确认 Actuator 是否启用。我们曾在一个医疗系统中exec查到进程正常但curl /actuator/health返回OUT_OF_SERVICE最终发现是 ConfigMap 挂载的数据库密码文件权限为600而应用用户无读取权限——exec用户是 root能读但应用用户不能。5.4kubectl get events的“时间黑洞”默认只查最近 1 小时老事件全丢kubectl get events默认只返回最近 1 小时的事件这是 Kubernetes 的硬编码限制--max-events默认 100且事件 TTL 为 1 小时。当故障发生在几小时前get events返回空你会误以为“没发生过事件”。真相是事件已被 API Server 清理。解决方案有两个提前配置在 API Server 启动参数中添加--event-ttl48h延长事件保留时间事后补救用kubectl get --raw /api/v1/events?fieldSelectorinvolvedObject.namepod-name直接调用 API绕过 kubectl 的默认限制。我们曾在一次跨夜故障复盘中用--raw调用找回了 3 小时前的FailedAttachVolume事件确认是存储后端凌晨维护导致而非集群配置问题。5.5kubectl top的“数据污染”Metrics Server 采集的是采样数据不是实时值kubectl top nodes/pods的数据来自 Metrics Server而 Metrics Server 从 Kubelet 的 /metrics
阅读完成 · 觉得有帮助?
咨询建站