K8S故障排查三板斧-CSDN博客

Kubernetes 故障排查三板斧:从入门到精通的排障指南

导读:在生产环境中,K8s 集群每天都会面临各种意想不到的问题------Pod 启动失败、服务无法访问、节点状态异常......面对这些问题,运维工程师的排查效率直接决定了业务的恢复速度。本文结合实际生产案例,系统梳理 K8s 故障排查的"三板斧"方法论,帮助你建立一套完整的排障思维框架。


一、为什么 K8s 故障排查这么难?

K8s 作为一个分布式容器编排平台,其架构本身就带来了排查的复杂性:

  • 组件繁多:Master 节点涉及 etcd、api-server、scheduler、controller-manager 四大组件;Worker 节点涉及 kubelet、kube-proxy 和 CNI 网络插件;
  • 网络分层:物理机网络、Pod 网络、Service 网络三层隔离,任何一层出问题都会导致"不通";
  • 抽象层级多:从 Pod 到 Deployment 到 Service 到 Ingress,经过多层代理转发,链路长,定位难。

但万变不离其宗。不管问题表象如何千变万化,K8s 故障排查都有其固定套路。经过大量实践总结,我把排查方法论归纳为 "三板斧"

  1. kubectl describe ------ 查事件,看状态
  2. kubectl logs ------ 看日志,找报错
  3. kubectl exec ------ 进容器,查细节

下面我们逐一拆解,并结合真实案例进行实战演练。


二、第一斧:kubectl describe ------ 查事件,看状态

2.1 核心原理

kubectl describe 命令可以查看资源的详细元数据事件(Events)信息。Events 记录了 K8s 各组件与该资源交互的完整过程,是排查问题的第一入口。

使用场景

Pod 状态 可能原因 describe 重点关注
Pending 资源不足、节点端口占用、调度失败 Events 中的 Scheduler 事件
ImagePullBackOff 镜像不存在、镜像仓库权限问题、网络不通 Events 中的 Pulling/Failed 事件
CrashLoopBackOff 容器启动即退出、端口冲突、配置错误 Containers 字段的 State 和 Last State
ErrImagePull 镜像名称拼写错误、tag 不存在 Events 中的 Failed to pull image
RunContainerError 启动命令不存在、环境变量错误 Containers 字段的 Message

2.2 实战案例:镜像拉取失败

问题描述 :部署了一个新业务的 Pod,状态一直显示 ImagePullBackOff

资源清单

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: troubleshooting-describe
spec:
  containers:
  - name: c1
    image: registry.cn-hangzhou.aliyuncs.com/eci_open/nginx:latest1111

排查过程

bash 复制代码
# 第一步:查看 Pod 状态
[root@master231 ~]# kubectl get pods -o wide
NAME                       READY   STATUS             RESTARTS   AGE
troubleshooting-describe   0/1     ImagePullBackOff   0          18s

# 第二步:describe 查看详细信息
[root@master231 ~]# kubectl describe pod troubleshooting-describe

# 重点看 Events 部分
Events:
  Type     Reason   Age                From               Message
  ----     ------   ----               ----               -------
  Normal   Scheduled 69s                default-scheduler  Successfully assigned ...
  Normal   Pulling    25s (x3 over 68s) kubelet            Pulling image "registry.cn-hangzhou.aliyuncs.com/eci_open/nginx:latest1111"
  Warning  Failed     24s (x3 over 68s) kubelet            Failed to pull image "...nginx:latest1111": rpc error: code = Unknown desc = Error response from daemon: manifest for ... not found: manifest unknown
  Warning  Failed     12s (x3 over 67s) kubelet            Error: ErrImagePull
  Normal   BackOff    12s (x3 over 67s) kubelet            Back-off pulling image "..."
  Warning  Failed     12s (x3 over 67s) kubelet            Error: ImagePullBackOff

