排障三件套:事件、状态、日志

Kubernetes 排障和普通服务器排障最大的不同,是一切都有状态、有事件、有日志。Pod 卡住、容器重启、节点失联,这些都不是"悄悄发生"的,集群早就把线索写在了某处。所以排障第一步不是瞎猜,而是先按顺序把「事件—状态—日志」三件套拿齐。

先看 Pod 的状态(STATUS):Pending、ContainerCreating、Running、CrashLoopBackOff、ImagePullBackOff……不同状态指向不同问题域。再看事件(Events):describe 输出的 Events 段是排障第一现场,调度失败、拉取失败、探针失败都会在这里写明原因。最后看日志(Logs):容器到底为什么退出,业务日志和 stderr 里最清楚。

# 三件套命令速查
kubectl get pods -A                      # 看所有 Pod 的状态
kubectl describe pod <pod> -n <ns>       # 看事件、容器状态、条件
kubectl logs <pod> -n <ns>               # 看容器标准输出日志
kubectl logs <pod> -n <ns> --previous    # 看上一次退出容器的日志
本文核心知识点
  • 事件describe 的 Events 段是排障第一现场。
  • 状态Pending、CrashLoop 等状态指向不同问题域。
  • 日志业务日志和退出码说明根因。
  • 资源节点与集群层资源决定调度与运行。
Kubernetes 故障排查配图:集群节点方块中一台亮起红色警示灯并被放大镜聚焦的蓝色扁平科技插画
故障不会凭空消失,先找到集群留下的线索再动手。

Pod 卡在 Pending:调度问题怎么定位

Pod 一直停在 Pending,意思是调度器还没找到合适的节点,或者节点上 Pod 起不来。最常见的原因有三个:资源不够(requests 超了节点剩余可分配量)、节点有污点而 Pod 没有容忍、PVC 没绑定成功(Pod 声明了持久卷但卷一直 Pending)。

不要猜,直接看 describe 的 Events:调度器会把原因写得明明白白,比如 0/3 nodes are available: insufficient cpu 或者 node(s) had untolerated taint。再配合查节点可分配资源,就能判断是加规格、调 requests,还是加 toleration。

# 定位 Pending 根因
kubectl describe pod <pod> -n <ns>        # 看 Events 段的调度失败原因
kubectl get nodes                        # 看节点状态与角色
kubectl describe node <node>             # 看 Allocatable 与已分配资源
kubectl get pvc -n <ns>                  # 若 Pod 挂卷,先查 PVC 是否 Bound

资源不够时,Events 会明确告诉你每个节点差多少;这时候要么调小 requests,要么扩容节点,而不是反复删 Pod 重试——重试多少次结果都一样。

ImagePullBackOff:镜像拉取失败

ImagePullBackOff 是镜像拉取失败的标志,kubelet 会指数退避地重试。常见原因:镜像名或标签写错、私有仓库没配认证、镜像不存在、仓库网络不通或被限流。describe 的 Events 里通常有 Failed to pull image 和具体的 rpc error。

私有镜像仓库需要在 Pod 上配 imagePullSecrets,并且在 Deployment 里引用;镜像标签要显式写全(比如 nginx:1.25 而不是 nginx),否则可能拉到意想不到的版本。限流(比如 Docker Hub 的 rate limit)会让拉取一直超时,可以换镜像源或加认证。

# 给 Deployment 配置私有仓库凭据
kubectl create secret docker-registry regcred \
  --docker-server=registry.example.com \
  --docker-username=ops \
  --docker-password=xxxx

# 在 Deployment 的 pod 模板中引用
# spec:
#   template:
#     spec:
#       imagePullSecrets:
#         - name: regcred

排查顺序:先确认镜像在仓库里真实存在,再确认标签正确,最后确认认证和网络。别一上来就怀疑集群,多数时候是镜像侧的问题。

CrashLoopBackOff:容器反复重启

CrashLoopBackOff 表示容器起来后很快退出,kubelet 按指数退避不断重启。这几乎总是应用自身的问题:启动命令或参数错了、依赖的环境变量或配置缺失、连不上数据库或配置中心、健康检查探针把正常启动中的进程误判为失败。

第一手证据是 kubectl logs --previous——看上一次退出容器的日志,而不是当前正在重启的容器;再配合退出码判断:1 通常是应用内部错误,137 是被杀(多半 OOM),127 是命令找不到。探针误杀的问题,要看 readiness/liveness 的探测路径和启动时长是否合理。

# CrashLoop 排查组合拳
kubectl logs <pod> -n <ns> --previous     # 上一次退出的日志
kubectl describe pod <pod> -n <ns>       # 看 Last State 与退出码
kubectl get pod <pod> -n <ns> -o yaml    # 看探针与 env 配置

# 退出码速查:1=应用错误 127=命令不存在
#            137=SIGKILL(常见 OOM) 143=SIGTERM(优雅退出失败)

注意一个反直觉的点:CrashLoopBackOff 并不总是应用崩了。健康检查探针配得太激进,会让一个本来能正常启动的应用被反复杀死,排查时先把探针和启动日志一起看。