跳到主要内容
版本:v3&v6

POD故障处理

提示

本文介绍关于 k3s/k8s Pod异常问题的诊断流程、排查方法、常见问题及解决方案。

本文目录

类别内容
诊断流程诊断流程
常见排查方法检查Pod的状态
检查pod的详情及事件
检查pod的容器日志
检查pod的配置
检查Pod的监控
使用终端进入容器常规诊断
常见问题及解决方案常见的Pod异常状态及处理方式
Pod OOM异常问题处理

诊断流程

Alt text

  1. 查看Pod是否处于异常状态,具体操作,请参见检查Pod的状态。

    a. 如果Pod状态异常,可通过查看Pod的事件、Pod的日志、Pod的配置等信息确定异常原因。具体操作,请参见常见排查方法。关于Pod异常状态及处理方式,请参见常见的Pod异常状态及处理方式。

    b. 如果Pod状态为Running但未正常工作,请参见Pod状态为Running但没正常工作。

  2. 若确认是Pod OOM异常问题,请参见Pod OOM异常问题处理。

  3. 如果问题仍未解决,请提交工单。

常见的Pod异常状态及处理方式

Pod状态Pod含义解决方案
PendingPod未被调度到节点上。Pod状态为Pending
Init:N/MPod包含M个Init容器,其中N个已经启动完成。Pod状态为Init:N/M(Init:Error和Init:CrashLoopBackOff)
Init:ErrorInit容器已启动失败。Pod状态为Init:N/M(Init:Error和Init:CrashLoopBackOff)
Init:CrashLoopBackOffInit容器启动失败,反复重启。Pod状态为Init:N/M(Init:Error和Init:CrashLoopBackOff)
CompletedPod的启动命令已执行完毕。Pod状态为Completed
CrashLoopBackOffPod启动失败,反复重启。Pod状态为CrashLoopBackOff
ImagePullBackOffPod镜像拉取失败。Pod状态为ImagePullBackOff
RunningPod运行正常。Pod Running但是未正常工作。无需处理Pod状态为Running但没正常工作
TerminatingPod正在关闭中。Pod状态为Terminating
EvictedPod被驱逐。Pod状态为Evicted
OOMKilledPod OOM。Pod状态为OOMKilled

常见排查方法

检查Pod的状态

  1. 登录运维操作服务器。
  2. 进入ONES运维工具箱容器。
    ones-ai-k8s.sh # 进入ones运维操作容器
    # cd /data/ones/ones-ai-k8s # K8S实例
  3. 输入Pod所在的命名空间,查看Pod状态。
    kubectl get ns # 查看全部命名空间
    kubectl -n $namespace get po
    kubectl -n $namespace get po |grep -vi running # 查看非Running状态Pod
    kubectl get po -A |grep -vi running # 查看所有命名空间非Running状态Pod

检查Pod的详情及事件

  1. 登录运维操作服务器。

  2. 进入ONES运维工具箱容器。

    ones-ai-k8s.sh # 进入ones运维操作容器
    # cd /data/ones/ones-ai-k8s # K8S实例
  3. 输入Pod所在的命名空间,输入PodName查看Pod资源 describe详情信息。

    kubectl -n $namespace describe po $ PodName

查看Pod渲染编排情况、镜像、Pod IP、Event、Limit资源限制、所在节点等详细信息,当Pod出现异常重点关注Event事件信息。

检查Pod的容器日志

  1. 登录运维操作服务器。
  2. 进入ONES运维工具箱容器。
    ones-ai-k8s.sh # 进入ones运维操作容器
    # cd /data/ones/ones-ai-k8s # K8S实例
  3. 输入Pod所在的命名空间,输入PodName查看该Pod容器日志
    kubectl -n $namespace logs $PodName
    kubectl -n $namespace logs $PodName -c $ContainerName # 如果 Pod 中有多个容器,使用此选项指定容器名,以查看特定容器的日志。
    kubectl -n $namespace logs $PodName --tail=20 # 查看最新20行日志
    kubectl -n $namespace logs $PodName -f # 实时追踪 Pod 的日志
    kubectl -n $namespace logs --previous $PodName # 查看 Pod 上一个容器实例的日志,例:崩溃前容器日志
    kubectl -n $namespace logs $PodName > /tmp/PodName.log # 保存日志信息
  4. 从其他渠道获取日志信息;例:kibanna(EFK\ELK)、grafana(loki)、运维工具箱在线下载日志.