根因分析 :从 Events 中可以清晰看到 manifest unknown,说明镜像 tag latest1111 根本不存在。这就是镜像名称拼写错误导致的。

经验总结 :当看到 ImagePullBackOff 状态时,第一时间用 describe 看 Events,通常 90% 的镜像问题都能在这里定位。


三、第二斧:kubectl logs ------ 看日志,找报错

3.1 核心原理

kubectl logs 用于查看 Pod 中指定容器的标准输出和标准错误日志。当容器已经启动但运行异常时,日志往往是最直接的线索。

常用参数

bash 复制代码
# 查看指定容器的日志(Pod 多容器时必须指定 -c)
kubectl logs -c <容器名> <Pod名>

# 查看实时日志(类似 tail -f)
kubectl logs -f <Pod名>

# 查看最近 100 行日志
kubectl logs --tail=100 <Pod名>

# 查看上一次运行的日志(容器重启后查看前一次的日志)
kubectl logs --previous <Pod名>

3.2 实战案例:同 Pod 多容器端口冲突

问题描述 :一个 Pod 中运行了两个 Nginx 容器,状态显示 1/2 Error,不断重启。

资源清单

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: troubleshooting-logs
spec:
  containers:
  - name: c1
    image: registry.cn-hangzhou.aliyuncs.com/eci_open/nginx:latest
  - name: c2
    image: registry.cn-hangzhou.aliyuncs.com/acs/nginx:1.21
    # 此镜像可以正常启动,但是由于都使用80端口,所以会起不来

排查过程

bash 复制代码
# 第一步:查看 Pod 状态
[root@master231 ~]# kubectl get pods -o wide
NAME                   READY   STATUS             RESTARTS   AGE
troubleshooting-logs   1/2     CrashLoopBackOff   5 (2m10s ago) 5m23s

# 第二步:describe 发现 c2 容器异常退出,但原因不明
[root@master231 ~]# kubectl describe po troubleshooting-logs
# Containers 字段显示:
#   c1: State=Running (正常)
#   c2: State=Terminated, Reason=Error, Exit Code=1
# Events 只显示 "Back-off restarting failed container",没有更详细信息

# 第三步:用 logs 查看两个容器的日志
[root@master231 ~]# kubectl logs -c c1 troubleshooting-logs
# c1 日志正常:nginx 正常启动

[root@master231 ~]# kubectl logs -c c2 troubleshooting-logs
# c2 日志显示:
2025/12/01 01:11:25 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address in use)
...
nginx: [emerg] still could not bind()

根因分析 :K8s 的 Pod 中所有容器共享网络命名空间(Network Namespace) ,这意味着 c1 容器已经占用了 80 端口,c2 容器再尝试绑定 80 端口就会报 Address in use 错误。

经验总结

  • describe 只能看到容器异常退出,但无法看到退出原因的具体错误信息
  • describe 的 Events 无法提供足够信息时,一定要用 logs 查看容器内部日志;
  • 同一 Pod 中的多容器设计时,务必确保端口不冲突,或者使用不同端口。

四、第三斧:kubectl exec ------ 进容器,查细节

4.1 核心原理

有时候,即使 describelogs 都看了,问题仍然无法定位。这时候就需要进入容器内部进行手动排查,就像登录到一台 Linux 服务器上做故障诊断一样。

常用用法

bash 复制代码
# 交互式进入容器(注意指定 -c 参数选择容器)
kubectl exec -it -c <容器名> <Pod名> -- sh

# 非交互式执行命令
kubectl exec -c <容器名> <Pod名> -- ps -ef

# 查看容器内的网络配置
kubectl exec <Pod名> -- ip a
kubectl exec <Pod名> -- cat /etc/resolv.conf

4.2 实战案例:容器启动命令覆盖后的排障

问题描述 :为了排查 c2 容器的问题,我们用 commandargs 覆盖了容器的默认启动命令,让容器先"活起来",再进去手动操作。

