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、Service 有没有全部 NotReady、节点有没有大面积 NotReady、最近 Events 集中在哪个方向。大部分时候,看完这四条就知道问题大概落在哪一层。

Pod 层

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 卡在哪个阶段(仍在 ContainerCreating——还没到应用层面);日志说启动后的应用行为(报了数据库连接错误——应用层面有问题,平台层正常)。

状态发生在哪个阶段先检查
Pending调度PVC 是否 Bound、节点资源、污点、亲和性
ImagePullBackOff镜像拉取仓库地址、imagePullSecrets、节点到仓库网络
ContainerCreating容器和网络创建CNI 分配 IP、卷挂载、sandbox 创建
CrashLoopBackOff容器运行logs --previous、exitCode、启动命令、OOM
OOMKilled容器运行memory 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 labels 不一致、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请求 404 或连接拒绝parentRefs 是否正确、namespace 权限、listener 是否匹配
ResolvedRefs=False请求 503后端 Service 是否存在、Secret 名称和 namespace
Programmed=False请求可能返回旧规则或 404控制器状态、Gateway describe

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 只说明 PV 和 PVC 绑定成功。挂载成功、权限正确、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 被写爆。只调大 Pod 的资源 limit 不解决节点磁盘满的问题。

控制平面层

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

故障现场保留

一次故障至少保留这些:

信息获取方式
相关资源 YAMLDeployment、Service、HTTPRoute、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 不稳定"有分析价值。