kubectl 排障实战:jsonpath 精准取值、custom-columns、events 排序与 top 速查
线上 Pod 出问题,别一上来就 kubectl get pods 然后一堆 describe 翻半天。kubectl 本身带了一套很强的查询和排障能力,用好了定位问题能快好几倍。这篇不讲怎么装、怎么创建资源,只讲出问题时最该会的那几招命令:精准取字段、自定义列、按时间看事件、看谁在吃资源。全是能直接抄进终端的。
events 一定要按时间排序,默认顺序会误导你
排障第一反应是看事件,但很多人直接 kubectl get events,结果事件是乱序的(默认按资源名之类排,不是按时间),你根本看不出「先发生了什么、后发生了什么」。
正确姿势永远带排序:
bash
# 按事件最后发生时间排序,最新的在最下面
kubectl get events --sort-by='.lastTimestamp'
# 只看某个命名空间,并且盯着实时刷新
kubectl get events -n prod --sort-by='.lastTimestamp' -w
# 只看某个 Pod 相关的事件(排障单个 Pod 时最有用)
kubectl get events --field-selector involvedObject.name=my-pod-xxxx \
--sort-by='.lastTimestamp'
--field-selector involvedObject.name=<pod> 这招很多人不知道,能直接过滤出跟某个对象相关的事件,不用在几百条 events 里大海捞针。
kubectl top:先看谁在吃 CPU/内存
Pod 被 OOMKilled、节点负载高,先用 top 看实际用量(需要集群装了 metrics-server):
bash
# 看各节点资源用量
kubectl top nodes
# 看某命名空间 Pod 用量,按内存倒序,一眼看出内存大户
kubectl top pods -n prod --sort-by=memory
# 按 CPU 排序
kubectl top pods -n prod --sort-by=cpu
# 看某个 Pod 内每个容器分别用了多少(多容器 Pod 排障必备)
kubectl top pod my-pod-xxxx --containers
--sort-by=memory 排完,排最前面的往往就是内存泄漏或配置不当的那个。配合下面的 jsonpath 看它的 limits,就能判断是不是快撞上限了。
jsonpath:从一坨 YAML 里精准抠出你要的那个字段
kubectl get pod -o yaml 输出几百行,你其实只想知道「这个 Pod 的镜像是啥」「它调度到哪个节点了」「重启了几次」。用 -o jsonpath 直接抠:
bash
# 取某个 Pod 的镜像
kubectl get pod my-pod -o jsonpath='{.spec.containers[0].image}'
# 取它被调度到的节点
kubectl get pod my-pod -o jsonpath='{.spec.nodeName}'
# 取容器重启次数(排查 CrashLoop 时看这个)
kubectl get pod my-pod -o jsonpath='{.status.containerStatuses[0].restartCount}'
# 取上次退出的原因和 exit code(OOMKilled 就在这)
kubectl get pod my-pod \
-o jsonpath='{.status.containerStatuses[0].lastState.terminated.reason}'
批量场景更能体现价值。比如「列出所有 Pod 用到的镜像去重」------排查某个坏镜像影响面时特别有用:
bash
# range 遍历所有 Pod 的所有容器,打印镜像,再排序去重
kubectl get pods -A -o jsonpath='{range .items[*]}{range .spec.containers[*]}{.image}{"\n"}{end}{end}' \
| sort -u
再比如「找出所有没配 resources.limits 的 Pod」------这种 Pod 是节点被打爆的隐患:
bash
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.containers[*].resources.limits}{"\n"}{end}' \
| grep -vE 'map\[.+\]' # 过滤掉 limits 非空的,剩下的就是没配 limits 的
jsonpath 语法几个要点:.items[*] 遍历列表,{range}...{end} 做循环,{"\n"} 和 {"\t"} 插入换行和制表符方便后续处理。
custom-columns:把关心的字段拉成一张表
jsonpath 适合抠单个值,但要同时看多个字段并排成表格 ,用 custom-columns 更清爽。比如一眼看全部 Pod 的「名字 / 节点 / 状态 / 重启次数」:
bash
kubectl get pods -o custom-columns=\
'NAME:.metadata.name,'\
'NODE:.spec.nodeName,'\
'STATUS:.status.phase,'\
'RESTARTS:.status.containerStatuses[0].restartCount'
输出直接是对齐的表格:
NAME NODE STATUS RESTARTS
web-5d8f-abcde node-1 Running 0
web-5d8f-fghij node-2 Running 7
api-7c9-klmno node-1 Running 0
一眼就看出 web-5d8f-fghij 重启了 7 次,有问题。再比如排查「哪些 Pod 调度在哪些节点、用的什么镜像」:
bash
kubectl get pods -A -o custom-columns=\
'NS:.metadata.namespace,'\
'POD:.metadata.name,'\
'NODE:.spec.nodeName,'\
'IMAGE:.spec.containers[0].image'
custom-columns 和 jsonpath 的区别:前者出表格适合人看多字段,后者出裸值适合抠单值喂给脚本。
看日志的几个实用姿势
bash
# 看崩溃前的日志(容器已重启,当前实例的日志看不到问题了)
kubectl logs my-pod --previous
# 多容器 Pod 指定容器
kubectl logs my-pod -c sidecar
# 按标签一次看一组 Pod 的日志(比如一个 Deployment 的所有副本)
kubectl logs -l app=web --tail=50 --prefix
# 只看最近 5 分钟
kubectl logs my-pod --since=5m
--previous 是排查 CrashLoopBackOff 的关键:容器崩了会重启,当前实例的日志是重启后的、往往看不出崩溃原因,--previous 才能看到上一个挂掉的实例留下的日志。
kubectl explain:忘了字段怎么写就查它,别翻网页
写 YAML 记不清某个字段的层级和类型,不用去翻官网文档,本地就能查:
bash
# 查 Pod spec 下有哪些字段
kubectl explain pod.spec
# 深入查某个字段的子字段和含义
kubectl explain pod.spec.containers.resources
# 递归展开整棵字段树
kubectl explain pod.spec.containers --recursive
它读的是你集群当前 API server 的 schema,所以查出来的字段和你集群版本一定对得上,比搜到的旧文档靠谱。
一个组合拳:快速定位「集群里最不健康的 Pod」
把上面几招串起来,一行找出所有非 Running 且重启多的 Pod:
bash
# 列出所有 Pod,过滤掉 Running 的,再看谁重启次数高
kubectl get pods -A -o custom-columns=\
'NS:.metadata.namespace,POD:.metadata.name,STATUS:.status.phase,'\
'RESTARTS:.status.containerStatuses[0].restartCount' \
| grep -v Running
# 或者直接用 field-selector 只捞非 Running 的(server 端过滤,更快)
kubectl get pods -A --field-selector status.phase!=Running
--field-selector 是在 API server 端过滤的,比拉全量再本地 grep 快,尤其大集群。注意它支持的字段有限(主要是 status.phase、spec.nodeName、metadata.name 这些),不是所有字段都能用。
小结
- 看事件永远带
--sort-by='.lastTimestamp',默认乱序会误导时间线;定位单对象加--field-selector involvedObject.name=<pod>。 kubectl top nodes/pods --sort-by=memory快速揪出资源大户,多容器加--containers。- jsonpath 抠单值 (镜像、节点、重启次数、退出原因),配
{range}{end}做批量;custom-columns 拉多字段表格给人看。 - 排 CrashLoop 用
kubectl logs --previous看崩溃前日志;按组看日志用-l 标签 --prefix。 - 忘字段用
kubectl explain,读的是当前集群 schema 最靠谱;非 Running 快筛用--field-selector status.phase!=Running。
一句话记忆点:排障别只会 get 和 describe------events 要排序、字段用 jsonpath/custom-columns 精准取、崩溃日志加 --previous,这几招能把定位时间砍一半。