我如何排查 Amazon EKS 中的 Pod 状态问题?

上次更新时间:2020 年 2 月 13 日

在 Amazon Elastic Compute Cloud (Amazon EC2) 实例或托管节点组上运行的 Amazon Elastic Kubernetes Service (Amazon EKS) Pod 被卡住。如何使我的 Pod 处于运行状态?

解决方法

重要提示:以下步骤仅适用于在 Amazon EC2 实例或托管节点组上启动的 Pod。这些步骤不适用于在 AWS Fargate 上启动的 Pod。

了解您的 Pod 的状态

1.    要从 Pod 的事件历史记录中获取信息,请运行以下命令:

$ kubectl describe pod YOUR_POD_NAME

注意:以下步骤中涉及的示例命令位于默认命名空间中。对于其他命名空间,请在命令中附加 -n YOURNAMESPACE

2.    根据您的 Pod 状态,完成以下其中一个部分的所有步骤:Pod 处于 Pending 状态Pod 处于 Waiting 状态,或者 Pod 处于 CrashLoopBackOff 状态

Pod 处于 Pending 状态

无法将处于 Pending 状态的 Pod 安排到节点上。

由于可用工作线程节点上的资源不足,或者您已在 Pod 上定义了占用的 hostPort,所以 Pod 可能处于 Pending 状态。

如果可用工作线程节点上的资源不足,请删除不必要的 Pod,或添加更多工作线程节点。例如,您的工作线程节点可能已耗尽 CPU 和内存。如果这个问题反复出现,您可以使用 Kubernetes Cluster Autoscaler 在集群中的资源不足时自动扩展您的工作线程节点组。

如果要为 Pod 定义 hostPort,请考虑以下事项:

(A) 将 Pod 绑定到 hostPort 时,可以安排 Pod 的位置数量有限。
(b) 除非有必要,否则请勿指定 hostPort,因为 hostIPhostPortprotocol 组合必须是唯一的。
(C) 如果必须指定 hostPort,则安排与工作线程节点数量相同的 Pod。

以下示例显示了处于 Pending 状态的 my-nginx-12345abc6d-7e8fgdescribe 命令的输出。由于资源限制,未安排 Pod。

$ kubectl describe pod my-nginx-86459cfc9f-2j5bq

Name:               my-nginx-12345abc6d-7e8fg
Namespace:          default
Priority:           0
PriorityClassName:  
Node:               
Labels:             pod-template-hash=86459cfc9f
                    run=my-nginx
Annotations:        kubernetes.io/psp: eks.privileged
Status:             Pending
...
Events:
  Type     Reason            Age                 From               Message
  ----     ------            ----                ----               -------
  Warning  FailedScheduling  7s (x6 over 5m58s)  default-scheduler  0/2 nodes are available: 1 Insufficient pods, 1 node(s) had taints that the pod didn't tolerate.

如果您的 Pod 在尝试上述步骤后仍处于 Pending 状态,请完成其他问题排查部分中的步骤。

Pod 处于 Waiting 状态

处于 Waiting 状态的 Pod 已安排在工作线程节点上(例如,Amazon EC2 实例),但无法在该节点上运行。

由于 Docker 镜像或存储库名称不正确、缺少权限或镜像不存在等原因,您的 Pod 可能处于 Waiting 状态。

如果您的 Docker 镜像或存储库名称不正确,请完成以下操作:

1.    登录 Docker Hub、Amazon Elastic Container Registry (Amazon ECR) 或其他容器镜像存储库,确保镜像和存储库名称正确无误。

2.    将存储库或存储库中的镜像与在 Pod 规范中指定的存储库或镜像名称进行比较。

如果镜像不存在或您缺少权限,请完成以下操作:

1.    验证指定的镜像在存储库中是否可用,以及是否配置了正确的权限以允许提取镜像。

2.    要确认镜像提取是可行的,并排除一般网络和存储库权限问题,请使用 Docker 从 Amazon EKS 工作线程节点手动提取镜像:

