我如何排查 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,因为 hostIP、hostPort 和 protocol 组合必须是唯一的。
- 如果指定了 hostPort,则安排与 Worker 节点数量相同的 Pod。
注意:将 Pod 绑定到 hostPort 时,可以安排 Pod 的位置数量有限。
以下示例显示了处于 Pending(待处理)状态的 frontend-port-77f67cff67-2bv7w 的 describe 命令的输出。由于请求的主机端口不适用于集群中的 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]]
$ 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 状态。