检查Pod的配置

  1. 登录运维操作服务器。
  2. 进入ONES运维工具箱容器。
    ones-ai-k8s.sh # 进入ones运维操作容器
    # cd /data/ones/ones-ai-k8s # K8S实例
  3. 输入Pod所在的命名空间,输入PodName查看Pod的配置信息。
    kubectl -n $namespace get po $PodName -o yaml
    查看Pod的详细配置,包括容器、卷挂载、环境变量等信息。确认配置是否符合预期。特别关注以下配置:
  • 容器镜像版本: 确保使用的容器镜像版本是预期的版本。(查看配置确认)
  • 环境变量: 检查环境变量配置,确保配置正确且没有缺漏。
  • 卷挂载: 确认卷挂载配置,检查挂载点是否正确,卷是否成功挂载。

检查Pod的监控

  1. 登录运维操作服务器。

  2. 进入ONES运维工具箱容器。

    ones-ai-k8s.sh # 进入ones运维操作容器
    # cd /data/ones/ones-ai-k8s # K8S实例
  3. 输入Pod所在的命名空间,输入PodName查看Pod的监控信息。

    kubectl -n $namespace top po $PodName

通过此命令可以查看实时的CPU和内存使用情况,帮助定位资源问题。关注以下指标:

  • CPU使用率: 确认是否有异常的CPU使用率波动。
  • 内存使用率: 检查内存占用情况,确认是否超过了分配的限制。
  1. 如上通过top命令查看当前Pod实时资源状态,再k3s环境不支持,同时也建议通过部署内置监控系统,通过grafana面板确认资源及历史资源状态,通过时间曲线维度,更容易发现问题。

使用终端进入容器常规诊断

  1. 登录运维操作服务器。

  2. 进入ONES运维工具箱容器。

    ones-ai-k8s.sh # 进入ones运维操作容器
    # cd /data/ones/ones-ai-k8s # K8S实例
  3. 输入Pod所在的命名空间,输入PodName和ContainerName使用以下命令进入容器终端。

    kubectl -n $namespace exec -it $PodName -c $ContainerName -- /bin/bash
    kubectl -n $namespace exec -it $PodName -c $ContainerName -- /bin/sh # 没有bash时,通过sh进入终端
    kubectl -n $namespace exec -it $PodName -- ping <destination-ip-or-domain>

    # 容器制作Base基座有所区别,个别容器可能不适用以下命令。
    ps # 通过ps 等命令进行常规进程诊断,需要根据容器业务进行进一步排查,例Project-api,可以排查服务进程、进一步排查其进程使用的配置,是否存在业务配置异常。

    ping、curl、wget、telnet nslookup host # 通过此类网络客户端工具排查网络等连通性问题,例:对端点kafka service endpoint 异常,可以通过ping kafka-ha
  4. 通过ones-tools容器进行诊断

    ones-ai-k8s.sh # 进入ones运维操作容器
    make ones-tools NAMESPACE=ones # ones 为namespace
    ping kafka-ha # 例:测试pod之间端点连通性
    mysql -h mysql-cluster-mysql-master -u root -p # 登录MySQL测试,查询联调等
    redis # redis联调同理

    通过3/4步骤命令可以进入容器内部,进行容器内部的调试和排查。

Pod状态为Pending

问题原因

若Pod停留在Pending状态,说明该Pod不能被调度到某一个节点上。通常是由于资源依赖、资源不足、该Pod使用了hostPort、污点和容忍等原因导致集群中缺乏需要的资源。

问题现象

Pod的状态为Pending。

解决方案

查看Pod的事件,根据事件描述,定位Pod不能被调度到节点的原因。主要原因有以下几类:

  • 资源依赖

    创建Pod时,需要依赖于集群中ConfigMap、PVC等资源。例如,Pod添加存储卷声明前,存储卷声明需要先与存储卷绑定。

  • 资源不足

    1. 查看该Pod节点资源状态(通过登录节点查看/通过grafana监控面板查看/其他方式)

      说明

      某个节点实际使用的CPU、内存资源非常低,新加入一个Pod时,如果会导致实际使用的资源超过该节点最大可供使用的资源,则调度程序不会将该Pod分配到该节点。这样可避免在日常的流量高峰时段,节点上出现资源短缺的情况。

    2. 若集群中的CPU或内存都已经耗尽,可参考如下方法处理。

      • 紧急删除或减少不必要的Pod,或通过滚动释放调度到其他节点。
      • 根据自身业务情况,调整Pod的资源配置,设置容器CPU和内存资源上下限。
      • 集群节点资源扩容升配,或添加新的节点。
  • 该Pod使用了hostPort

    如果您使用了hostPort,那么Deployment或ReplicationController中Replicas值不能超过集群中的节点数,因为每个实例的任意端口只有一个。如果该端口被其他应用占用,将导致Pod调度失败。因此建议您不要使用hostPort,您可以使用Service访问Pod。

  • 污点和容忍

    当您在Pod的事件中看到TaintsTolerations时,说明是由于污点导致,您可以删除污点或者给Pod设置容忍,具体情况需要具体处理,如若当节点异常,已经出现不可调度污点情况,需要紧急处理。

