Appearance
排错体系
"服务不可用"在 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 是否在运行 |
| 返回 404 | Host 或 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 kubeletNFS 场景在节点上验证客户端能否到达服务端:
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 故障至少保留这些信息:
| 信息 | 获取方式 |
|---|---|
| 相关资源 YAML | Deployment、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 不稳定"有分析价值。