资源清单

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: troubleshooting-exec
spec:
  containers:
  - name: c1
    image: registry.cn-hangzhou.aliyuncs.com/eci_open/nginx:latest
  - name: c2
    image: registry.cn-hangzhou.aliyuncs.com/acs/nginx:1.21
    # 覆盖默认启动命令(相当于 Dockerfile 的 ENTRYPOINT)
    command:
    - tail
    # 覆盖默认参数(相当于 Dockerfile 的 CMD)
    args:
    - -f
    - /etc/hosts

排障过程

bash 复制代码
# 第一步:容器成功启动
[root@master231 ~]# kubectl get pods -o wide
NAME                   READY   STATUS    RESTARTS   AGE
troubleshooting-exec   2/2     Running   0          3s

# 第二步:进入 c2 容器手动操作
[root@master231 ~]# kubectl exec -c c2 -it troubleshooting-exec -- sh
/ # ps -ef
PID   USER     TIME   COMMAND
    1 root      0:00   tail -f /etc/hosts
   12 root      0:00   sh

# 第三步:尝试手动启动 nginx
/ # nginx
2025/12/01 01:28:52 [emerg] 20#20: bind() to 0.0.0.0:80 failed (98: Address in use)
# 确认是端口冲突!

# 第四步:修改端口后启动
/ # sed -i '/listen/s#80#81#g' /etc/nginx/conf.d/default.conf
/ # nginx
/ # netstat -untalp
tcp        0 0 0.0.0.0:80    0.0.0.0:*     LISTEN  (c1 容器)
tcp        0 0 0.0.0.0:81    0.0.0.0:*     LISTEN  (c2 容器,修改端口后成功)

根因分析:通过进入容器手动操作,确认了端口冲突的问题,并找到了修改端口解决冲突的方法。

经验总结

  • 当容器无法正常启动时,可以先临时用 command: [tail, -f, /etc/hosts] 让容器保持运行,再 exec 进去手动排查;
  • command 相当于覆盖 Dockerfile 的 ENTRYPOINTargs 相当于覆盖 CMD,这个技巧在故障排查中非常实用;
  • 进入容器后可以检查配置文件、端口占用、网络连通性等,和操作普通 Linux 系统一样。

五、故障排查决策树

根据实际工作经验,我总结了以下决策树,帮助你快速定位问题:

复制代码
Pod 异常
├── Pending(无法调度)
│   ├── 节点资源不足 → 扩容节点或清理资源
│   ├── 节点端口被占用 → kubectl describe 确认具体原因
│   └── 调度约束(nodeSelector/污点)→ 检查节点标签和污点配置
│
├── ImagePullBackOff / ErrImagePull(镜像问题)
│   ├── 镜像名称/tag 错误 → describe Events 确认
│   ├── 私有仓库认证失败 → 检查 imagePullSecrets 配置
│   └── 网络不通 → 检查节点到镜像仓库的网络连通性
│
├── CrashLoopBackOff(容器启动即退出)
│   ├── 查看日志 → kubectl logs / kubectl logs --previous
│   ├── 查看退出码 → describe 的 Containers.State.Exit Code
│   │   ├── Exit Code 0 → 正常退出,检查重启策略
│   │   ├── Exit Code 1 → 应用报错,查看日志
│   │   └── Exit Code 137 → OOMKilled(内存不足被杀)
│   └── 进入容器排查 → kubectl exec(配合 command: tail -f ...)
│
├── Running 但服务不可访问
│   ├── Pod 内部 → kubectl exec curl localhost:端口
│   ├── Pod 间通信 → kubectl exec curl 目标Pod_IP:端口
│   ├── Service 代理 → kubectl get svc / kubectl get ep
│   ├── DNS 解析 → kubectl exec nslookup Service名.命名空间.svc.cluster.local
│   └── Ingress → 检查 Ingress 配置和 Ingress Controller 日志
│
└── ContainerCreating(一直卡在创建中)
    ├── describe 查看 Events
    ├── 存储卷挂载失败 → 检查 PV/PVC/SC 状态
    ├── 镜像拉取中 → 检查网络和镜像大小
    └── CNI 网络配置失败 → 检查 CNI 插件状态

