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 故障排查思维,在运维之路上越走越远。


参考资源

相关推荐
江畔柳前堤20 小时前
roLabelImg 详细安装教程
开发语言·人工智能·后端·云原生
nxb5561 天前
haproxy算法,ip透传,自定义haproxy错误页面
运维·服务器
AKAMAI1 天前
你的源服务器可能是你做出的最昂贵决定
运维·人工智能·云计算
Dxy12393102161 天前
Linux 编译安装 Python 3.12.10(多版本共存,不破坏系统Python)
linux·运维·python
技术深耕者1 天前
AI Agent从演示到生产:企业进入“自动化层”时代
运维·人工智能·自动化
w67820071 天前
Prisma不能优雅的支持DTO,试试Vona ORM吧
linux·运维·ubuntu
APItesterCris1 天前
Open Claw 实战教程:5 分钟搭建京东商品自动化监控与数据分析系统
大数据·运维·数据库·数据仓库·自动化
heimeiyingwang1 天前
【架构实战】Kubernetes调度器深度剖析:从Pod调度到自定义调度器
java·架构·kubernetes
阿里云云原生1 天前
五层监控与运维数字孪生:畅捷通如何打造应对亿级数据的全栈可观测体系?
云原生
阿里云云原生1 天前
从“救火”到“体检”:基于 STAROps 与 SysOM 的主机智能巡检闭环实战
云原生