简介:这份文档面向 Kubernetes 运维工程师、云计算从业者及正在准备相关认证的技术人员,系统梳理了 k8s 集群在实际生产环境中常见的故障类型与排查思路。内容围绕连接异常、通信异常、节点内部异常和应用故障四大场景展开,涵盖 pod 处于 ContainerCreating、Pending、ImagePullBackOff 等典型状态的成因分析与诊断流程,并给出 node 节点重置重新入群、存储卷未挂载 pv、网络插件部署异常等具体处理方案,配合 kubectl 常用命令与 kubelet 日志查看方法,帮助读者建立从现象到根因的排错路径。资源包为 1 个 docx 文档,约 11.58MB,结构按故障章节组织,便于按需查阅。目前已有 2878 人学习下载,适合希望提升 k8s 故障定位效率、积累实战排错经验的运维人员参考。
1. k8s 故障处理笔记:从 Pod 起不来到底层网络排查的完整路径
凌晨两点收到告警,某个核心服务的 Pod 大面积重启,kubectl get pods一看全是CrashLoopBackOff,但业务代码昨天刚上线时还是好的。这种场景做 k8s 运维的人多少都遇到过。k8s 故障处理的核心难点不在于命令多复杂,而在于故障现象往往指向多个可能原因,排查路径如果不对,很容易在错误的方向上浪费大量时间。这份笔记整理的是我在实际工作中反复用到的排查思路和操作步骤,覆盖 Pod 异常、网络插件问题、控制节点初始化失败、存储挂载失败等高频场景。适合已经能跑起 k8s 集群、但在出问题时不知道从哪下手的人。每一条都尽量给出可复现的命令和判断依据,而不是泛泛而谈“检查日志”。
2. Pod 异常状态排查:从 Pending 到 CrashLoopBackOff 的逐层定位
2.1 先看状态再动手:Pod 生命周期中的关键信号
拿到一个异常 Pod,第一步永远是kubectl describe pod,而不是直接看应用日志。describe 的输出里包含了调度结果、容器启动过程、挂载信息和最近事件,这些信息能快速把问题范围缩小到调度层、镜像层、存储层还是应用层。
# 查看 Pod 详细状态,重点关注 Events 部分 kubectl describe pod <pod-name> -n <namespace> # 只看事件,按时间排序 kubectl get events -n <namespace> --sort-by='.lastTimestamp'describe 输出中,Status字段告诉你 Pod 当前处于哪个阶段,Events则记录了从创建到现在的关键动作。比如FailedScheduling说明调度器找不到合适的节点,FailedMount说明存储卷挂载有问题,BackOff说明容器启动后退出被反复重启。先根据这些事件把问题归类,再进入对应的排查分支。
参数说明:-n指定命名空间,不指定则默认 default;--sort-by按事件时间排序,排查偶发问题时特别有用。
2.2 Pending 状态:调度器为什么不选这个节点
Pending 意味着 Pod 已经被 API Server 接受,但还没有被调度到任何节点上。常见原因有三类:资源不足、节点选择器不匹配、污点和容忍度冲突。
# 查看节点资源分配情况 kubectl describe node <node-name> | grep -A 5 "Allocated resources" # 查看节点标签,确认 nodeSelector 是否能匹配 kubectl get nodes --show-labels # 查看节点污点 kubectl describe node <node-name> | grep Taints如果Allocated resources显示 CPU 或内存的 requests 已经接近容量,调度器就不会再把新 Pod 放上去。这时候要么清理无用 Pod,要么调整工作负载的 resource requests。如果是 nodeSelector 或 affinity 配置问题,检查 Pod spec 里的nodeSelector字段和节点标签是否一致。污点问题则看 Pod 的tolerations是否覆盖了节点上的 taint。
我一般会先用kubectl get pods -o wide确认 Pod 是否真的没有被分配节点,再用kubectl describe pod看具体的调度失败原因。这两个命令组合能解决八成以上的 Pending 问题。
2.3 CrashLoopBackOff:容器反复重启的四个常见根因
CrashLoopBackOff 是容器启动后退出,kubelet 按指数退避策略反复重启。排查顺序建议是:先看容器退出码,再看应用日志,最后检查探针配置。
# 查看容器上一次退出的退出码和原因 kubectl get pod <pod-name> -o jsonpath='{.status.containerStatuses[0].lastState.terminated}' # 查看当前容器日志 kubectl logs <pod-name> -n <namespace> # 查看上一次崩溃的日志 kubectl logs <pod-name> -n <namespace> --previous退出码 0 通常意味着容器主进程正常结束,但 k8s 期望它持续运行,这种情况常见于启动命令写成了执行完就退出的脚本。退出码 1 一般是应用报错,需要看日志定位。退出码 137 表示被 SIGKILL 杀死,多半是 OOMKilled,检查 Pod 的 memory limit 是否太小。退出码 143 是 SIGTERM,通常是收到了终止信号。
探针配置错误也容易导致 CrashLoopBackOff。livenessProbe 如果 initialDelaySeconds 设得太短,应用还没启动完就被判定为不健康,kubelet 会杀掉容器重启。readinessProbe 配置不当则会导致 Pod 一直不 Ready,但不会重启。这两种情况在 describe 的 Events 里能看到Liveness probe failed或Readiness probe failed的记录。
2.4 镜像拉取失败:ImagePullBackOff 的排查清单
ImagePullBackOff 说明 kubelet 无法拉取镜像。排查步骤很固定:确认镜像地址是否正确、确认镜像仓库是否可达、确认拉取凭证是否配置。
# 查看 Pod 事件中的具体拉取错误 kubectl describe pod <pod-name> | grep -A 10 "Events" # 查看已创建的 secret kubectl get secrets -n <namespace> # 检查 Pod 是否引用了 imagePullSecrets kubectl get pod <pod-name> -o jsonpath='{.spec.imagePullSecrets}'常见错误信息包括manifest unknown(镜像 tag 不存在)、unauthorized(凭证无效或未配置)、dial tcp timeout(网络不通)。如果是私有仓库,确认 Secret 的 type 是kubernetes.io/dockerconfigjson,并且 Pod spec 里通过imagePullSecrets引用了它。注意 Secret 必须和 Pod 在同一个 namespace。
还有一个容易忽略的点:如果节点上已经有该镜像的缓存,但 tag 是latest,kubelet 默认的 imagePullPolicy 是Always,每次都会去仓库拉取。仓库不可达时就会失败。可以临时把 imagePullPolicy 改成IfNotPresent来验证是否是仓库问题,但生产环境不建议长期这样配置。
3. 网络插件故障:Pod 跨节点不通与 DNS 解析失败的排查方法
3.1 先确认 CNI 插件是否正常工作
k8s 的网络模型要求每个 Pod 有独立 IP,且跨节点 Pod 能直接通信。这个能力由 CNI 插件提供,常见的有 Calico、Flannel、Cilium。网络问题的第一步是确认 CNI 插件的 Pod 是否全部 Running。
# 查看 CNI 插件 Pod 状态,以 Calico 为例 kubectl get pods -n kube-system | grep calico # 查看 CNI 配置文件是否存在 ls /etc/cni/net.d/ # 查看节点上的路由信息 ip route show如果 CNI Pod 本身就不健康,先解决它。CNI Pod 起不来的常见原因是镜像拉取失败、RBAC 权限不足、或者节点上的 CNI 配置文件残留导致冲突。/etc/cni/net.d/目录下如果有多个 CNI 配置文件,kubelet 会按字母顺序选择第一个,可能选到错误的配置。
路由信息能反映跨节点通信是否正常。Calico 使用 BGP 或 IPIP 模式,Flannel 使用 VXLAN 或 host-gw 模式。如果路由表里缺少到其他节点 Pod 网段的路由,跨节点通信就会失败。这时候需要检查 CNI 插件的配置和节点间的网络连通性。
3.2 Pod 跨节点不通的抓包定位法
当确认 CNI Pod 正常但跨节点仍然不通时,抓包是最直接的定位手段。在源节点和目标节点上分别抓取 Pod 网卡和隧道网卡的流量,对比数据包在哪个环节丢失。
# 在源节点上,抓取 Pod 网卡的流量 tcpdump -i <pod-veth> -nn icmp # 在源节点上,抓取隧道网卡的流量 tcpdump -i tunl0 -nn icmp # 在目标节点上,抓取对应 Pod 网卡的流量 tcpdump -i <target-pod-veth> -nn icmp如果源 Pod 网卡有包发出,但隧道网卡没有,说明 CNI 插件的路由规则没有生效。如果隧道网卡有包但目标节点没有收到,说明节点间的底层网络有问题,可能是防火墙拦截了 VXLAN 或 IPIP 协议。如果目标节点收到了但目标 Pod 网卡没有,说明目标节点的路由或 iptables 规则有问题。
这个方法的逻辑是逐跳验证,把“不通”这个模糊现象拆解成具体的丢包位置。我一般会先用kubectl exec进入源 Pod ping 目标 Pod IP,同时在两端抓包,这样能快速定位。
3.3 DNS 解析失败:CoreDNS 排查的五个检查点
DNS 问题表现为 Pod 内无法解析 Service 名称,但直接 ping IP 是通的。排查 CoreDNS 需要按顺序检查以下五点。
# 1. 检查 CoreDNS Pod 状态 kubectl get pods -n kube-system -l k8s-app=kube-dns # 2. 检查 CoreDNS Service 是否存在 kubectl get svc -n kube-system kube-dns # 3. 检查 Pod 的 DNS 配置 kubectl exec <pod-name> -- cat /etc/resolv.conf # 4. 在 Pod 内测试 DNS 解析 kubectl exec <pod-name> -- nslookup kubernetes.default # 5. 查看 CoreDNS 日志 kubectl logs -n kube-system -l k8s-app=kube-dns第一,CoreDNS Pod 必须是 Running 且 Ready。第二,kube-dns Service 的 ClusterIP 必须存在,且 Endpoints 指向 CoreDNS Pod。第三,Pod 的/etc/resolv.conf里 nameserver 应该是 kube-dns 的 ClusterIP,search 域应该包含 Pod 所在 namespace 的域名后缀。第四,如果 nslookup 超时,说明 Pod 到 CoreDNS 的网络不通,检查网络策略或 iptables 规则。第五,CoreDNS 日志里如果有大量 SERVFAIL,可能是上游 DNS 不可达或 CoreDNS 配置了错误的 forward 地址。
一个常见坑是 NetworkPolicy 默认拒绝所有入站流量,如果给 CoreDNS 所在 namespace 加了策略但没有放行 DNS 端口,所有 Pod 的 DNS 都会挂。这种情况在启用网络策略的集群里特别容易翻车。
4. 控制节点初始化失败:kubeadm init 报错的排查与恢复
4.1 the api server is not healthy 的常见原因
kubeadm init过程中如果看到the api server is not healthy after 4m0.00747357s,说明 kubelet 启动了 API Server 静态 Pod,但健康检查一直没通过。这个报错本身信息量很少,需要去看 kubelet 日志和容器运行时日志。
# 查看 kubelet 日志 journalctl -xeu kubelet --no-pager | tail -100 # 查看容器运行时状态,以 containerd 为例 systemctl status containerd # 查看 API Server 容器是否创建 crictl ps -a | grep kube-apiserver # 查看 API Server 容器日志 crictl logs <container-id>常见原因有四个。第一,容器运行时没配好,kubelet 无法创建容器。检查 containerd 的配置文件/etc/containerd/config.toml里SystemdCgroup是否设为 true,这个参数在 k8s 1.24 之后必须和 kubelet 的 cgroup driver 一致。第二,镜像拉取失败,kubelet 拉不到kube-apiserver镜像。可以用kubeadm config images pull提前拉取,观察具体报错。第三,端口冲突,6443 端口被占用。用ss -tlnp | grep 6443检查。第四,证书问题,如果之前 init 过又没清理干净,残留的证书会导致新 API Server 启动失败。用kubeadm reset清理后重试。
4.2 kubeadm reset 之后必须清理的残留文件
kubeadm reset不会自动清理所有文件,残留的配置和证书会导致下一次 init 失败。我一般会手动清理以下目录。
# 停止 kubelet systemctl stop kubelet # 清理 kubeadm 相关目录 rm -rf /etc/kubernetes/ rm -rf /var/lib/etcd/ rm -rf $HOME/.kube/ # 清理 CNI 配置 rm -rf /etc/cni/net.d/ # 清理 iptables 规则 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X # 重启容器运行时和 kubelet systemctl restart containerd systemctl restart kubelet这些目录里,/etc/kubernetes/存放了证书和静态 Pod 清单,/var/lib/etcd/存放 etcd 数据,$HOME/.kube/存放 kubeconfig。不清理干净就重新 init,etcd 可能因为数据不一致而启动失败,API Server 可能因为证书不匹配而拒绝连接。
iptables 规则清理也很重要。kube-proxy 和 CNI 插件会写入大量规则,reset 后这些规则可能残留,导致新集群的网络行为异常。清理后重启容器运行时和 kubelet,让它们重新生成必要的配置。
4.3 初始化成功后的验证步骤
kubeadm init成功不代表集群就能用了,还需要验证几个关键组件。
# 确认节点状态 kubectl get nodes # 确认核心组件 Pod 状态 kubectl get pods -n kube-system # 确认 API Server 健康 kubectl get --raw /healthz # 确认 DNS 可用 kubectl run test-dns --image=busybox:1.28 --rm -it -- nslookup kubernetes.default节点状态应该是 Ready,kube-system 下的 Pod 应该全部 Running。如果有 Pod 处于 Pending 或 CrashLoopBackOff,先解决它们再继续。/healthz返回 ok 说明 API Server 正常。DNS 测试能解析出 ClusterIP 说明 CoreDNS 工作正常。
如果节点状态是 NotReady,通常是 CNI 插件还没装。kubeadm init 完成后需要手动安装 CNI 插件,否则节点不会进入 Ready 状态。这是新手最容易卡住的地方,因为 kubeadm 的输出里不会明确提示这一点。
5. 避坑与常见问题:那些让我加班到凌晨的 k8s 故障
5.1 节点 NotReady 但 kubelet 日志没有明显报错
现象:kubectl get nodes显示 NotReady,但journalctl -u kubelet里没有 ERROR 级别的日志。
原因:kubelet 与 API Server 的通信正常,但容器运行时或 CNI 插件有问题。kubelet 的日志级别默认只记录关键错误,一些警告信息被淹没了。
解决:用journalctl -u kubelet --no-pager | grep -i "cni\|runtime\|failed"过滤关键词。同时检查systemctl status containerd和crictl ps的输出。如果是 CNI 问题,确认/etc/cni/net.d/下有配置文件且 CNI 插件的二进制文件存在于/opt/cni/bin/。
5.2 Pod 内无法访问 Service,但直接访问 Pod IP 正常
现象:在 Pod 内curl <service-name>超时,但curl <pod-ip>正常。
原因:kube-proxy 没有正确写入 iptables 或 IPVS 规则,或者 Service 的 Endpoints 为空。
解决:先kubectl get endpoints <service-name>确认 Endpoints 是否有 Pod IP。如果为空,检查 Service 的 selector 是否匹配 Pod 标签。如果 Endpoints 正常,检查 kube-proxy Pod 是否 Running,以及节点上的 iptables 规则是否有对应的 Service 转发规则。用iptables -t nat -L KUBE-SERVICES -n | grep <service-ip>查看。
5.3 存储卷挂载失败导致 Pod 一直 ContainerCreating
现象:Pod 状态一直是 ContainerCreating,describe 显示FailedMount或Unable to attach or mount volumes。
原因:PV 和 PVC 不匹配、StorageClass 配置错误、或者节点上缺少对应的挂载工具。
解决:先kubectl get pvc确认 PVC 是否 Bound。如果 Pending,检查 StorageClass 是否存在且 provisioner 正常工作。如果 PVC 已 Bound 但挂载失败,检查节点上是否安装了 NFS 客户端、iSCSI 工具等依赖。用kubectl describe pod看具体挂载错误信息,常见的有mount: wrong fs type或timeout。
5.4 节点磁盘压力导致 Pod 被驱逐
现象:Pod 突然被 Evicted,节点状态显示DiskPressure。
原因:节点上的镜像和容器日志占满了磁盘,kubelet 触发驱逐策略。
解决:先清理无用镜像crictl rmi --prune,再清理容器日志。长期方案是配置 kubelet 的--eviction-hard和--eviction-soft参数,以及定期清理镜像。用df -h确认哪个分区满了,通常是/var/lib/containerd或/var/log。
5.5 Service 的 ClusterIP 无法 ping 通
现象:在 Pod 内 ping Service 的 ClusterIP 不通,但 curl 对应的端口是通的。
原因:ClusterIP 是虚拟 IP,由 iptables 或 IPVS 规则实现转发,不响应 ICMP 请求。ping 不通是正常现象。
解决:不要用 ping 测试 Service 连通性,用curl或nc测试具体端口。如果端口也不通,再按 5.2 的方法排查。
6. 进阶技巧:用临时容器和事件流快速定位疑难故障
6.1 临时容器:不重启 Pod 也能进去排查
k8s 1.23 之后,临时容器(Ephemeral Container)成为稳定特性。当 Pod 里的容器没有 shell 或者已经崩溃无法进入时,可以用临时容器挂载到同一个 namespace 里排查。
# 给运行中的 Pod 添加一个临时容器 kubectl debug -it <pod-name> --image=busybox:1.28 --target=<container-name> # 直接复制一个 Pod 并修改启动命令 kubectl debug <pod-name> -it --copy-to=debug-pod --container=debug -- sh--target参数让临时容器共享目标容器的进程命名空间,可以直接看到目标容器的进程和网络。--copy-to则是创建一个 Pod 副本,可以修改镜像或命令来绕过原 Pod 的启动问题。这两个用法在排查“容器起不来但又想看里面状态”的场景下特别有用。
参数说明:--image指定临时容器使用的镜像,建议用带调试工具的镜像如nicolaka/netshoot;--target指定要共享命名空间的容器名;--copy-to创建的新 Pod 名称需要唯一。
6.2 用事件流和审计日志做故障回溯
k8s 的 Event 默认只保留一小时,对于偶发故障,事后排查往往找不到线索。我一般会部署一个事件收集工具,把 Event 持久化到外部存储。如果没有这个条件,至少可以用kubectl get events -w实时观察。
# 实时观察所有 namespace 的事件 kubectl get events -A -w # 按资源类型过滤事件 kubectl get events -A --field-selector involvedObject.kind=Pod # 查看审计日志(如果启用了) tail -f /var/log/kubernetes/audit.log | grep <resource-name>审计日志记录了所有 API 请求,能回答“谁在什么时候改了什么”的问题。对于配置被误改导致的故障,审计日志是唯一的后悔药。启用审计需要在 API Server 的启动参数里配置--audit-policy-file和--audit-log-path,生产环境建议至少记录 RequestResponse 级别。
6.3 一个我反复用到的排查习惯
每次处理完故障,我会把kubectl describe和关键日志的输出保存到一个按日期命名的文件里。下次遇到类似现象时,先翻之前的记录对比。这个习惯帮我省了很多重复排查的时间,因为 k8s 的故障模式其实很有限,大部分问题都是那几种原因换了个表现形式。另外,我习惯在集群里常备一个netshoot的 DaemonSet,需要抓包或测网络时直接kubectl exec进去,不用临时拉镜像。这个镜像里 tcpdump、nslookup、curl、ss 都有,排查网络问题时能省不少事。希望帮到你。
本文还有配套的精品资源,点击获取