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

上次更新日期:2021 年 12 月 8 日

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

解决方法

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

了解您的 Pod 的状态

1.    要获取 Pod 的状态,请运行以下命令:

$ kubectl get pod

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

$ kubectl describe pod YOUR_POD_NAME

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

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

Pod 处于 Pending 状态

无法将处于 Pending 状态的 Pod 安排到节点上。发生这种情况可能是因为资源不足或使用了 HostPort。有关详细信息,请参阅 Kubernetes 文档中的 Pod 阶段

如果 Worker 节点上的可用资源不足,请考虑删除不必要的 Pod。您也可以在 Worker 节点上添加更多资源。您可以使用 Kubernetes Cluster Autoscaler 在集群中出现资源不足情况时自动扩展您的 Worker 节点组。

CPU 不足

$ kubectl describe pod frontend-cpu                               
Name:         frontend-cpu
Namespace:    default
Priority:     0
Node:         <none>
Labels:       <none>
Annotations:  kubernetes.io/psp: eks.privileged
Status:       Pending
...
Events:
  Type     Reason            Age                 From               Message
  ----     ------            ----                ----               -------
  Warning  FailedScheduling  22s (x14 over 13m)  default-scheduler  0/3 nodes are available: 3 Insufficient cpu.

内存不足

$ kubectl describe pod frontend-memory
Name:         frontend-memory
Namespace:    default
Priority:     0
Node:         <none>
Labels:       <none>
Annotations:  kubernetes.io/psp: eks.privileged
Status:       Pending
...
Events:
  Type     Reason            Age                 From               Message
  ----     ------            ----                ----               -------
  Warning  FailedScheduling  80s (x14 over 15m)  default-scheduler  0/3 nodes are available: 3 Insufficient memory.

如果为 Pod 定义了 HostPort,请遵循以下最佳实践:

  • 除非有必要,否则请勿指定 hostPort,因为 hostIPhostPortprotocol 组合必须是唯一的。
  • 如果指定了 hostPort,则安排与 Worker 节点数量相同的 Pod。

注意:将 Pod 绑定到 hostPort 时,可以安排 Pod 的位置数量有限。

以下示例显示了处于 Pending(待处理)状态的 frontend-port-77f67cff67-2bv7wdescribe 命令的输出。由于请求的主机端口不适用于集群中的 Worker 节点,因此未安排 Pod。

端口不可用

$ kubectl describe pod frontend-port-77f67cff67-2bv7w                                            
Name:           frontend-port-77f67cff67-2bv7w
Namespace:      default
Priority:       0
Node:           <none>
Labels:         app=frontend-port
                pod-template-hash=77f67cff67
Annotations:    kubernetes.io/psp: eks.privileged
Status:         Pending
IP:             
IPs:            <none>
Controlled By:  ReplicaSet/frontend-port-77f67cff67
Containers:
  app:
    Image:      nginx
    Port:       80/TCP
    Host Port:  80/TCP
...
Events:
  Type     Reason            Age                  From               Message
  ----     ------            ----                 ----               -------
  Warning  FailedScheduling  11s (x7 over 6m22s)  default-scheduler  0/3 nodes are available: 3 node(s) didn't have free ports for the requested pod ports.

如果由于节点存在 Pod 无法支持的污点而不能安排 Pod,则示例输出会类似于以下内容:

$ kubectl describe pod nginx                                                  
Name:         nginx
Namespace:    default
Priority:     0
Node:         <none>
Labels:       run=nginx
Annotations:  kubernetes.io/psp: eks.privileged
Status:       Pending
...
Events:
  Type     Reason            Age                  From               Message
  ----     ------            ----                 ----               -------
  Warning  FailedScheduling  8s (x10 over 9m22s)  default-scheduler  0/3 nodes are available: 3 node(s) had taint {key1: value1}, that the pod didn't tolerate.

您可以使用以下命令检查您的节点是否存在污点:

$ kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints             
NAME                                                TAINTS
ip-192-168-4-78.ap-southeast-2.compute.internal     [map[effect:NoSchedule key:key1 value:value1]]
ip-192-168-56-162.ap-southeast-2.compute.internal   [map[effect:NoSchedule key:key1 value:value1]]
ip-192-168-91-249.ap-southeast-2.compute.internal   [map[effect:NoSchedule key:key1 value:value1]]

如果希望保留节点污点,那么可以在 PodSpec 中为 Pod 指定容忍度。有关更多信息,请参阅 Kubernetes 文档中的概念部分。

– 或者 –

在污点值的末尾添加 -,来删除节点污点:

$ kubectl taint nodes NODE_Name key1=value1:NoSchedule-

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

您的容器处于 Waiting 状态

处于 Waiting 状态的容器已安排在 Worker 节点上(例如 EC2 实例),但无法在该节点上运行。

由于 Docker 镜像不正确或存储库名称不正确,您的容器能处于 Waiting(等待中)状态。或者,由于镜像不存在或您缺少权限,您的 Pod 可能处于 Waiting(等待中)状态。

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

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

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

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

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

2.    要确认镜像提取是可行的,并排除一般网络和存储库权限问题,请手动提取镜像。您必须使用 Docker 从 Amazon EKS Worker 节点提取镜像。例如:

$ 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 Jul 2021 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

如果您的容器在尝试上述步骤后仍处于 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 [-f] [-p] (POD | TYPE/NAME) [-c CONTAINER]

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

以下示例显示 Pod 处于 CrashLoopBackOff 状态,原因是应用程序在启动之后退出,请注意 State(状态)、Last State(最后状态)、Reason(原因)、Exit Code(退出代码)和 Restart Count(重新启动计数)以及 Events(事件)。

