
1. 这不是“看一眼”那么简单kubectl 查资源使用本质是 K8s 集群健康诊断的日常切片你敲下kubectl top nodes终端吐出几行数字——CPU 和内存使用率。看起来很简单对吧但如果你真以为这只是个“监控仪表盘的命令行快照”那接下来的故障排查、容量规划、甚至一次莫名其妙的 Pod 驱逐都会让你反复怀疑人生。我干了七年 K8s 运维和平台建设从单节点 Minikube 搭建测试环境到管理过 300 节点、承载日均 2000 万请求的生产集群最常被问的问题不是“怎么部署服务”而是“为什么这个 Pod 总是 Pending”、“那个节点 CPU 显示 95%但实际业务完全没卡顿”、“top 命令显示内存用得不多可 OOMKilled 却天天报”。这些问题90% 的根源不在应用代码里而在你对kubectl top这类基础命令背后数据来源、计算逻辑、采样机制和局限性的理解偏差上。核心关键词kubectl、K8s、节点、Pod、资源使用情况它们串起来的不是一条命令路径而是一整套资源可观测性链条。kubectl top本身不采集数据它只是个“翻译器”——把 Metrics Server 暴露的聚合指标用人类能读的格式呈现出来。而 Metrics Server 又依赖于每个节点上的 kubelet 汇报的 cAdvisor 数据cAdvisor 则直接扒进程的/proc文件系统和 cgroup 统计。这一层套一层任何一个环节掉链子你看到的数字就可能是“假象”。比如你看到某个 Pod 内存使用率 80%但实际它可能刚被 Linux OOM Killer 干掉只是还没来得及上报状态又或者你看到节点 CPU 使用率只有 40%但kubectl describe node却显示Allocatable资源几乎耗尽因为大量未设置requests的 Pod 正在无序抢占——这根本不是“使用率低”而是“调度失控”。所以这篇内容不是教你“五个命令搞定监控”而是带你拆开kubectl top这个黑盒子搞清楚它到底在看什么、怎么看、为什么有时候不准、以及当它不准时你该信谁、该查什么、该补什么。适合两类人一类是刚接触 K8s 的开发者或运维想真正理解集群资源水位另一类是已经会用top命令但在压测时发现指标和现象对不上、在扩容时拿不准该加多少节点的资深同学。你不需要提前装好 Metrics Server也不需要会写 Prometheus 查询语句——我们从kubectl这个最熟悉的入口开始一层层往下挖直到看见 Linux 内核的 cgroup 统计原生值。这才是你在生产环境里能真正靠得住的“资源使用情况”。2. 为什么kubectl top不是万能钥匙设计思路与底层依赖全解析2.1 它不是监控系统而是指标消费端很多人误以为kubectl top是 K8s 自带的监控功能就像 Docker 的docker stats一样。这是最大的认知陷阱。Docker 的stats是直接调用容器运行时如 containerd的 API实时读取 cgroup 文件延迟低、精度高、无需额外组件。而kubectl top完全不同它是一个纯粹的客户端命令自身不采集、不存储、不计算任何指标。它的全部工作就是向集群中一个叫Metrics Server的独立服务发起 HTTP GET 请求然后把返回的 JSON 数据格式化成表格输出。提示Metrics Server 是一个轻量级、内存型的指标聚合器它不持久化数据只保留最近几分钟的滚动窗口。它不替代 Prometheus 这样的长期存储监控系统它的定位非常明确——为kubectl top、Horizontal Pod AutoscalerHPA、kubectl describe中的资源分配信息提供实时、低延迟的指标支撑。这意味着kubectl top的可用性、准确性和时效性100% 取决于 Metrics Server 的健康状况。如果 Metrics Server Pod 崩溃、资源不足、网络不通或者它自己无法从 kubelet 拉取数据那么kubectl top nodes就会报错error: the server is currently unable to handle the request而不是返回“0%”。这不是你的命令错了是整个指标链路断了。我见过太多团队在集群升级后忘记重新部署 Metrics Server结果所有top命令都失效大家第一反应是“kubectl 坏了”花了半天时间查 kubectl 版本兼容性最后发现只是 Metrics Server 的 Deployment YAML 里镜像 tag 写错了。2.2 数据源头kubelet → cAdvisor → Metrics Server 的三级接力Metrics Server 的数据从哪来答案是每个节点上的kubelet。kubelet 作为节点代理内置了一个叫cAdvisor的组件Container Advisor。cAdvisor 是 Google 开源的容器监控代理它不依赖任何外部服务直接读取宿主机上所有容器的 cgroup 文件如/sys/fs/cgroup/memory/kubepods.slice/.../memory.usage_in_bytes和/proc信息如/proc/[pid]/stat进行原始统计。它暴露一个本地 HTTP 接口默认:10250/metrics/cadvisorMetrics Server 就通过这个接口定期默认 60 秒轮询所有节点的 kubelet拉取原始指标。这里的关键细节是cAdvisor 统计的是容器进程组cgroup的资源消耗不是 Pod 的“逻辑资源”。一个 Pod 里如果有两个容器cAdvisor 会分别统计它们各自的 CPU 时间和内存用量然后 Metrics Server 把它们加总作为该 Pod 的“总用量”。但问题来了如果一个容器崩溃退出它的 cgroup 可能还残留着历史数据如果一个容器启动失败cgroup 根本没创建cAdvisor 就统计不到它。这就是为什么你有时会看到kubectl top pod显示某个 Pod 的 CPU 是 0m但kubectl get pod状态却是CrashLoopBackOff——因为容器根本没跑起来自然没 cgroup也就没数据可报。2.3 为什么top显示的“使用率”常常让人困惑kubectl top nodes输出的 CPU 使用率单位是mmillicores比如1234m表示 1.234 核。这个数字是怎么算出来的它不是当前 CPU 时间 / 总 CPU 时间的简单百分比。cAdvisor 计算的是过去 60 秒内该 cgroup 所有线程在 CPU 上实际运行的时间总和除以 60 秒。也就是说这是一个“平均负载”的瞬时快照不是“占用率”。举个例子一个 4 核节点如果过去 60 秒内所有容器加起来总共用了 120 秒的 CPU 时间意味着它们在 4 个核上并行跑了 30 秒那么top就会显示1200m1.2 核而不是30%。这个设计是为了让 HPA 能基于绝对资源量做扩缩容决策而不是被百分比误导。内存就更微妙了。kubectl top显示的是memory.usage即当前 cgroup 的内存使用字节数。但它不等于 RSSResident Set SizeRSS 是进程实际占用的物理内存页。memory.usage包含了 page cache文件缓存和 swap如果启用。一个大量读写文件的 Podmemory.usage可能高达 2GB但 RSS 可能只有 500MB其余 1.5GB 是内核为它缓存的文件页。这些缓存是可回收的当其他进程需要内存时Linux 会自动释放。所以kubectl top pod显示内存用了 90%不一定代表内存紧张可能只是它“很会用缓存”。2.4 选型逻辑为什么 Metrics Server 是唯一选择而非 Prometheus你可能会问我们已经有 Prometheus 了为什么还要 Metrics Server为什么不直接用kubectl去查 Prometheus答案是职责分离与性能边界。Prometheus 是一个通用、强大的监控和告警系统它通过 Pull 模式从各种 Exporter包括 kube-state-metrics、node-exporter拉取指标存储在 TSDB 里支持复杂查询和长期趋势分析。但它不适合做kubectl top这种低延迟、高并发的即时查询。想象一下当你执行kubectl top nodes集群有 100 个节点Metrics Server 只需向 100 个 kubelet 发起 100 个轻量 HTTP 请求几秒内就能汇总完毕。而如果让kubectl去查 Prometheus它得先发起一个 PromQL 查询如sum by (instance) (container_memory_usage_bytes{container!})Prometheus 得从磁盘读取最近的数据块、做聚合、再返回 JSON——这个过程可能要几百毫秒到几秒且在高并发时容易成为瓶颈。Metrics Server 的设计哲学就是“够用就好”它只存最近 2 分钟的数据只暴露cpu/usage_rate和memory/usage这两个最关键的指标不做任何告警、不存历史、不支持自定义标签。这种极致的简化换来了极高的可靠性和极低的资源开销通常一个 Pod 只需 50Mi 内存。它不是要取代 Prometheus而是和 Prometheus 形成互补Metrics Server 负责“此刻集群水位”的快速感知Prometheus 负责“过去一小时内存泄漏趋势”的深度分析。我在给客户做架构评审时第一条建议永远是“Metrics Server 必装Prometheus 按需装但两者不能互相替代。”3. 核心实操从零开始部署、验证与精准解读kubectl top输出3.1 部署 Metrics Server三步走拒绝“一键脚本”陷阱很多教程告诉你kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.3/components.yaml一行搞定。这在演示环境没问题但在生产环境这是埋雷。我亲眼见过三个因“一键部署”导致的线上事故一个是镜像拉取超时Metrics Server 启动失败整个集群的 HPA 失效一个是 RBAC 权限太宽被安全团队勒令下线还有一个是 TLS 证书配置错误导致 kubelet 拒绝 Metrics Server 的 HTTPS 请求。正确的做法是分三步每一步都做验证第一步下载并审查 YAML# 不要直接 apply 远程 URL先下载到本地 curl -L https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.3/components.yaml -o metrics-server.yaml # 重点检查三处 # 1. image 字段确认镜像仓库是否可达tag 是否稳定v0.6.3 是当前推荐稳定版 # 2. args 部分确保有 --kubelet-insecure-tls仅用于测试环境或 --kubelet-certificate-authority生产环境必须 # 3. serviceAccount 和 ClusterRoleBinding确认权限最小化不要有 cluster-admin第二步生产环境 TLS 配置关键Metrics Server 默认用 HTTPS 连接 kubelet需要 kubelet 的 CA 证书。生产环境绝不能用--kubelet-insecure-tls。正确做法是在 kubelet 启动参数中确保--rotate-certificatestrue和--cert-dir/var/lib/kubelet/pki已配置。将 kubelet 的 CA 证书通常是/var/lib/kubelet/pki/ca.crt复制到 Metrics Server 的 ConfigMap 中。修改metrics-server-deployment.yaml的argsargs: - --cert-dir/tmp - --secure-port4443 - --kubelet-preferred-address-typesInternalIP,ExternalIP,Hostname - --kubelet-use-node-status-port - --kubelet-certificate-authority/tmp/ca.crt # 指向 ConfigMap 挂载的证书然后挂载 ConfigMapvolumeMounts: - name: ca-volume mountPath: /tmp/ca.crt subPath: ca.crt volumes: - name: ca-volume configMap: name: metrics-server-ca第三步部署与验证# 创建 ConfigMap kubectl create configmap metrics-server-ca --from-fileca.crt./ca.crt -n kube-system # 应用修改后的 YAML kubectl apply -f metrics-server.yaml # 等待 Pod Running kubectl get pods -n kube-system | grep metrics-server # 验证 Metrics Server 自身健康 kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes | jq . # 如果返回 JSON 数组说明 Metrics Server 已就绪注意kubectl get --raw是验证 Metrics Server 是否正常工作的黄金标准。它绕过了kubectl top的格式化层直接查看原始 API 响应。如果这里报错connection refused或no endpoints available说明 Metrics Server 的 Service 或 Deployment 有问题而不是kubectl top命令的问题。3.2kubectl top nodes不只是看数字更要读懂“Allocatable”与“Capacity”执行kubectl top nodes后你会看到类似这样的输出NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% node-01 1234m 30% 4.2Gi 52% node-02 876m 21% 3.8Gi 47%新手常犯的错误是只盯着CPU%和MEMORY%这两列。但真正决定集群能否接纳新 Pod 的是kubectl describe node里的Allocatable字段。让我们对比一下# 先看 top 的“使用率” kubectl top nodes # 再看 describe 的“可分配资源” kubectl describe node node-01 | grep -A 10 Allocatable输出会是Allocatable: cpu: 3900m memory: 15625520Ki ... Capacity: cpu: 4 memory: 16384Mi注意Capacity是节点物理资源总量4 核 4000mAllocatable是 K8s 实际能调度给 Pod 的资源量3900m。差额100m是 K8s 为系统组件kubelet、dockerd、systemd预留的资源。kubectl top的CPU%是1234m / 3900m ≈ 31%而不是1234m / 4000m。所以top的百分比是基于Allocatable计算的这非常合理——因为调度器只关心Allocatable。但问题在于top显示的1234m是当前所有 Pod 的 CPU 使用总和。而Allocatable是3900m。这看起来还有2666m的余量。可为什么新 Pod 还是 Pending因为kubectl describe node的Conditions部分会告诉你真相Conditions: Type Status LastHeartbeatTime Reason Message ---- ------ ----------------- ------ ------- OutOfDisk False Thu, 01 Jan 1970 00:00:00 0000 KubeletHasSufficientDisk kubelet has sufficient disk space available MemoryPressure False Thu, 01 Jan 1970 00:00:00 0000 KubeletHasSufficientMemory kubelet has sufficient memory available DiskPressure False Thu, 01 Jan 1970 00:00:00 0000 KubeletHasNoDiskPressure kubelet has no disk pressure PIDPressure False Thu, 01 Jan 1970 00:00:00 0000 KubeletHasSufficientPID kubelet has sufficient PID available Ready True Thu, 01 Jan 1970 00:00:00 0000 KubeletReady kubelet is posting ready status这些False状态说明节点资源充足。但如果Conditions里出现MemoryPressure: True那就说明节点内存真的快爆了即使top显示MEMORY%只有 70%。因为MemoryPressure是 kubelet 根据memory.available可用内存触发的而memory.availablememory.capacity-memory.usage-memory.working_set工作集更接近 RSS。top的memory.usage包含了 page cache而memory.available不包含。所以top看似宽松Conditions却已拉响警报——这是两个不同的健康维度。3.3kubectl top pods穿透到容器级识别“安静的杀手”kubectl top pods的输出是NAME CPU(cores) MEMORY(bytes) nginx-7c786df6b8-abcde 12m 123Mi redis-5c7c8c9d4-xyzab 45m 456Mi这看起来很直观。但请记住这个数字是 Pod 内所有容器的资源使用总和。一个 Pod 里如果有nginx和log-forwarder两个容器top显示的12m是它们加起来的 CPU。如果你想单独看nginx容器的用量kubectl top无能为力。你需要kubectl exec进入容器用top或htop命令或者更专业地用crictl如果你用 containerd# 先找到 Pod 对应的 container ID kubectl get pod nginx-7c786df6b8-abcde -o jsonpath{.status.containerStatuses[0].containerID} # 假设输出是 containerd://abc123... # 然后用 crictl stats 查看该容器的实时指标 crictl stats abc123输出会包含cpu_usage纳秒级、memory_usage字节等原生字段比kubectl top精确得多。更常见的需求是为什么这个 Pod 的MEMORY(bytes)一直在缓慢上涨从 100Mi 涨到 500Mi最后 OOMKilledkubectl top只给你一个数字无法告诉你原因。这时你需要结合kubectl describe pod和kubectl logs# 查看 Pod 的事件找 OOMKilled 记录 kubectl describe pod nginx-7c786df6b8-abcde | grep -A 10 Events # 查看容器日志找内存泄漏线索如 Java 的 OutOfMemoryError kubectl logs nginx-7c786df6b8-abcde -c nginx --tail100 # 如果是 Java 应用还可以 dump heap kubectl exec nginx-7c786df6b8-abcde -c nginx -- jmap -dump:formatb,file/tmp/heap.hprof 1kubectl top是发现问题的“望远镜”而describe、logs、exec才是解决问题的“手术刀”。它们必须配合使用。3.4 参数调优让top更准、更快、更贴合你的场景kubectl top命令本身支持几个关键参数它们能极大提升排查效率--namespace指定命名空间避免在default里大海捞针。kubectl top pods -n production--sort-by按字段排序这是最实用的。kubectl top pods --sort-bymemory.usage会按内存用量降序排列一眼就能找到“内存大户”。同样--sort-bycpu.usage找 CPU 大户。--containers这是 1.20 版本的新特性可以显示 Pod 内每个容器的用量。kubectl top pods --containers输出会是POD NAME CPU(cores) MEMORY(bytes) nginx-7c786df6b8-abcde nginx 10m 110Mi nginx-7c786df6b8-abcde logsidecar 2m 13Mi这个功能彻底解决了“一个 Pod 多容器不知道谁在吃资源”的痛点。我强烈建议所有集群升级到 1.20并养成kubectl top pods --containers --sort-bymemory.usage的习惯。--use-protocol-buffers启用 Protocol Buffers 编码减少网络传输体积对大规模集群100 节点有明显加速效果。kubectl top nodes --use-protocol-buffers另外Metrics Server 本身的配置也影响top的表现。在metrics-server-deployment.yaml的args中可以调整--metric-resolution30s将指标采样间隔从默认 60 秒缩短到 30 秒让top数据更“实时”。但代价是 kubelet 的负载增加不建议低于 15 秒。--kubelet-timeout10s设置 Metrics Server 向 kubelet 请求的超时时间。如果网络延迟高可以适当调大避免因超时导致部分节点数据缺失。4. 常见问题与排查技巧实录那些让你抓狂的top异常我都踩过4.1 问题速查表kubectl top报错的 5 种典型场景与解法现象可能原因排查命令解决方案error: the server is currently unable to handle the requestMetrics Server Pod CrashLoopBackOff 或未 Runningkubectl get pods -n kube-system | grep metrics-server检查 Pod 日志kubectl logs -n kube-system metrics-server-xxx常见原因是 TLS 证书错误或 kubelet 地址不可达error: Metrics not available for nodesMetrics Server 已运行但无法从 kubelet 拉取数据kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes检查 Metrics Server 的--kubelet-*参数确认--kubelet-preferred-address-types包含节点实际 IP 类型如 InternalIPerror: Metrics not available for podsMetrics Server 无法获取 Pod 指标但节点指标正常kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/default/pods检查 Pod 是否处于Running状态CrashLoopBackOff的 Pod 不会产生指标检查 Pod 是否设置了hostNetwork: true这可能导致 cAdvisor 无法正确关联容器top显示 CPU 为0m但describe pod显示Ready: TruePod 的主容器已启动但尚未产生 CPU 活动如 Java 应用正在加载类kubectl logs pod-name等待应用初始化完成或检查应用启动日志是否有卡点top显示内存持续上涨但describe node的Conditions无压力memory.usage包含 page cache而Conditions基于memory.availablekubectl exec pod -- cat /sys/fs/cgroup/memory/memory.stat | grep pgpgin如果pgpginpage in很高说明应用在大量读文件cache 占用高属正常现象4.2 “幽灵 Pod”为什么top能看到get pods却找不到这是个经典谜题。你执行kubectl top pods看到一个叫legacy-app-5c7c8c9d4-xyzab的 Pod 占用 2.1Gi 内存但kubectl get pods --all-namespaces \| grep legacy-app却一无所获。这通常意味着这个 Pod 已被删除但其 cgroup 尚未被 kubelet 清理干净。Kubelet 的清理逻辑是当 Pod 被 API Server 删除后kubelet 会收到事件然后停止容器、删除 cgroup。但如果 kubelet 因为某种原因如 OOM、网络中断没有及时处理这个事件cgroup 就会残留。cAdvisor 依然能读取这个“僵尸 cgroup”的数据Metrics Server 就会把它当作一个“活着的 Pod”上报。解决方法很简单登录到对应节点手动清理。# 找到该 Pod 的 UID从 top 输出或 describe 中获取 # 在节点上查找对应的 cgroup ls /sys/fs/cgroup/memory/kubepods.slice/ | grep xyzab # 强制删除 cgroup谨慎操作确保 Pod 确实已不存在 echo 0 /sys/fs/cgroup/memory/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-podxyzab.slice/cgroup.procs rmdir /sys/fs/cgroup/memory/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-podxyzab.slice更稳妥的做法是重启 kubeletsystemctl restart kubelet。它会自动清理所有孤儿 cgroup。但这会造成节点短暂不可用生产环境慎用。4.3 “虚假高负载”top显示 95% CPU但业务完全不卡我遇到过最离谱的一次一个数据库节点kubectl top nodes显示 CPU 98%kubectl describe node的Conditions一切正常但应用响应时间毫秒级毫无压力。最后发现是top命令本身在“捣鬼”。kubectl top的实现是 Metrics Server 向 kubelet 发起/metrics/cadvisor请求。而 kubelet 的 cAdvisor 接口在高负载时响应会变慢。Metrics Server 为了不阻塞会设置一个超时默认 30 秒。如果超时它会返回一个“上次成功拉取”的缓存值。而这个缓存值可能来自 2 分钟前——那时节点确实 CPU 100%但现在早已恢复。所以你看到的98%是过期数据。验证方法直接 curl kubelet 的 cAdvisor 接口。# 获取节点 IP kubectl get node node-01 -o jsonpath{.status.addresses[?(.typeInternalIP)].address} # curl cAdvisor curl -k https://node-ip:10250/metrics/cadvisor | grep container_cpu_usage_seconds_total如果响应很快1s说明 cAdvisor 正常top的数据是实时的如果超时或响应巨慢那top的数据大概率是缓存的。解决方案在 Metrics Server 的args中增加--kubelet-timeout5s并确保 kubelet 的--streaming-connection-idle-timeout参数足够长默认 4h通常不用改。同时优化 kubelet 的性能比如减少--sync-frequency默认 1m可调为 5m。4.4 实操心得我的“三步诊断法”与避坑清单经过上百次线上故障复盘我总结出一套针对资源问题的“三步诊断法”它比盲目kubectl top高效得多第一步看Conditions定生死kubectl describe node node-name | grep -A 5 Conditions如果MemoryPressure或DiskPressure是True立刻停止所有排查先解决这个。这是 K8s 的“生命体征”比任何top数字都权威。第二步看AllocatablevsUsage算余量kubectl top nodes kubectl describe node node-name | grep -A 5 Allocatable计算Allocatable - top_usage。如果余量 100m CPU 或 100Mi 内存说明调度已到极限新 Pod 必然 Pending。这时top的百分比已经失去意义。第三步看Events和Logs找根因kubectl describe pod pod-name kubectl logs pod-name --previous # 查看上一次崩溃的日志90% 的资源问题根因不在资源本身而在应用行为。比如一个 Python 应用top显示内存 90%但logs里有OSError: [Errno 24] Too many open files这其实是文件描述符耗尽不是内存不够。我的避坑清单血泪教训绝不相信kubectl top的单一数字它只是一个快照必须结合describe、logs、events交叉验证。--containers参数是神器1.20 版本必用它能瞬间定位多容器 Pod 中的“害群之马”。Metrics Server 的--metric-resolution不要设得太小30 秒是平衡点15 秒以下会让 kubelet 压力陡增得不偿失。kubectl top不是告警工具它没有阈值、没有历史、没有通知。告警必须用 Prometheus Alertmanager。top的内存单位是字节不是 MiB1234567890是 1.23Gi不是 1234Mi。用numfmt --toiec-i --suffixB 1234567890可以友好格式化。5. 超越top当基础命令不够用时你应该掌握的进阶手段5.1kubectl describe node比top更丰富的资源视图kubectl top nodes只给你两个数字而kubectl describe node是一个宝藏。除了前面说的Allocatable和Conditions它还包含Non-terminated Pods表格列出该节点上所有非终止状态的 Pod以及它们各自申请的requests和limits。这是理解“为什么资源不够”的关键。你会发现很多 Pending Pod 的requests.cpu是100m而节点Allocatable.cpu是3900m看似够用。但describe会告诉你已经有 38 个 Pod 各占100m加起来3800m只剩100m所以第 39 个 Pod 就 Pending 了。top永远不会告诉你这个“排队”逻辑。System Info部分Machine-ID、System UUID、Boot ID这些在排查硬件级问题如 CPU 频率降频时很有用。OS Image和Kernel Version则是排查内核 bug 的依据。Addresses节点的 IP 地址列表。当top显示某个节点异常你可以立刻ssh过去用top、iostat、vmstat做底层诊断。5.2kubectl get --raw直连 Metrics API获取原始数据kubectl top是一个友好的封装但有时你需要原始 JSON。kubectl get --raw就是你的后门。# 获取所有节点的原始指标 kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes | jq . # 获取特定命名空间下所有 Pod 的指标 kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/default/pods | jq . # 获取单个 Pod 的指标需要精确名称 kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/default/pods/nginx-7c786df6b8-abcde | jq .这些原始数据可以被导入到 Grafana 中做成自定义面板也可以用脚本解析生成日报。比如一个简单的 Bash 脚本每天凌晨统计集群最高内存 Pod#!/bin/bash # 获取所有 Pod 内存用量按降序排列取 Top 10 kubectl get --raw /apis/metrics.k8s.io/v1beta1/pods | \ jq -r .items[] | select(.containers[0].usage.memory ! null) | \(.metadata.namespace)/\(.metadata.name) \(.containers[0].usage.memory) | \ sort -k2 -hr | head -105.3crictl和ctr绕过 K8s直击容器运行时当kubectl top和describe都无法解释问题时你需要下沉到容器运行时层。crictlcontainerd 的 CLI和ctrcontainerd 的底层 CLI是终极武器。# 列出所有容器包括 Pause 容器 sudo crictl ps -a # 查看某个容器的详细状态和指标 sudo crictl stats container-id # 查看容器的 cgroup 路径 sudo crictl inspect container-id | grep cgroupPath # 直接读取 cgroup 文件以 memory 为例 cat /sys/fs/cgroup/memory/cgroup-path/memory.usage_in_bytes cat /sys/fs/cgroup/memory/cgroup-path/memory.statmemory.stat里的pgpgin、pgpgout、pgmajfault等字段能