排错手册¶
排错不是「猜一个原因然后重启」。先确定故障边界,再收集证据,最后验证假设。这份手册给你一套可以重复执行的流程,以及一张按现象索引的故障表。
五步排错法¶
flowchart LR
A[定义现象] --> B[确定边界]
B --> C[收集证据]
C --> D[提出假设]
D --> E[验证并修复]
E -->|未解决| C
图:不要跳过「确定边界」。同一个 502,可能是 Pod、Service、Ingress、CNI 或外部 LB 的问题。
- 定义现象:谁访问谁、什么时间、错误码/超时、影响范围。
- 确定边界:单个 Pod?单个节点?单个 namespace?全部服务?
- 收集证据:
get、describe、logs、events、top、节点日志。 - 提出假设:一次只验证一个,写出「如果假设成立,应该看到什么」。
- 验证并修复:修复后做回归,确认没有引入新问题。
先取证,再重启
kubectl delete pod 会清掉容器日志与上一次退出状态。先执行 kubectl logs --previous、describe、保存事件,再考虑重启。
第一分钟做什么¶
# 1. 集群是否健康
kubectl get --raw='/readyz?verbose'
# 2. 节点是否 Ready
kubectl get nodes -o wide
# 3. 异常 Pod
kubectl get pods -A --field-selector=status.phase!=Running
# 4. 最近事件
kubectl get events -A --sort-by=.lastTimestamp | tail -30
# 5. 控制平面
kubectl get pods -n kube-system -o wide
如果 API 都连不上,先跳到「控制平面」一节,不要在应用层浪费时间。
按 Pod 状态索引¶
Pending¶
Pod 没有被调度到节点。
| 事件关键词 | 原因 | 处理 |
|---|---|---|
Insufficient cpu/memory |
节点资源不足 | 降 requests、扩容节点、清理僵尸 Pod |
node(s) had untolerated taint |
污点未容忍 | 加 toleration,或调度到其他节点 |
node affinity/selector |
亲和性不满足 | 检查 nodeSelector、affinity、节点标签 |
persistentvolumeclaim not found |
PVC 不存在 | 创建 PVC 或修正名字 |
pod has unbound immediate PVC |
PVC 未绑定 | describe pvc,检查 StorageClass |
exceeded quota |
资源配额 | 调整 ResourceQuota |
no nodes available |
没有可调度节点 | 检查节点状态与 cordon |
ImagePullBackOff / ErrImagePull¶
| 原因 | 验证 | 处理 |
|---|---|---|
| 镜像名 / tag 错 | crictl pull <image> |
修正镜像 |
| 私有仓库无凭据 | imagePullSecrets |
创建 docker-registry Secret |
| 仓库不可达 | 节点上 curl registry |
配 mirror / 代理 |
| 架构不匹配 | docker manifest inspect |
用多架构镜像 |
| 限流 | 事件中有 429 |
配镜像加速或重试 |
CrashLoopBackOff¶
容器启动后反复退出。
kubectl logs <pod> -n <ns> --previous
kubectl describe pod <pod> -n <ns> | grep -E 'Exit Code|Reason|Last State'
| 退出码 | 含义 | 常见原因 |
|---|---|---|
| 0 | 正常退出 | 前台进程结束,容器没有常驻进程 |
| 1 | 应用错误 | 配置错、依赖不可用、启动异常 |
| 127 | 命令不存在 | command 路径错 |
| 137 | 被 SIGKILL / OOM | 内存超限、liveness 重启 |
| 143 | SIGTERM | 优雅终止、被删除 |
Running 但 0/1¶
readiness 探针失败,Pod 不接收流量。
kubectl describe pod <pod> -n <ns> | grep -A10 -i readiness
kubectl exec <pod> -n <ns> -- wget -qO- http://localhost:<port>/<path>
kubectl get endpoints <svc> -n <ns>
常见原因:探针路径/端口错、应用启动慢但 initialDelaySeconds 太短、依赖未就绪、host 头不匹配。
Terminating 卡住¶
- finalizer 未清理:找到对应控制器;
- 优雅终止超时:
terminationGracePeriodSeconds; - 节点失联:
kubectl delete pod --force --grace-period=0(确认容器已停)。
按故障域索引¶
Service 访问不通¶
kubectl get svc <svc> -n <ns> -o yaml
kubectl get endpoints <svc> -n <ns>
kubectl get endpointslice -n <ns> -l kubernetes.io/service-name=<svc>
kubectl get pods -n <ns> --show-labels
| 检查点 | 正常 | 异常处理 |
|---|---|---|
| selector | 与 Pod 标签一致 | 修正 selector |
| Endpoints | 有 Pod IP | 检查 readiness、namespace |
| targetPort | 与容器端口一致 | 修正端口名/号 |
| NetworkPolicy | 允许来源 | 加放行规则 |
| DNS | nslookup svc.ns 有结果 |
查 CoreDNS |
| kube-proxy | Pod Running | 查规则 / 日志 |
DNS 解析失败¶
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50
kubectl run dns --image=busybox:1.36 --rm -it --restart=Never -- \
nslookup kubernetes.default
- CoreDNS Pod 是否 Ready;
- 是否被 NetworkPolicy 阻断 53 端口;
/etc/resolv.conf的nameserver是否是 Service CIDR 内的地址;- 跨 namespace 是否用了短名。
Ingress 502 / 404¶
kubectl get ingress -n <ns> -o yaml
kubectl get svc -n ingress-nginx
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller --tail=100
kubectl get endpoints <backend-svc> -n <ns>
- 404:host / path 不匹配,或 IngressClass 不对;
- 502:后端未 Ready、端口错、协议错(HTTPS 后端需注解);
- 504:后端超时,检查
proxy-read-timeout与应用性能。
PVC Pending¶
kubectl describe pvc <pvc> -n <ns>
kubectl get storageclass
kubectl get pv
kubectl get pods -n kube-system | grep -E 'csi|provisioner'
| 原因 | 处理 |
|---|---|
| 没有默认 StorageClass | 指定 storageClassName 或设默认 |
WaitForFirstConsumer |
先创建使用它的 Pod |
| 容量不足 / 访问模式不匹配 | 调整请求或 PV |
| provisioner Pod 异常 | 查 CSI 日志 |
| 拓扑限制 | 用 allowedTopologies 或本地 PV |
节点 NotReady¶
kubectl describe node <node>
ssh <node> 'systemctl status kubelet; journalctl -u kubelet -n 100 --no-pager'
ssh <node> 'df -h; free -h; systemctl status containerd'
| 原因 | 现象 | 处理 |
|---|---|---|
| kubelet 挂了 | Kubelet stopped posting |
重启 kubelet,查配置 |
| 磁盘压力 | DiskPressure |
清理镜像/日志 |
| 内存压力 | MemoryPressure |
驱逐低优先级 Pod |
| 网络插件异常 | CNI Pod 未就绪 | 重启 CNI |
| 证书过期 | kubelet 报 x509 | 轮换证书 |
| 时间不同步 | TLS 错误 | 修 NTP |
控制平面异常¶
kubectl get pods -n kube-system
kubectl get --raw='/readyz?verbose'
sudo crictl ps | grep -E 'kube-apiserver|etcd|kube-controller|kube-scheduler'
sudo journalctl -u kubelet -n 200 --no-pager
- API Server 起不来:看静态 Pod 清单
/etc/kubernetes/manifests/与容器日志; - etcd 异常:检查磁盘、证书、
/var/lib/etcd空间; - 证书过期:
kubeadm certs check-expiration; - 全部静态 Pod 异常:检查 kubelet 与容器运行时。
资源与性能¶
kubectl top nodes
kubectl top pods -A --sort-by=cpu
kubectl describe node <node> | sed -n '/Allocated resources/,/Events/p'
kubectl get pod <pod> -o jsonpath='{.status.qosClass}'
- CPU 高但未限流:看应用本身;
- CPU 被 throttle:提高 limits 或优化;
- 内存持续增长:查泄漏,设置合理 limit;
- 节点磁盘满:清理未使用镜像
crictl rmi --prune。
常用证据命令¶
kubectl get events -n <ns> --sort-by=.lastTimestamp
kubectl describe pod <pod> -n <ns>
kubectl logs <pod> -n <ns> --all-containers --tail=200
kubectl logs <pod> -n <ns> --previous
kubectl get pod <pod> -n <ns> -o yaml
kubectl get endpoints,endpointslice -n <ns>
kubectl get pvc -n <ns>
kubectl get --raw='/readyz?verbose'
不要做的事¶
- 不要一上来就删 Pod / 重启节点;
- 不要同时改多个变量;
- 不要在没看 Events 的情况下猜镜像问题;
- 不要把
latest镜像用于生产; - 不要用
--force删除有状态 Pod 而不确认数据; - 不要把「Pod Running」当成「服务可用」。