六、高频故障场景速查表

故障场景 常见原因 排查命令 解决方案
Pod 状态 Pending 节点资源不足 kubectl describe pod <name> 扩容节点或清理无用 Pod
Pod 状态 ImagePullBackOff 镜像不存在/无权限 kubectl describe pod <name> 检查镜像名称、配置 imagePullSecrets
Pod 状态 CrashLoopBackOff 应用启动报错/端口冲突 kubectl logs <name> 查看日志修复配置,注意同 Pod 端口不冲突
Pod 状态 OOMKilled 内存超限 kubectl describe pod <name> 调整 resources.limits.memory
Pod 状态 RunContainerError 启动命令不存在 kubectl describe pod <name> 检查 command/args 拼写
节点状态 NotReady kubelet 异常/CNI 故障 systemctl status kubelet 检查 kubelet 日志和 CNI 配置
Service 无法访问 Endpoints 为空 kubectl get ep <svc名> 检查 Service selector 与 Pod labels 是否匹配
DNS 解析失败 CoreDNS 异常 kubectl exec nslookup xxx 检查 CoreDNS Pod 状态和配置

七、排障思维框架总结

K8s 故障排查的核心思想是自上而下,逐层定位

复制代码
用户访问入口
    ↓
Ingress Controller → Ingress 配置是否正确?
    ↓
Service → Endpoints 是否有后端 Pod?selector 是否匹配?
    ↓
Pod → Pod 是否 Running?容器是否 Ready?
    ↓
容器内部 → 应用是否正常监听端口?日志是否有报错?
    ↓
节点 → kubelet 是否正常?CNI 网络是否正常?

记住这个排查链路,遇到任何 K8s 问题都能快速定位。

三板斧速记口诀

一 describe 看状态,Events 里找答案;
二 logs 看日志,报错信息最直接;
三 exec 进容器,手动排查不犹豫。


八、写在最后

K8s 故障排查能力的提升,不是靠看文档就能练出来的,核心在于大量的实战练习。建议你:

  1. 刻意制造故障:手动删除 Pod、修改错误镜像 tag、制造端口冲突等,然后用三板斧排查;
  2. 记录排障日志:每次排查完问题后,记录问题现象、排查过程、根因分析和解决方案;
  3. 关注 Events :养成习惯,任何资源出问题第一时间 describe 看 Events;
  4. 理解底层原理:了解 Pod 的创建流程、Service 的代理机制、CNI 的网络模型,排查时才能有的放矢。

希望这篇文章能帮助你建立系统的 K8s 故障排查思维,在运维之路上越走越远。


参考资源

相关推荐
程序员老邢1 小时前
【技术底稿 32】Nginx 经典大坑复盘:本机公网域名自环代理,导致接口返回首页 / 404 实战排障
java·运维·nginx·前后端分离·技术底稿·后端部署
忧云2 小时前
开源 SSH 客户端 Netcatty:免费替代 Termius,带 AI 的现代化运维工具
运维·开源·ssh
Geoking.2 小时前
云计算服务模型详解:SaaS、PaaS 与 IaaS 的区别、发展历史与应用场景
云原生·云计算·paas
想唱rap2 小时前
传输层协议TCP
linux·运维·服务器·网络·c++·tcp/ip
曦夜日长2 小时前
Linux系统篇,权限(二):缺省权限、最终权限的计算、文件隔离的两种方式
linux·运维·服务器
kebidaixu3 小时前
OK3568开发板更新Ubuntu22.04方法总结
linux·运维·服务器
AIDF20263 小时前
K8s 完整知识体系(含架构图)
云原生·容器·kubernetes