$ docker pull yourImageURI:yourImageTag

3.    要验证镜像是否存在,请检查镜像和标签是否都存在于 Docker Hub 或 Amazon ECR 中。

注意:如果您使用的是 Amazon ECR,请验证存储库策略是否允许为 NodeInstanceRole 提取镜像。或者,验证 AmazonEC2ContainerRegistryReadOnly 角色是否已附加到策略中。

以下示例显示了由于镜像提取错误,容器处于 Waiting 状态的 Pod 处于 Pending 状态:

$ kubectl describe po web-test

Name:               web-test
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               ip-192-168-6-51.us-east-2.compute.internal/192.168.6.51
Start Time:         Wed, 22 Jan 2020 08:18:16 +0200
Labels:             app=web-test
Annotations:        kubectl.kubernetes.io/last-applied-configuration:
                      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"app":"web-test"},"name":"web-test","namespace":"default"},"spec":{...
                    kubernetes.io/psp: eks.privileged
Status:             Pending
IP:                 192.168.1.143
Containers:
  web-test:
    Container ID:   
    Image:          somerandomnonexistentimage
    Image ID:       
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Waiting
      Reason:       ErrImagePull
...
Events:
  Type     Reason            Age                 From                                                 Message
  ----     ------            ----                ----                                                 -------
  Normal   Scheduled         66s                 default-scheduler                                    Successfully assigned default/web-test to ip-192-168-6-51.us-east-2.compute.internal
  Normal   Pulling           14s (x3 over 65s)   kubelet, ip-192-168-6-51.us-east-2.compute.internal  Pulling image "somerandomnonexistentimage"
  Warning  Failed            14s (x3 over 55s)   kubelet, ip-192-168-6-51.us-east-2.compute.internal  Failed to pull image "somerandomnonexistentimage": rpc error: code = Unknown desc = Error response from daemon: pull access denied for somerandomnonexistentimage, repository does not exist or may require 'docker login'
  Warning  Failed            14s (x3 over 55s)   kubelet, ip-192-168-6-51.us-east-2.compute.internal  Error: ErrImagePull

如果您的 Pod 在尝试上述步骤后仍处于 Waiting 状态,请完成其他问题排查部分中的步骤。

您的 Pod 处于 CrashLoopBackOff 状态

卡在 CrashLoopBackOff 状态中的 Pod 处于启动、崩溃、重新启动,然后再次崩溃的循环中。

如果您收到“Back-Off restarting failed container”输出消息,则您的容器可能会在 Kubernetes 启动该容器后很快退出。

要在当前 Pod 的日志中查找错误,请运行以下命令:

$ kubectl logs YOUR_POD_NAME

要在先前崩溃的 Pod 的日志中查找错误,请运行以下命令:

$ kubectl logs --previous YOUR-POD_NAME

注意:对于多容器 Pod,可以在末尾追加容器名称。例如:

$ kubectl logs POD_NAME CONTAINER_NAME

如果存活探针未返回成功状态,请验证是否为应用程序配置了正确的存活探针。有关更多信息,请参阅配置探针

以下示例显示了处于 CrashLoopBackOff 状态的 Pod,因为应用程序在启动后退出:

$ kubectl describe po crash-app-6847947bf8-28rq6

Name:               crash-app-6847947bf8-28rq6
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               ip-192-168-6-51.us-east-2.compute.internal/192.168.6.51
Start Time:         Wed, 22 Jan 2020 08:42:20 +0200
Labels:             pod-template-hash=6847947bf8
                    run=crash-app
Annotations:        kubernetes.io/psp: eks.privileged
Status:             Running
IP:                 192.168.29.73
Controlled By:      ReplicaSet/crash-app-6847947bf8
Containers:
  main:
    Container ID:  docker://6aecdce22adf08de2dbcd48f5d3d8d4f00f8e86bddca03384e482e71b3c20442
    Image:         alpine
    Image ID:      docker-pullable://alpine@sha256:ab00606a42621fb68f2ed6ad3c88be54397f981a7b70a79db3d1172b11c4367d
    Port:          80/TCP
    Host Port:     0/TCP
    Command:
      /bin/sleep
      1
    State:          Waiting
      Reason:       CrashLoopBackOff
...
Events:
  Type     Reason     Age                From                                                 Message
  ----     ------     ----               ----                                                 -------
  Normal   Scheduled  47s                default-scheduler                                    Successfully assigned default/crash-app-6847947bf8-28rq6 to ip-192-168-6-51.us-east-2.compute.internal
  Normal   Pulling    28s (x3 over 46s)  kubelet, ip-192-168-6-51.us-east-2.compute.internal  Pulling image "alpine"
  Normal   Pulled     28s (x3 over 46s)  kubelet, ip-192-168-6-51.us-east-2.compute.internal  Successfully pulled image "alpine"
  Normal   Created    28s (x3 over 45s)  kubelet, ip-192-168-6-51.us-east-2.compute.internal  Created container main
  Normal   Started    28s (x3 over 45s)  kubelet, ip-192-168-6-51.us-east-2.compute.internal  Started container main
  Warning  BackOff    12s (x4 over 42s)  kubelet, ip-192-168-6-51.us-east-2.compute.internal  Back-off restarting failed container

如果您的 Pod 在尝试上述步骤后仍处于 CrashLoopBackOff 状态,请完成其他问题排查部分中的步骤。

其他问题排查方法

如果您的 Pod 在完成上述部分中的步骤后仍卡滞,请尝试以下步骤:

1.    要确认工作线程节点存在于集群中并且处于 Ready 状态(允许在集群上安排 Pod),请运行以下命令:

$ kubectl get nodes

输出应类似于以下内容:

NAME                                          STATUS   ROLES    AGE   VERSION
ip-192-168-6-51.us-east-2.compute.internal    Ready    <none>   25d   v1.14.6-eks-5047ed
ip-192-168-86-33.us-east-2.compute.internal   Ready    <none>   25d   v1.14.6-eks-5047ed

如果节点不在集群中,则添加工作线程节点

如果节点处于 NotReady 状态或无法加入集群,请参阅如何将我的节点的状态从 NotReady 或 Unknown 状态更改为 Ready 状态?

2.    要检查 Kubernetes 集群的版本,请运行以下命令:

$ kubectl version --short

输出应类似于以下内容:

Client Version: v1.14.6-eks-5047ed
Server Version: v1.14.9-eks-c0eccc

3.    要检查 Kubernetes 工作线程节点的版本,请运行以下命令:

$ kubectl get node -o custom-columns=NAME:.metadata.name,VERSION:.status.nodeInfo.kubeletVersion

输出应类似于以下内容:

NAME                                          VERSION
ip-192-168-6-51.us-east-2.compute.internal    v1.14.6-eks-5047ed
ip-192-168-86-33.us-east-2.compute.internal   v1.14.6-eks-5047ed

4.    根据步骤 2 和 3 的输出,确认集群的 Kubernetes 服务器版本与可接受的版本倾斜中的工作线程节点版本相匹配。

重要提示:修补程序版本可能不同(例如,对于集群,版本为 v1.14.x;对于工作线程节点,版本为 v1.14.y)。

如果集群和工作线程节点版本不兼容,则使用 eksctl(请参阅 eksctl 选项卡)或 AWS CloudFormation(请参阅自行管理的节点选项卡)创建新节点组

--或者--

使用兼容的 Kubernetes 版本创建新的托管节点组(Kubernetes:v1.14,平台:eks.3 及更高版本)。然后,删除带有不兼容 Kubernetes 版本的节点组。

5.    要确认 Kubernetes 控制平面可以与工作线程节点通信,请根据 Amazon EKS 安全组注意事项中的建议规则验证防火墙规则,然后验证节点是否处于 Ready 状态。


这篇文章对您有帮助吗?

我们可以改进什么?


需要更多帮助?