Kubernetes容器环境故障排查指南

📅 发布时间:2026/7/7 21:08:15 👁️ 浏览次数:
Kubernetes容器环境故障排查指南
目录标题Kubernetes容器环境故障排查指南目录背景环境限制当前测试环境调试方案方案一利用宿主机调试工具推荐✅ 已验证方案二直接读取 /proc 文件系统 ✅ 已验证方案三使用 perf 工具 ✅ 已验证方案四生成 Core Dump ✅ 已验证方案五Kubernetes原生调试 ✅ 已验证多线程 vs 多进程关键区别多进程调试示例多线程调试示例TID vs PID 的区别实战案例案例1: 数据库进程响应缓慢案例2: 内存泄漏诊断案例3: 死锁检测快速参考常用 /proc 路径进程状态码快速诊断脚本实测验证结果验证环境验证1: 容器内调试工具检查验证2: /proc 文件系统有效性验证3: 多线程场景 (MySQL - 245个线程)验证4: 多进程场景 (Redis实例)验证5: 内存分析验证6: 文件描述符分析关键发现总结快速诊断脚本 (实测版)注意事项完整验证结果汇总 (2026-01-29)宿主机调试工具验证容器运行时工具验证Kubernetes 工具验证/proc 文件系统验证Core Dump 配置验证实测进程信息crictl 使用注意事项perf 工具验证详情Kubernetes容器环境故障排查指南目录背景环境限制调试方案多线程 vs 多进程实战案例快速参考背景在Kubernetes数据库容器环境中由于安全或镜像精简的原因往往缺少传统的调试工具如pstack- 打印进程堆栈gdb- GNU调试器strace- 系统调用跟踪lsof- 列出打开的文件tcpdump- 网络抓包这给生产环境的问题分析带来挑战需要采用替代方案。环境限制当前测试环境目标主机: 148平台: Kubernetes ()限制: 容器内无标准调试工具约束: 只读环境不允许修改资源配置调试方案方案一利用宿主机调试工具推荐✅ 已验证原理: 容器与宿主机共享Linux内核容器进程在宿主机上有对应的PID。验证状态: ✅ 2026-01-29 在 148 验证通过crictl v1.26.0 可用需指定--runtime-endpointunix:///run/containerd/containerd.sockpstack、gdb、strace、lsof、gcore、tcpdump 均可用MySQL容器进程 (PID 4047749, 59线程) 测试通过# 1. 获取容器在宿主机上的PID# 方法A: 通过 crictl (containerd 运行时 - 推荐)# 注意需指定 runtime-endpointcrictl --runtime-endpointunix:///run/containerd/containerd.sockps|grep容器名或Pod名crictl --runtime-endpointunix:///run/containerd/containerd.sock inspectcontainer-id|greppid:# 方法B: 通过 ctr (containerd 原生工具)ctr -n k8s.io tasksls|grep容器名ctr -n k8s.io task infocontainer-id|grepPid# 方法C: 通过 docker (旧版本运行时)dockerps|grep容器名dockerinspectcontainer-id--format{{.State.Pid}}# 方法D: 通过 kubectl 获取 containerID 后用 crictlkubectl get podpod-name-ojsonpath{.status.containerStatuses[0].containerID}# 输出格式: containerd://container-id提取完整IDcrictl inspectcontainer-id--format{{.info.pid}}# 2. 在宿主机上使用调试工具sudogdb -phost-pidsudopstackhost-pidsudostrace-phost-pid-f -etracefile,network方案二直接读取 /proc 文件系统 ✅ 已验证原理: Linux内核通过 /proc 提供进程和系统信息无需额外工具。验证状态: ✅ 2026-01-29 验证通过/proc/pid/stack 正常工作/proc/pid/status 正常工作/proc/pid/task/ 多线程查看正常内核版本: 5.10.0-136.12.0.86.oe2203sp1.x86_64# 查看进程堆栈如果内核支持 CONFIG_STACKTRACEcat/proc/pid/stack# 查看进程状态内存、CPU、线程数等cat/proc/pid/status# 关键字段:# - Threads: 线程总数# - VmRSS: 实际物理内存使用# - voluntary_context_switches: 主动切换次数# - nonvoluntary_context_switches: 被动切换次数# 查看所有线程ls/proc/pid/task/cat/proc/pid/task/tid/stack# 查看特定线程堆栈# 查看内存映射cat/proc/pid/maps# 查看打开的文件描述符ls-la /proc/pid/fd/lsof-ppid2/dev/null||ls-la /proc/pid/fd/# 查看网络连接cat/proc/pid/net/tcpcat/proc/pid/net/tcp6 ss -tunlp|greppid方案三使用 perf 工具 ✅ 已验证原理: perf 是Linux内核性能分析工具通常在基础镜像中可用。验证状态: ✅ 2026-01-29 验证通过已安装 perf-5.10.0-136.108.0.188.oe2203sp1安装命令:yum install -y perf版本: perf version 5.10.0-136.108.0.188.oe2203sp1.x86_64MySQL进程 (PID 4047749) 测试通过# 检查perf是否可用whichperf# /usr/bin/perfperf version# 5.10.0-136.108.0.188.oe2203sp1.x86_64# 采样分析CPU使用perftop-ppid# 统计性能计数器perfstat-ppid--sleep1# 示例输出 (MySQL进程):# Performance counter stats for process id 4047749:# 79,801,017 cycles# 32,686,447 instructions # 0.41 insn per cycle# 1.002716058 seconds time elapsed# 记录性能数据perf record -g -ppid--sleep30perf report# 跟踪系统调用perf trace -ppid--duration2# 示例输出 (MySQL线程):# mysqld/4048895 futex(uaddr: 0x7fc4b3a44a44, op: WAIT|PRIVATE_FLAG, ...) -1 ETIMEDOUT# mysqld/4048783 io_getevents(ctx_id: 140483204546560, min_nr: 1, nr: 256, ...) 0# mysqld/3902096 ppoll(ufds: 0x7fc4b164b0e8, nfds: 1, ...) 1# 查看可用事件perf list# 采样分析CPU使用perftop-ppid# 记录性能数据perf record -g -ppid--sleep30perf report# 查看当前调度情况perf sched方案四生成 Core Dump ✅ 已验证原理: 进程崩溃或手动触发时生成内存快照。验证状态: ✅ 2026-01-29 验证通过gcore 可用成功生成 2.9GB core 文件core_pattern:core(输出到当前目录)core_uses_pid:1(文件名包含PID)ulimit -c:2097152(2MB限制但实际可生成更大的core)# 方法1: 使用gcore已验证可用gcore -o /tmp/core_outputpid# 方法2: 发送ABRT信号kill-ABRTpid# 检查 /proc/sys/kernel/core_pattern 确认core文件位置# 方法3: 通过/proc触发echo1/proc/sys/kernel/core_uses_pidulimit-c unlimitedkill-SEGVpid# Core文件需要复制到有gdb的环境分析gdbexecutablecore-file方案五Kubernetes原生调试 ✅ 已验证验证状态: ✅ 2026-01-29 验证通过kubectl debug 命令可用Kubernetes v1.24.10 支持 ephemeral containers (1.23)集群地址: 10.10.180.15 ()# 1. 使用 kubectl debug 创建调试容器kubectl debug -itpod-name\--imagenicolaka/netshoot\--targetcontainer-name\--sh# 2. 使用 ephemeral container (K8s 1.23)kubectl debug -itpod-name--profilesysadmin --sh# 3. 共享进程命名空间kubectl debug -itpod-name--share-processes --imageubuntu --sh# 然后在调试容器中 ps aux 查看目标进程# 4. 拷贝文件到宿主机kubectlcpnamespace/pod-name:/var/log/error.log ./多线程 vs 多进程关键区别特性多进程多线程/proc 结构每个进程有独立 /proc/主进程下有 /proc//task/堆栈查看cat /proc//stackcat /proc//task//stack线程数Threads1ThreadsN调试范围单个进程需要查看所有线程多进程调试示例# 查看某个数据库的所有子进程psaux|grepmysql pgrep -a mysql# 对每个进程单独分析forpidin$(pgrep mysql);doecho Process$pidcat/proc/$pid/status|grep-E(Name|Threads|State)cat/proc/$pid/stack2/dev/null|head-20done多线程调试示例# 查看主进程的所有线程pid$(pgrep java|head-1)echoTotal threads:$(ls/proc/$pid/task|wc-l)# 查看每个线程的堆栈fortidin/proc/$pid/task/*;dotid_num$(basename$tid)echo Thread$tid_numcat/proc/$pid/task/$tid_num/stack2/dev/null|head-10echodone|less# 查找特定状态的线程# 比如 BLOCKED (睡眠状态)fortidin/proc/$pid/task/*;dostate$(cat$tid/status|grepState|awk{print $2})if[$stateS];thenechoThread$(basename$tid)is sleepingcat$tid/stackfidoneTID vs PID 的区别多进程场景: ├── /proc/1234/ # 进程1 │ ├── stack # 进程1的堆栈 │ └── status # 进程1的状态 ├── /proc/1235/ # 进程2 │ ├── stack # 进程2的堆栈 │ └── status # 进程2的状态 多线程场景 (主进程 PID1234): ├── /proc/1234/ # 主进程 │ ├── stack # 主线程堆栈 │ ├── status # 显示 ThreadsN │ └── task/ # 线程目录 │ ├── 1234/ # 主线程 │ │ └── stack │ ├── 1235/ # 工作线程1 │ │ └── stack │ └── 1236/ # 工作线程2 │ └── stack实战案例案例1: 数据库进程响应缓慢# 1. 检查进程状态pid$(pgrep mysql|head-1)cat/proc/$pid/status|grep-E(State|Threads|voluntary)# 2. 查看主堆栈cat/proc/$pid/stack# 3. 如果是多线程检查所有线程fortidin/proc/$pid/task/*;doechoThread$(basename$tid):cat$tid/stack2/dev/null|head-5done# 4. 检查CPU使用top-H -p$pid-n1# 5. 检查IO等待cat/proc/$pid/io# read_bytes/write_bytes 显示IO量案例2: 内存泄漏诊断# 1. 查看进程内存cat/proc/pid/status|grep-E(VmSize|VmRSS)# 2. 查看内存映射详情cat/proc/pid/maps|awk{print $1, $6}|sort-u# 3. 查看匿名内存可能是堆cat/proc/pid/maps|grep-E(heap|stack)|# 4. smaps 统计更详细cat/proc/pid/smaps|grep-A1Size:案例3: 死锁检测# 1. 查看所有线程状态fortidin/proc/pid/task/*;dostate$(cat$tid/status|grepState|awk{print $2})case$stateinD)echoThread$(basename$tid): Uninterruptible sleep (IO);;S)echoThread$(basename$tid): Sleeping;;R)echoThread$(basename$tid): Running;;*)echoThread$(basename$tid): State$state;;esacdone# 2. 查看D状态线程的堆栈通常在等待IOfortidin/proc/pid/task/*;dostate$(cat$tid/status|grepState|awk{print $2})if[$stateD];thenecho Thread$(basename$tid)in D state cat$tid/stackfidone快速参考常用 /proc 路径/proc/pid/status# 进程状态摘要/proc/pid/stack# 内核堆栈跟踪/proc/pid/maps# 内存映射/proc/pid/smaps# 详细内存统计/proc/pid/fd/# 打开的文件描述符/proc/pid/net/tcp# TCP连接/proc/pid/task/# 线程目录多线程/proc/pid/task/tid/stack# 特定线程堆栈进程状态码码状态说明RRunning正在运行或可运行SSleeping可中断睡眠DDisk不可中断睡眠等待IOZZombie僵尸进程TStopped已停止tTracing被跟踪调试快速诊断脚本#!/bin/bash# quick-diagnose.sh - 快速诊断脚本PID${1:-$(pgrep -o java)}# 默认取第一个Java进程echo Process Info:$PIDcat/proc/$PID/status2/dev/null|grep-E(Name|State|Threads|Pid|PPid)echo-e\n Stack Trace cat/proc/$PID/stack2/dev/null||echoNeed CAP_SYS_ADMIN or kernel supportecho-e\n Thread Info if[-d /proc/$PID/task];thenechoTotal threads:$(ls/proc/$PID/task|wc-l)echo-e\nTop 5 threads by stack:ls/proc/$PID/task|head-5|whilereadtid;doecho-e\n--- Thread$tid---cat/proc/$PID/task/$tid/stack2/dev/null|head-5donefiecho-e\n Memory Info cat/proc/$PID/status2/dev/null|grep-E(VmSize|VmRSS|VmPeak)echo-e\n File Descriptors echoOpen FDs:$(ls/proc/$PID/fd2/dev/null|wc-l)echo-e\n Connections ss -tunp2/dev/null|grep$PID||netstat-tunp2/dev/null|grep$PID使用方法./quick-diagnose.shpid实测验证结果验证环境主机: 148 (2)内核: 5.10.0-136.12.0.86.oe2203sp1.x86_64容运行时: containerd://1.7.3Kubernetes版本: v1.24.10验证时间: 2026-01-28验证1: 容器内调试工具检查# 在MySQL容器中检查调试工具kubectlexec-n -admin mysql-65cbddad00-0 -c mysql --bash-ccommand -v pstack gdb strace lsof# 结果: 未找到标准调试工具# 仅找到: gdbm_dump, gdbm_load, gdbmtool, gdbus (非调试工具)结论: 容器内确实缺少 pstack、gdb、strace、lsof 等标准调试工具。验证2: /proc 文件系统有效性测试进程: MySQL (PID: 2368198)# 进程基本信息cat/proc/2368198/status|grep-E(Name|State|Threads|Pid|PPid)# 输出:# Name: mysqld# State: S (sleeping)# Threads: 245# Pid: 2368198堆栈跟踪验证:cat/proc/2368198/stack# 输出:# [0] do_poll.constprop.00x273/0x3a0# [0] do_sys_poll0x1ae/0x260# [0] __se_sys_poll0x2c/0x140# [0] do_syscall_640x40/0x80# [0] entry_SYSCALL_64_after_hwframe0x61/0xc6结论: /proc/stack 在当前内核环境下工作正常可以获取有效的堆栈信息。验证3: 多线程场景 (MySQL - 245个线程)不同线程的堆栈对比:线程ID状态堆栈特征2368198 (主线程)Sdo_poll → 等待网络I/O2368207 (工作线程)Sfutex_wait → 等待互斥锁2368228 (工作线程)Sfutex_wait → 等待互斥锁2368236 (工作线程)Sfutex_wait → 等待互斥锁分析:主线程在处理网络轮询 (poll)工作线程在等待 futex (快速用户空间互斥锁)不同线程有不同的堆栈说明 /proc/task//stack 可以正确区分线程验证4: 多进程场景 (Redis实例)独立Redis进程对比:进程PID线程数内存使用父进程174917578256 KB174883817494865~8200 KB1748898分析:每个Redis实例是独立的进程每个进程有自己的 /proc/ 目录通过 /proc//stack 查看单个进程的堆栈验证5: 内存分析MySQL (多线程共享内存):VmSize: 6944320 kB (~6.6 GB) VmRSS: 2153536 kB (~2 GB) VmData: 6849564 kBRedis (多进程独立内存):VmSize: 124464 kB (~121 MB) VmRSS: 8256 KB (~8 MB) VmData: 116320 kB结论: 多线程应用共享内存空间多进程应用各自独立内存。验证6: 文件描述符分析ls/proc/2368198/fd|wc-l# 结果: 283个打开的文件描述符# 部分FD类型:# FD 0: /dev/null# FD 1: /data/mysql/log/alert.log# FD 10: /data/mysql/data/ibdata2# FD 100-106: socket:[...] (网络连接)关键发现总结/proc/stack 可用: 当前内核支持堆栈跟踪无需额外工具多线程查看路径:/proc/pid/task/tid/stack每个线程有独立堆栈多进程查看路径:/proc/pid/stack每个进程独立查看线程状态可区分: 不同线程有不同的堆栈和状态文件描述符可访问: 通过 /proc//fd/ 查看打开的文件快速诊断脚本 (实测版)#!/bin/bash# diagnose.sh - 实测验证的诊断脚本if[-z$1];thenechoUsage:$0pidechoExample:$02368198exit1fiPID$1echo 进程基本信息 cat/proc/$PID/status2/dev/null|grep-E(Name|State|Threads|Pid|PPid|Tgid)||echo无法读取进程信息echo-e\n 线程信息 if[-d /proc/$PID/task];thenTOTAL_THREADS$(ls/proc/$PID/task2/dev/null|wc-l)echo总线程数:$TOTAL_THREADSif[$TOTAL_THREADS-gt1];thenecho-e\n 多线程堆栈采样 (前5个线程) ls/proc/$PID/task2/dev/null|head-5|whilereadtid;doSTATE$(cat/proc/$PID/task/$tid/status2/dev/null|grepState|awk{print $2})echo-e\n--- 线程$tid(状态:$STATE) ---cat/proc/$PID/task/$tid/stack2/dev/null|head-3donefielseecho无法访问线程信息fiecho-e\n 内存使用 cat/proc/$PID/status2/dev/null|grep-E(VmSize|VmRSS|VmData)echo-e\n 文件描述符 echo打开的FD数量:$(ls/proc/$PID/fd2/dev/null|wc-l)echo部分FD类型:ls/proc/$PID/fd2/dev/null|head-5|whilereadfd;doLINK$(ls-l /proc/$PID/fd/$fd2/dev/null|awk{print $11})echo FD$fd:$LINKdoneecho-e\n 进程状态说明 echoR Running (运行中)echoS Sleeping (可中断睡眠)echoD Disk wait (不可中断睡眠/IO等待)echoZ Zombie (僵尸进程)注意事项权限要求: 读取 /proc//stack 需要 CAP_SYS_ADMIN 权限或 root内核支持: 堆栈跟踪需要内核开启 CONFIG_STACKTRACE已验证当前内核支持安全性: 生产环境慎用 gdb/strace可能影响性能只读原则: 在本环境中只进行观察不修改任何配置containerd 环境: 推荐使用crictl(Kubernetes标准工具) 或ctr -n k8s.io查找容器PID而非 docker inspect文档版本: 1.3 (完整验证版 - perf已安装)验证环境: 148 (2)验证日期: 2026-01-28 初始验证2026-01-29 完整验证2026-01-29 perf安装验证完整验证结果汇总 (2026-01-29)宿主机调试工具验证工具状态版本/说明验证命令pstack✅ 可用/usr/bin/pstackpstack 4047749成功显示59个线程gdb✅ 可用/usr/bin/gdbGNU调试器strace✅ 可用/usr/bin/stracestrace -p 4047749 -f成功附加59个线程lsof✅ 可用/usr/bin/lsoflsof -p 4047749成功显示文件列表gcore✅ 可用/usr/bin/gcore成功生成2.9GB core文件tcpdump✅ 可用v4.99.1网络抓包工具perf✅ 可用v5.10.0-136.108.0.188.oe2203sp1yum install -y perf安装已验证stat/trace/top/list容器运行时工具验证工具状态版本/说明crictl✅ 可用v1.26.0 (需指定--runtime-endpointunix:///run/containerd/containerd.sock)ctr✅ 可用containerd 原生工具docker✅ 可用兼容工具Kubernetes 工具验证工具状态版本/说明kubectl debug✅ 可用K8s v1.24.10 支持 ephemeral containers/proc 文件系统验证路径状态说明/proc/pid/stack✅ 可用内核堆栈跟踪正常/proc/pid/status✅ 可用进程状态正常/proc/pid/task/✅ 可用多线程查看正常/proc/pid/fd/✅ 可用文件描述符查看正常Core Dump 配置验证配置项值说明core_patterncore输出到当前目录core_uses_pid1文件名包含PIDulimit -c20971522MB限制实际可生成更大core实测进程信息进程PID线程数状态mysqld404774959S (sleeping)crictl 使用注意事项重要: 当前环境需要显式指定 runtime-endpoint# 正确用法crictl --runtime-endpointunix:///run/containerd/containerd.sockpscrictl --runtime-endpointunix:///run/containerd/containerd.sock inspectcontainer-id# 提取PID的方法crictl --runtime-endpointunix:///run/containerd/containerd.sock inspectid|greppid:|head-1perf 工具验证详情安装命令:yuminstall-y perf已验证的 perf 子命令:命令状态说明perf version✅显示版本 5.10.0-136.108.0.188.oe2203sp1perf list✅列出可用事件 (cycles, instructions, cache-misses 等)perf stat✅统计性能计数器 (cycles: 79M, instructions: 32M)perf top✅实时采样显示 (4000Hz cycles)perf trace✅跟踪系统调用 (futex, io_getevents, ppoll)perf record✅记录性能数据MySQL 进程 perf 输出示例:# perf stat 输出Performance counter statsforprocessid4047749:79,801,017 cycles32,686,447 instructions# 0.41 insn per cycle1.002716058secondstimeelapsed# perf trace 输出mysqld/4048895 futex(uaddr: 0x7fc4b3a44a44, op: WAIT|PRIVATE_FLAG,...)-1 ETIMEDOUT mysqld/4048783 io_getevents(ctx_id:140483204546560, min_nr:1, nr:256,...)0mysqld/3902096 ppoll(ufds: 0x7fc4b164b0e8, nfds:1,...)1