Pod状态为Init:N/M(Init:Error和Init:CrashLoopBackOff)

问题原因

  • 若Pod停留在Init:N/M状态,说明该Pod包含M个Init容器,其中N个已经启动完成,但仍有M-N个Init容器未启动成功。
  • 若Pod停留在Init:Error状态,说明Pod中的Init容器启动失败。
  • 若Pod停留在Init:CrashLoopBackOff状态,说明Pod中的Init容器启动失败并处于反复重启状态。

问题现象

  • Pod的状态为Init:N/M。
  • Pod的状态为Init:Error。
  • Pod的状态为Init:CrashLoopBackOff。

解决方案

  1. 查看Pod的事件,确认当前Pod中未启动的Init容器是否存在异常。具体操作,请参见检查Pod的详情及事件
  2. 查看Pod中未启动的Init容器的日志,通过日志内容排查问题。具体操作,请参见检查Pod的容器日志
  3. 查看Pod的配置,确认未启动的Init容器配置是否正常。

Pod状态为ImagePullBackOff

问题原因

若Pod停留在ImagePullBackOff状态,说明此Pod已被调度到某个节点,但拉取镜像失败。

问题现象

Pod的状态为ImagePullBackOff。

解决方案

通过查看该Pod的事件描述,查看具体拉取失败的镜像名称。

  1. 确认容器镜像名称是否正确。

  2. 登录到Pod所在的节点,执行docker pull [$Image] ctr image pull [$Image]命令,查看是否能正常下载容器镜像。

    说明

    [$Image]为容器镜像的名称。

    • 若镜像拉取失败,请排查私有镜像仓库服务状态及网络连通状态,排查是否缺失镜像等。

Pod状态为CrashLoopBackOff

问题原因

若Pod停留在CrashLoopBackOff状态,说明容器中应用程序有问题。

问题现象

Pod的状态为CrashLoopBackOff。

解决方案

  1. 查看Pod的事件,确认当前Pod是否存在异常。具体操作,请参见检查Pod的详情及事件
  2. 查看Pod的日志,通过日志内容排查问题。具体操作,请参见检查Pod的容器日志
  3. 查看Pod的配置,确认容器中的健康检查配置是否正常有效。具体操作,请参见检查Pod的配置。。关于Pod健康检查的更多信息,请联系该业务组一并分析,参见K8S/K3S配置存活、就绪和启动探测器配置说明。

Pod状态为Completed

问题原因

若Pod出现Completed状态,说明容器中的启动命令已执行完毕,容器中的所有进程都已退出。

问题现象

Pod的状态为Completed,确认该资源编排,正常情况可以忽略。

解决方案

  1. 查看Pod的配置,确定Pod中容器的启动命令。具体操作,请参见检查Pod的配置
  2. 查看Pod的日志,通过日志内容排查问题。具体操作,检查Pod的容器日志

Pod状态为Running但没正常工作

问题原因

部署使用的YAML文件有问题。

问题现象

Pod状态为Running但没正常工作。

解决方案

  1. 查看Pod的配置,确定Pod中容器的配置是否符合预期。具体操作,请参见检查Pod的配置

  2. 使用以下方法,排查环境变量中的某一个Key是否存在拼写错误。

    以command拼写成commnd为例,说明拼写问题排查方法。

    说明

    创建Pod时,环境变量中的某一个Key拼写错误的问题会被集群忽略,如Command拼写为Commnd,您仍能够使用该YAML文件创建资源。但容器运行时,不会执行有拼写问题的YAML文件,而是执行镜像中的默认命令。

    kubectl -n $namespace get po $PodName -o yaml >XXX.yaml # 保存该资源编排配置
    1. 在执行kubectl apply -f命令前为其添加--validate,然后执行kubectl apply --validate -f XXX.yaml 命令。

      如果您将command拼写成commnd,将看到错误信息XXX] unknown field: commnd XXX] this may be a false alarm, see https://gXXXb.XXX/6842pods/test

    2. 执行以下命令,将输出结果的pod.yaml文件与您创建Pod使用的文件进行对比。

      kubectl -n $namespace get pods $PodName -o yaml > pod.yaml

      说明

      [$PodName]为异常Pod的名称,您可以通过kubectl get pods命令查看。

      • pod.yaml文件比您创建Pod所使用的文件多几行,说明已创建的Pod符合预期。
      • 如果您创建Pod所使用文件里的代码行在pod.yaml文件中没有,说明您创建Pod使用的文件存在拼写问题。
  3. 查看Pod的日志,通过日志内容排查问题。具体操作,检查Pod的容器日志

  4. 可通过终端进入容器查看容器内的本地文件是否符合预期。具体操作,请参见使用终端进入容器常规诊断

