k8s pod异常状态分析

pod状态

1. 前置检查

在排查异常状态的pod错误之前,可以先检查一下node状态,执行kubectl get node查看是否所有的node状态都正常。

2. pod状态为CrashLoopBackOff

如果pod状态为CrashLoopBackOff状态,查看pod日志来定位原因,或者describe pod看一下。

3. pod状态为Pending

pod状态为Pending状态,说明调度失败,通常跟污点、标签、cpu、内存、磁盘等资源相关。

可以通过kubectl describe pod -n {NAMESPACE} {POD_NAME},可以在最后的Event部分找到原因。

4. pod状态为Init:0/1

有些pod会有Init Containers,这些container是在pod的containers执行之前先执行。如果Init Container出现未执行完成的情况,此时pod处于Init状态。

通过kubectl get pod -n {NAMESPACE} {POD_NAME} -o yaml 找到pod的Init Containers,并找到其中的name字段。执行kubectl logs -n {NAMESPACE} {POD_NAME} -c {INIT_CONTAINER_NAME}可以查看Init Container的日志来分析原因。

5. pod状态为Terminating

pod处于此种状态的原因大致可分为: 1、pod或其控制器被删除。 解决方法:查看pod控制器类型和控制器名称,查看其控制器是否正常。如果正常pod将会被重建,如果pod没有被重建,查看controller-manager是否正常。 2、pod所在节点状态NotReady导致。 解决方法:检查该节点的网络,cpu,内存,磁盘空间等资源是否正常。检查该节点的kubelet、docker服务是否正常。检查该节点的网络插件pod是否正常。

最常见的pod处于Terminating状态的解决办法为强制删除 kubectl delete pods -n ${namespace} ${name} --grace-period=0 --force

6. pod状态为Evicted

pod处于Evicted的原因大致可分为: 1、kubelet服务启动时存在驱逐限制当节点资源可用量达到指定阈值(magefs.available<15%,memory.available<300Mi,nodefs.available<10%,nodefs.inodesFree<5%) 会优先驱逐Qos级别低的pod以保障Qos级别高的pod可用。 解决方法:增加节点资源或将被驱逐的pod迁移到其他空闲资源充足的节点上。 2、pod所在节点上被打上了NoExecute的污点,此种污点会将该节点上无法容忍此污点的pod进行驱逐。 解决方法:查看该节点上的NoExecute污点是否必要。或者pod是否可以迁移到其他节点。 3、pod所在的节点为NotReady状态

通常可以通过kubectl describe pods ${pod} -n ${namespace}的底部的Events信息来找到一些问题的原因。例如下面例子中可以看到DiskPressure信息,说明跟磁盘相关。

1
2
3
4
5
Events:
  Type     Reason     Age        From                 Message
  ----     ------     ----       ----                 -------
  Warning  Evicted    61s        kubelet, acs.deploy  The node had condition: [DiskPressure].
  Normal   Scheduled  <invalid>  default-scheduler    Successfully assigned ark-system/bridge-console-bridge-console-554d57bb87-nh2vd to acs.deploy

或者根据pod的Message字段来找到原因

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Name:           tiller-deploy-7f6456894f-22vgr
Namespace:      kube-system
Priority:       0
Node:           a36e04001.cloud.e04.amtest17/
Start Time:     Mon, 08 Jun 2020 12:17:26 +0800
Labels:         app=helm
                name=tiller
                pod-template-hash=7f6456894f
Annotations:    <none>
Status:         Failed
Reason:         Evicted
Message:        Pod The node had condition: [DiskPressure].

由于pod驱逐的原因排查跟时间点相关,需要根据pod被驱逐的时间来分析当时的状态。 4、批量删除状态Evicted的pod,此操作会删除集群里面所有状态为Evicted的pod

1
2
ns=`kubectl get ns | awk 'NR>1 {print $1}'`
for i in $ns;do  kubectl get pods -n $i  | grep Evicted| awk '{print $1}' | xargs  kubectl delete pods -n $i ;done

7. pod状态为Unknown

通常该状态为pod对应节点的为NotReady,通过查看 kubectl get node 来查看node是否为NotReady。

8. pod为running,但是Not Ready状态

1
argo-ui-56f4d67b69-8gshr   0/1     Running     0          10h

类似上面这种状态,此时说明pod的readiness健康检查没过导致的,需要先从pod的健康检查本身来排查问题。可以通过 kubectl get pods -n ${namespace} ${name} -o yaml 找到pod的健康检查部分,关键字为readiness,然后进入pod中执行对应的健康检查命令来测试健康检查的准确性。

例如readiness的配置如下,需要进入pod中执行curl http://127.0.0.1/api/status,也可以在pod对应的node节点上执行curl [http://${pod_ip}/api/status](http://127.0.0.1/api/status)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    livenessProbe:
      failureThreshold: 3
      httpGet:
        path: /api/status
        port: http
        scheme: HTTP
      initialDelaySeconds: 120
      periodSeconds: 10
      successThreshold: 1
      timeoutSeconds: 1

9. pod为ContainerCreating状态

通过kubectl describe pods -n ${namespace} ${name}的Events部分来分析原因,可能的原因如下:

  • 网络分配ip地址失败

10. Init:CrashLoopBackOff

  1. 通过kubectl get pod -n {NAMESPACE} {POD_NAME} -o yaml 找到pod的Init Containers,并找到其中的name字段。
  2. 执行kubectl logs -n {NAMESPACE} {POD_NAME} -c {INIT_CONTAINER_NAME}可以查看Init Container的日志来分析原因。

11. PodInitializing

需要查看initContainer的日志

12. MatchNodeSelector

查看pod的status信息可以看到如下信息:

1
2
3
4
5
status:
  message: Pod Predicate MatchNodeSelector failed
  phase: Failed
  reason: MatchNodeSelector
  startTime: "2022-03-15T05:07:57Z"

说明该pod没有调度成功,在predicate的MatchNodeSelector阶段失败了,没有匹配上node节点。

在k8s 1.21之前的版本,存在bug,节点重启后可能遇到过问题,将pod delete后重新调度可以解决。https://github.com/kubernetes/kubernetes/issues/92067

参考