Skip to content

排错体系

"服务不可用"在 K8s 里可能落在入口层、Service、Pod、节点、存储、DNS 解析、NetworkPolicy、控制平面或应用自身。排查的效率依赖一个习惯:先分层定位,再看具体命令。每层的排查对象和工具是固定的,但问题会跨层叠加。

分层路径

用户请求进入集群后经过的每一层都可能出问题:

第一组命令用来快速扫一眼全局状态:

bash
kubectl get pods -A -o wide
kubectl get svc -A
kubectl get events -A --sort-by=.lastTimestamp
kubectl get nodes -o wide

从这四条命令能看到 Pod 有没有大面积的 CrashLoopBackOff、服务有没有全部 NotReady、节点有没有大面积 NotReady、最近的 Events 集中在哪个方向。这四样看完,大部分时候能知道问题大概落在哪一层。

Pod 层

bash
kubectl describe pod <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace> --previous  # Pod 重启后看上一次的日志

Events 比日志先看。Events 告诉你 Pod 在哪个阶段卡住了;日志告诉你在这一阶段里具体发生了什么。

状态发生在哪个阶段排查方向
Pending调度PVC 未绑定、节点资源、污点、亲和性
ImagePullBackOff镜像拉取仓库地址、凭据、证书、节点网络
ContainerCreating容器创建CNI 分配网络、卷挂载、sandbox 创建
CrashLoopBackOff容器运行启动命令、配置、依赖服务、OOM
OOMKilled容器运行内存 limit、应用内存占用

Service 层

Service 不通时先拆分:是 DNS 解析不到 ClusterIP,还是 ClusterIP 转不到 Pod:

bash
kubectl -n demo get svc web
kubectl -n demo get endpointslice -l kubernetes.io/service-name=web
kubectl -n demo get pod -l app=web -o wide

用临时 Pod 从集群内部测试:

bash
kubectl run curl --rm -it --image=curlimages/curl --restart=Never -- sh
# Pod 内
curl -v http://web.demo.svc.cluster.local   # 走 Service
curl -v http://<pod-ip>:8080                 # 直连 Pod IP

直连 Pod IP 通而 Service 不通:问题在 Service 端口映射、selector 没匹配到 Pod、EndpointSlice 内容为空或 kube-proxy/节点转发规则有问题。

直连 Pod IP 也不通:问题在 CNI、NetworkPolicy 或应用本身没在监听。

Gateway/Ingress 层

Gateway API:

bash
kubectl get gatewayclass
kubectl get gateway -A
kubectl get httproute -A
kubectl describe httproute <name> -n <namespace>

看 HTTPRoute 的 status 里的 Conditions——它不是可有可无的字段,是路由是否真正下发的直接信号:

Conditions问题
Accepted=False路由没被 Gateway 接受——parentRefs、namespace 权限、listener 不匹配
ResolvedRefs=False后端 Service 或 Secret 解析失败
Programmed=False控制器还没把规则下到数据面

Ingress:

bash
kubectl get ingress -A
kubectl describe ingress <name> -n <namespace>
kubectl get ingressclass
现象判断方向
外部入口完全不通DNS、LB VIP、控制器 Pod 是否在运行
返回 404Host 或 Path 没有匹配的规则
502/503后端 Service 不可用、Pod 不 Ready
TLS 报错Secret 不存在、证书过期、域名不匹配

存储层

PVC Bound 只说明绑定成功,不说明挂载成功和 IO 正常。三个要分别验证:

bash
kubectl get pvc -A
kubectl describe pvc <pvc-name> -n <namespace>
kubectl get pv
kubectl describe pod <pod-name> -n <namespace>  # Events 里有 mount 信息

节点上:

bash
journalctl -u kubelet -n 100 --no-pager | grep -i mount
mount | grep kubelet

NFS 场景在节点上验证客户端能否到达服务端:

bash
showmount -e <nfs-server>

节点层

bash
kubectl describe node <node-name>      # 看 Conditions 和 Events
systemctl status kubelet --no-pager
systemctl status containerd --no-pager
journalctl -u kubelet -n 200 --no-pager
df -h && free -h

节点有 DiskPressure 或 MemoryPressure 时,Pod 层面的问题只是表面。要看触发压力的真实原因——日志没轮转、镜像堆积、emptyDir 被写爆。

控制平面层

bash
kubectl -n kube-system get pods -o wide | grep -E 'apiserver|scheduler|controller|etcd'
kubectl get --raw='/readyz?verbose'
kubectl get --raw='/livez?verbose'

/readyz?verbose 能看到每个控制平面组件的健康检查结果,出问题时能定位到具体是哪个组件不健康。

现象可能出问题的组件
kubectl 操作卡顿、超时apiserver、etcd 延迟
资源创建失败etcd 写入、准入 webhook、认证
Pod 一直不被调度scheduler、节点资源
副本异常不自动恢复controller-manager

故障现场保留

一次 K8s 故障至少保留这些信息:

信息获取方式
相关资源 YAMLDeployment、Service、Route、PVC
Pod Events 和状态kubectl describe pod
应用日志kubectl logs(当前和 --previous
节点状态Node Conditions、kubelet/containerd 日志
入口指标Gateway/Ingress 的 QPS、状态码、延迟
变更记录镜像 tag、Helm revision、Git commit、kubectl rollout history

接口超时、发布异常这类故障复盘,这些信息比一句"Pod 不稳定"有分析价值。