Pod状态为Terminating

问题原因

若Pod的状态为Terminating,说明此Pod正处于关闭状态。

问题现象

Pod状态为Terminating。

解决方案

Pod停留在Terminating状态一段时间后会被自动删除。若Pod一直停留在Terminating状态,可执行如下命令强制删除:

kubectl delete pod $PodName -n $namespace --grace-period=0 --force

Pod状态为Evicted

问题原因

当节点的内存、磁盘空间、文件系统的inode和操作系统可分配的PID等资源中的一个或者多个达到特定的消耗水平,就会引发kubelet主动地驱逐节点上一个或者多个Pod,以回收节点资源。

问题现象

Pod的状态为Evicted。

解决方案

  1. 执行以下命令,查看Pod的status.message字段,来确定Pod被驱逐的原因。

    kubectl  get pod $PodName -o yaml -n $namespace

    预期输出:

    status:
    message: 'Pod the node had condition: [DiskPressure].'
    phase: Failed
    reason: Evicted

    通过上述status.message字段,可以判断当前Pod是因为节点磁盘压力 (DiskPressure) 被驱逐。

    说明

    注意这里仅以磁盘压力驱逐为例,其它例如内存压力(MemoryPressure)和PID压力(PIDPressure)等也会以类似的方式展示。

  2. 执行以下命令,删除被驱逐的Pod。

    kubectl get pods -n [$namespace]| grep Evicted | awk '{print $1}' | xargs kubectl delete pod -n [$namespace]

以下汇总如何避免Pod被驱逐的方法:

  • 内存压力:
    • 根据自身业务情况,调整Pod的资源配置,设置容器的CPU和内存资源上下限。
    • 为节点进行扩容升配。
  • 磁盘压力:
    • 定时清理节点上的业务Pod日志,避免磁盘被日志打满。
    • 为节点进行磁盘扩容。
  • PID压力:根据自身业务情况,调整Pod的资源配置。

Pod OOM异常问题处理

问题原因

当集群中的容器使用超过其限制的内存,容器可能会被终止,触发OOM(Out Of Memory)事件,导致容器异常退出。关于OOM事件,调整Pod的资源配置,设置容器的内存资源上下限,该类场景无法一概而论,需要该业务模块进一步定位分析,避免业务内存使用不佳,泄漏等问题。

问题现象

  • 若被终止的进程为容器的阻塞进程,可能导致容器异常重启。
  • 若出现OOM异常问题,请参见检查Pod的详情及事件
  • 若有配置集群异常报警服务,则OOM事件出现时可收到相关报警。

解决方案

  1. 查看发生OOM异常的Pod所在的节点。

    • 命令行方式查看

      执行以下命令,查看容器信息。

      kubectl  get pod $PodName -o wide -n $namespace

      预期输出:

      NAME        READY   STATUS    RESTARTS   AGE   IP            NODE
      pod_name 1/1 Running 0 12h 192.20.6.52 ones-001
    • Grafana监控面板查看:查看Pod详情下的节点信息,Grafana检查节点的监控 通过kubectl查看 请参见检查Pod的详情及事件

  2. 登录Pod所在的Node,查看内核日志/var/log/message。在日志中查询关键字out of memory,确认具体被OOM终止的进程。如果该进程是容器的阻塞进程,OOM终止后容器会重启。

  3. 通过Grafana监控面板,观测Pod内存监控查看内存增长曲线,确定异常出现时间。

  4. 根据监控、内存增长时间点、日志、进程名等信息,排查Pod内对应进程是否存在内存泄漏。

    • 若OOM是进程内存泄漏导致,请联系业务模块自行排查泄露原因。
    • 若进程运行状态正常,则根据实际运行需要,适当增大Pod的内存限制,建议Pod的内存实际使用量不超过内存限制值的80%。