$ kubectl describe pod crash-app-b9cf4587-66ftw 
Name:         crash-app-b9cf4587-66ftw
Namespace:    default
Priority:     0
Node:         ip-192-168-91-249.ap-southeast-2.compute.internal/192.168.91.249
Start Time:   Tue, 12 Oct 2021 12:24:44 +1100
Labels:       app=crash-app
              pod-template-hash=b9cf4587
Annotations:  kubernetes.io/psp: eks.privileged
Status:       Running
IP:           192.168.82.93
IPs:
  IP:           192.168.82.93
Controlled By:  ReplicaSet/crash-app-b9cf4587
Containers:
  alpine:
    Container ID:   containerd://a36709d9520db92d7f6d9ee02ab80125a384fee178f003ee0b0fcfec303c2e58
    Image:          alpine
    Image ID:       docker.io/library/alpine@sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a
    Port:           <none>
    Host Port:      <none>
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Tue, 12 Oct 2021 12:26:21 +1100
      Finished:     Tue, 12 Oct 2021 12:26:21 +1100
    Ready:          False
    Restart Count:  4
    ...
Events:
  Type     Reason     Age                  From               Message
  ----     ------     ----                 ----               -------
  Normal   Scheduled  2m30s                default-scheduler  Successfully assigned default/crash-app-b9cf4587-66ftw to ip-192-168-91-249.ap-southeast-2.compute.internal
  Normal   Pulled     2m25s                kubelet            Successfully pulled image "alpine" in 5.121853269s
  Normal   Pulled     2m22s                kubelet            Successfully pulled image "alpine" in 1.894443044s
  Normal   Pulled     2m3s                 kubelet            Successfully pulled image "alpine" in 1.878057673s
  Normal   Created    97s (x4 over 2m25s)  kubelet            Created container alpine
  Normal   Started    97s (x4 over 2m25s)  kubelet            Started container alpine
  Normal   Pulled     97s                  kubelet            Successfully pulled image "alpine" in 1.872870869s
  Warning  BackOff    69s (x7 over 2m21s)  kubelet            Back-off restarting failed container
  Normal   Pulling    55s (x5 over 2m30s)  kubelet            Pulling image "alpine"
  Normal   Pulled     53s                  kubelet            Successfully pulled image "alpine" in 1.858871422s

Pod 的存活探针故障的示例:

$ kubectl describe pod nginx
Name:         nginx
Namespace:    default
Priority:     0
Node:         ip-192-168-91-249.ap-southeast-2.compute.internal/192.168.91.249
Start Time:   Tue, 12 Oct 2021 13:07:55 +1100
Labels:       app=nginx
Annotations:  kubernetes.io/psp: eks.privileged
Status:       Running
IP:           192.168.79.220
IPs:
  IP:  192.168.79.220
Containers:
  nginx:
    Container ID:   containerd://950740197c425fa281c205a527a11867301b8ec7a0f2a12f5f49d8687a0ee911
    Image:          nginx
    Image ID:       docker.io/library/nginx@sha256:06e4235e95299b1d6d595c5ef4c41a9b12641f6683136c18394b858967cd1506
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Tue, 12 Oct 2021 13:10:06 +1100
      Finished:     Tue, 12 Oct 2021 13:10:13 +1100
    Ready:          False
    Restart Count:  5
    Liveness:       http-get http://:8080/ delay=3s timeout=1s period=2s #success=1 #failure=3
    ...
Events:
  Type     Reason     Age                    From               Message
  ----     ------     ----                   ----               -------
  Normal   Scheduled  2m47s                  default-scheduler  Successfully assigned default/nginx to ip-192-168-91-249.ap-southeast-2.compute.internal
  Normal   Pulled     2m44s                  kubelet            Successfully pulled image "nginx" in 1.891238002s
  Normal   Pulled     2m35s                  kubelet            Successfully pulled image "nginx" in 1.878230117s
  Normal   Created    2m25s (x3 over 2m44s)  kubelet            Created container nginx
  Normal   Started    2m25s (x3 over 2m44s)  kubelet            Started container nginx
  Normal   Pulled     2m25s                  kubelet            Successfully pulled image "nginx" in 1.876232575s
  Warning  Unhealthy  2m17s (x9 over 2m41s)  kubelet            Liveness probe failed: Get "http://192.168.79.220:8080/": dial tcp 192.168.79.220:8080: connect: connection refused
  Normal   Killing    2m17s (x3 over 2m37s)  kubelet            Container nginx failed liveness probe, will be restarted
  Normal   Pulling    2m17s (x4 over 2m46s)  kubelet            Pulling image "nginx"

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

其他问题排查

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

1.    要确认 Worker 节点存在于集群中并且处于 Ready 状态,请运行以下命令:

$ kubectl get nodes

示例输出:

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

如果节点处于 NotReady(未准备)状态,请参阅如何将我的节点的状态从 NoReady(未准备)或 Unknown(未知)状态更改为 Ready(已准备)状态?如果无法加入集群,请参阅如何将 Worker 节点加入 Amazon EKS 集群?

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

$ kubectl version --short

示例输出:

Client Version: v1.21.2-eks-5047ed
Server Version: v1.21.2-eks-c0eccc

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

$ 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.21.2-eks-5047ed
ip-192-168-86-33.us-east-2.compute.internal   v1.21.2-eks-5047ed

4.    确认集群的 Kubernetes 服务器版本与可接受的版本倾斜中的 Worker 节点版本相匹配(从 Kubernetes 文档)。使用上述步骤 2 和 3 的输出作为此比较的基础。

重要提示:补丁版本可能不同(例如,对于集群,版本为 v1.21.x;对于 Worker 节点,版本为 v1.21.y)。

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

– 或者 –

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

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


这篇文章对您有帮助吗?


您是否需要账单或技术支持?