本页面可帮助您解决 Google Kubernetes Engine (GKE) 中出现 CrashLoopBackOff
事件的 Pod 相关问题。
本页面适用于希望找出导致容器崩溃的应用级问题(例如配置错误或与代码相关的 bug)的应用开发者。还适用于需要确定容器重启的平台级根本原因(例如资源耗尽、节点中断或活跃性探测配置错误)的平台管理员和运维人员。如需详细了解我们在 Trusted Cloud by S3NS 内容中提及的常见角色和示例任务,请参阅常见的 GKE Enterprise 用户角色和任务。
了解 CrashLoopBackOff
事件
当您的 Pod 陷入 CrashLoopBackOff
状态时,其中的某个容器会反复启动、崩溃或退出。此 CrashLoop 会触发 Kubernetes 尝试按照其 restartPolicy
重启容器。每次重启失败后,下次尝试之前的延迟时间会以指数方式增加(例如,10 秒、20 秒、40 秒),最长为 5 分钟。
虽然此事件表明您的容器中存在问题,但它也是一个有价值的诊断信号。CrashLoopBackOff
事件确认 Pod 创建的许多基础步骤(例如分配给节点和拉取容器映像)已完成。有了这些知识,您就可以专注于调查容器的应用或配置,而不是集群基础设施。
出现 CrashLoopBackOff
状态的原因是 Kubernetes(具体而言是 kubelet)根据 Pod 的重启政策处理容器终止的方式。
该周期通常遵循以下模式:
- 容器启动。
- 容器退出。
- kubelet 会观察已停止的容器,并根据 Pod 的
restartPolicy
重启该容器。 - 此循环会重复进行,容器会在指数退避延迟时间不断增加后重启。
Pod 的 restartPolicy
是实现此行为的关键。默认政策 Always
是导致此循环的最常见原因,因为即使容器成功退出,它也会在容器因任何原因退出时重启容器。OnFailure
政策不太可能导致循环,因为它仅在退出代码不为零时重启,而 Never
政策则完全避免了重启。
确定 CrashLoopBackOff
事件的症状
状态为 CrashLoopBackOff
的 Pod 是 CrashLoopBackOff
事件的主要指示。
不过,您可能会遇到一些不太明显的 CrashLoopBackOff
事件症状:
- 工作负载的运行状况良好的副本数量为零。
- 运行状况良好的副本数量急剧减少。
- 启用了 Pod 横向自动扩缩的工作负载扩缩缓慢或无法扩缩。
如果某个 system
工作负载(例如,日志记录或指标代理)的状态为 CrashLoopBackOff
,您可能还会注意到以下症状:
- 某些 GKE 指标未报告。
- 部分 GKE 信息中心和图表存在数据缺口。
- Pod 级网络连接问题。
如果您发现任何这些不太明显的症状,下一步应该是确认是否发生了 CrashLoopBackOff
事件。
确认 CrashLoopBackOff
事件
如需确认和调查 CrashLoopBackOff
事件,请从 Kubernetes 事件和容器的应用日志中收集证据。这两个来源提供了不同但互补的问题视图:
- Kubernetes 事件确认 Pod 正在崩溃。
- 容器的应用日志可以显示容器内进程失败的原因。
如需查看此信息,请选择以下其中一个选项:
控制台
如需查看 Kubernetes 事件和应用日志,请执行以下操作:
在 Trusted Cloud 控制台中,前往工作负载页面。
选择要调查的工作负载。概览或详细信息标签页会显示有关工作负载状态的更多信息。
在托管式 Pod 部分中,点击有问题的 Pod 的名称。
在“Pod 详细信息”页面上,调查以下内容:
- 如需查看 Kubernetes 事件的详细信息,请前往事件标签页。
- 如需查看容器的应用日志,请前往日志标签页。您可以在此页面上找到应用特定的错误消息或堆栈轨迹。
kubectl
如需查看 Kubernetes 事件和应用日志,请执行以下操作:
查看集群中正在运行的所有 Pod 的状态:
kubectl get pods
输出类似于以下内容:
NAME READY STATUS RESTARTS AGE POD_NAME 0/1 CrashLoopBackOff 23 8d
在输出中,查看以下列:
Ready
:查看有多少个容器已准备就绪。在此示例中,0/1
表示在预期的一个容器中,有零个容器处于就绪状态。此值是出现问题的明显迹象。Status
:查找状态为CrashLoopBackOff
的 Pod。Restarts
:值较高表示 Kubernetes 反复尝试启动容器但均失败。
确定失败的 Pod 后,描述该 Pod 以查看与该 Pod 状态相关的集群级事件:
kubectl describe pod POD_NAME -n NAMESPACE_NAME
替换以下内容:
POD_NAME
:您在kubectl get
命令的输出中确定的 Pod 的名称。NAMESPACE_NAME
:Pod 的命名空间。
输出类似于以下内容:
Containers: container-name: ... State: Waiting Reason: CrashLoopBackOff Last State: Terminated Reason: StartError Message: failed to create containerd task: failed to create shim task: context deadline exceeded: unknown Exit Code: 128 Started: Thu, 01 Jan 1970 00:00:00 +0000 Finished: Fri, 27 Jun 2025 16:20:03 +0000 Ready: False Restart Count: 3459 ... Conditions: Type Status PodReadyToStartContainers True Initialized True Ready False ContainersReady False PodScheduled True ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning Failed 12m (x216 over 25h) kubelet Error: context deadline exceeded Warning Failed 8m34s (x216 over 25h) kubelet Error: context deadline exceeded Warning BackOff 4m24s (x3134 over 25h) kubelet Back-off restarting failed container container-name in pod failing-pod(11111111-2222-3333-4444-555555555555)
在输出中,查看以下字段,了解是否存在
CrashLoopBackOff
事件的迹象:State
:容器的状态可能显示为Waiting
,并带有原因CrashLoopBackOff
。Last State
:之前终止的容器的状态。查找Terminated
状态,并查看退出代码,以确定是否存在崩溃(非零退出代码)或意外的成功退出(零退出代码)。Events
:集群本身采取的操作。查找有关容器启动的消息,然后查找活跃性探测失败或退避警告(例如Back-off restarting failed container
)。
如需详细了解 Pod 失败的原因,请查看其应用日志:
kubectl logs POD_NAME --previous
--previous
标志用于从之前终止的容器中检索日志,您可以在其中找到显示崩溃原因的特定堆栈轨迹或错误消息。当前容器可能太新,尚未记录任何日志。在输出中,查找会导致进程退出的特定于应用的错误。如果您使用的是自定义应用,编写该应用的开发者最能解读这些错误消息。如果您使用的是预构建的应用,这些应用通常会提供自己的调试说明。
使用崩溃循环的 Pod 交互式 playbook
确认 CrashLoopBackOff
事件后,请使用互动式 playbook 开始问题排查:
在 Trusted Cloud 控制台中,前往 GKE 互动式 Playbook - Pod 崩溃循环页面。
在集群列表中,选择您要排查问题的集群。如果您找不到集群,请在过滤条件字段中输入集群的名称。
在命名空间列表中,选择您要排查问题的命名空间。如果您找不到命名空间,请在过滤条件字段中输入命名空间。
请逐一查看以下各部分,以帮助您回答以下问题:
- 识别应用错误:哪些容器正在重启?
- 调查内存不足问题:是否存在与应用相关的配置错误或错误?
- 调查节点中断:是否因节点资源中断而导致容器重启?
- 调查活跃性探测故障问题:活跃性探测是否停止了您的容器?
- 关联更改事件:容器开始崩溃前后发生了什么?
可选:如需接收有关未来
CrashLoopBackOff
事件的通知,请在未来应对措施提示部分中选择创建提醒。
如果在使用了该 playbook 后问题仍然存在,请阅读本指南的其余部分,详细了解如何解决 CrashLoopBackOff
事件。
解决 CrashLoopBackOff
事件
以下部分将帮助您解决 CrashLoopBackOff
事件的最常见原因:
解决资源耗尽问题
CrashLoopBackOff
事件通常是由内存不足 (OOM) 问题引起的。如果 kubectl describe
输出显示以下内容,则可以确认这是原因所在:
Last State: Terminated
Reason: OOMKilled
如需了解如何诊断和解决 OOM 事件,请参阅排查 OOM 事件。
解决活跃性探测失败问题
活跃性探测是由 kubelet
执行的定期健康检查。如果探测失败的次数达到指定次数(默认次数为 3),kubelet
会重启容器。如果探测失败的情况持续存在,则可能会导致 CrashLoopBackOff
事件。
确认是否是活跃性探测导致的
如需确认活跃性探测失败是否会触发 CrashLoopBackOff
事件,请查询 kubelet
日志。这些日志通常包含明确的消息,表明探测失败和后续的重启。
在 Trusted Cloud 控制台中,前往 Logs Explorer 页面。
在查询窗格中,输入以下查询,过滤出任何与活跃性探测相关的重启:
resource.type="k8s_node" log_id("kubelet") jsonPayload.MESSAGE:"failed liveness probe, will be restarted" resource.labels.cluster_name="CLUSTER_NAME"
将
CLUSTER_NAME
替换为您的集群名称。查看输出。如果活跃性探测失败是
CrashLoopBackOff
事件导致的,则查询会返回类似于以下内容的日志消息:Container probe failed liveness probe, will be restarted
确认是活跃性探测导致 CrashLoopBackOff
事件后,请继续排查常见原因:
查看活跃性探测配置
配置错误的探测是导致 CrashLoopBackOff
事件的常见原因。检查探测清单中的以下设置:
- 验证探测类型:探测的配置必须与应用报告其健康状况的方式相符。例如,如果您的应用具有健康检查网址(例如
/healthz
),请使用httpGet
探测类型。如果其健康状况是通过运行命令来确定的,请使用exec
探测类型。例如,如需检查网络端口是否处于开放和监听状态,请使用tcpSocket
探测类型。 - 检查探测参数:
- 路径(适用于
httpGet
探测类型):确保 HTTP 路径正确,并且您的应用在该路径上提供健康检查。 - 端口:验证探测中配置的端口是否确实被应用使用和公开。
- 命令(适用于
exec
探测类型):确保命令存在于容器中,成功时返回的退出代码为0
,并在配置的timeoutSeconds
时间段内完成。 - 超时:确保
timeoutSeconds
值足以让应用做出响应,尤其是在启动期间或在负载下。 - 初始延迟时间 (
initialDelaySeconds
):检查初始延迟时间是否足以让应用在探测开始之前启动。
- 路径(适用于
如需了解详情,请参阅 Kubernetes 文档中的配置活跃性、就绪性和启动探测。
检查 CPU 和磁盘 I/O 利用率
资源争用会导致探测超时,这是活跃性探测失败的主要原因。如需查看资源使用情况是否是导致活跃性探测失败的原因,请尝试以下解决方案:
- 分析 CPU 使用情况:在探测间隔期间,监控受影响的容器及其运行所在节点的 CPU 利用率。需要跟踪的一项关键指标是
kubernetes.io/container/cpu/core_usage_time
。容器或节点上的 CPU 使用率过高可能会导致应用无法及时响应探测。 - 监控磁盘 I/O:检查节点的磁盘 I/O 指标。您可以使用
compute.googleapis.com/guest/disk/operation_time
指标来评估磁盘操作所花费的时间,这些操作按读取和写入进行分类。高磁盘 I/O 会显著减慢容器启动、应用初始化或整体应用性能,从而导致探测超时。
应对大规模部署
在同时部署大量 Pod(例如,通过 ArgoCD 等 CI/CD 工具)的场景中,新的 Pod 突然激增可能会使集群资源不堪重负,导致控制平面资源耗尽。这种资源不足会延迟应用启动,并可能导致活跃性探测在应用准备就绪之前反复失败。
如需解决此问题,请尝试以下解决方案:
- 实施分阶段部署:实施分批或在较长时间内部署 Pod 的策略,以避免节点资源过载。
- 重新配置或扩缩节点:如果无法进行分阶段部署,请考虑使用更快或更大的磁盘或永久性卷声明升级节点,以更好地应对不断增长的 I/O 需求。确保您的集群自动扩缩已正确配置。
- 等待并观察:在某些情况下,如果集群的资源不足情况不严重,工作负载可能会在严重延迟后(有时是 30 分钟或更长时间)最终部署。
解决暂时性错误
应用在启动或初始化期间可能会遇到暂时性错误或速度变慢,从而导致探测最初失败。如果应用最终恢复,请考虑增加活跃性探测清单中 initialDelaySeconds
或 failureThreshold
字段中定义的值。
解决探测资源消耗问题
在极少数情况下,活跃性探测的执行本身可能会消耗大量资源,从而触发资源限制,这可能会导致容器因 OOM 终止而被终止。确保探测命令是轻量级的。轻量级探测器更有可能快速可靠地执行,从而更准确地报告应用的真实健康状况。
解决应用配置错误问题
应用配置错误会导致许多 CrashLoopBackOff
事件。如需了解应用停止的原因,首先要检查退出代码。此代码用于确定问题排查路径:
- 退出代码
0
表示成功退出,这对于长时间运行的服务来说是意外的,并表明容器的入口点或应用设计存在问题。 - 非零退出代码表示应用崩溃,这会促使您将注意力转向配置错误、依赖项问题或代码中的 bug。
查找退出代码
如需查找应用的退出代码,请执行以下操作:
描述 Pod:
kubectl describe pod POD_NAME -n NAMESPACE_NAME
替换以下内容:
POD_NAME
:存在问题的 Pod 的名称。NAMESPACE_NAME
:Pod 的命名空间。
在输出中,查看相关容器的
Last State
部分下的Exit Code
字段。如果退出代码为0
,请参阅排查成功退出(退出代码 0)问题。如果退出代码是0
以外的数字,请参阅排查应用崩溃(非零退出代码)问题。
排查成功退出(退出代码 0
)
退出代码 0
通常表示容器的进程已成功完成。
虽然这是基于任务的 Job 所需的结果,但对于长时间运行的控制器(如 Deployment、StatefulSet 或 ReplicaSet),这可能表示存在问题。
这些控制器会努力确保 Pod 始终处于运行状态,因此会将任何退出都视为需要修正的故障。kubelet
通过遵循 Pod 的 restartPolicy
(默认为 Always
)来强制执行此行为,即使容器成功退出,也会重新启动。此操作会创建一个循环,最终触发 CrashLoopBackOff
状态。
意外成功退出的最常见原因如下:
容器命令未启动持久进程:容器仅在其初始进程(
command
或entrypoint
)运行时保持运行。如果此进程不是长时间运行的服务,则容器会在命令完成后立即退出。例如,["/bin/bash"]
等命令会立即退出,因为它们没有要运行的脚本。如需解决此问题,请确保容器的初始进程启动一个持续运行的进程。工作器应用在工作队列为空时退出:许多工作器应用都设计为检查队列中是否有任务,并在队列为空时彻底退出。如需解决此问题,您可以使用 Job 控制器(专为运行至完成的任务而设计),也可以修改应用的逻辑以作为持久性服务运行。
应用因缺少或无效的配置而退出:如果应用缺少必需的启动指令(例如命令行实参、环境变量或关键配置文件),则可能会立即退出。
如需解决此问题,请先检查应用的日志,看看是否存在与配置加载或缺少参数相关的特定错误消息。然后,验证以下内容:
- 应用实参或环境:确保所有必需的命令行实参和环境变量都已按应用预期正确传递到容器。
- 配置文件的存在:确认所有必需的配置文件都位于容器内的预期路径中。
- 配置文件内容:验证配置文件的内容和格式,以检查是否存在语法错误、缺少必需字段或值不正确的情况。
此问题的一个常见示例是,当应用配置为从装载了
ConfigMap
卷的文件中读取数据时。如果ConfigMap
未附加、为空或具有错误命名的键,则设计为在缺少配置时退出的应用可能会停止并返回退出代码0
。在这种情况下,请验证以下设置: - Pod 的卷定义中的ConfigMap
名称是否与其真实名称一致。 -ConfigMap
中的键与应用预期在已装载的卷中找到的文件名匹配。
排查应用崩溃问题(非零退出代码)
当容器以非零代码退出时,Kubernetes 会重启该容器。如果导致错误的根本问题持续存在,应用会再次崩溃,然后循环往复,最终达到 CrashLoopBackOff
状态。
非零退出代码清楚地表明应用本身发生了错误,这会引导您将调试工作重点放在应用的内部运作和环境上。以下问题通常会导致此终止:
配置错误:非零退出代码通常表示应用配置或运行环境存在问题。检查您的应用是否存在以下常见问题:
- 缺少配置文件:应用可能无法找到或访问所需的配置文件。
- 配置无效:配置文件可能包含语法错误、错误的值或不兼容的设置,导致应用崩溃。
- 权限问题:应用可能缺少读取或写入配置文件所需的权限。
- 环境变量:不正确或缺失的环境变量可能会导致应用出现故障或无法启动。
entrypoint
或command
无效:容器的entrypoint
或command
字段中指定的命令可能不正确。如果新部署的映像的可执行文件路径有误,或者容器映像中没有相应文件,则可能会出现此问题。此配置错误通常会导致128
退出代码。不受控制的映像更新(
:latest
标记):如果工作负载映像使用:latest
标记,新 Pod 可能会拉取引入了重大更改的更新映像版本。为确保一致性和可重现性,请始终在生产环境中使用特定的不可变映像标记(例如
v1.2.3
)或 SHA 摘要(例如sha256:45b23dee08...
)。这种做法有助于确保每次都提取完全相同的图片内容。
依赖项问题:如果应用无法连接到其依赖的其他服务,或者无法通过身份验证或没有足够的权限来访问这些服务,则可能会崩溃。
外部服务不可用:应用可能依赖于因网络连接问题或服务中断而无法访问的外部服务(例如数据库或 API)。如需排查此问题,请连接到 Pod。如需了解详情,请参阅 Kubernetes 文档中的调试正在运行的 Pod。
连接到 Pod 后,您可以运行命令来检查对文件、数据库的访问权限,或测试网络。例如,您可以使用
curl
等工具尝试访问服务的网址。此操作有助于您确定问题是由网络政策、DNS 还是服务本身引起的。身份验证失败:由于凭证不正确,应用可能无法通过外部服务进行身份验证。检查容器的日志中是否有
401 Unauthorized
(凭证无效)或403 Forbidden
(权限不足)等消息,这些消息通常表示 Pod 的服务账号缺少进行外部 Trusted Cloud by S3NS服务调用的必要 IAM 角色。如果您使用 GKE 工作负载身份联合,请验证主账号标识符是否具有执行相应任务所需的权限。如需详细了解如何使用 GKE 工作负载身份联合向主账号授予 IAM 角色,请参阅配置授权和主账号。 您还应验证 GKE 元数据服务器的资源使用量是否已超出其限制。
超时:应用在等待外部服务响应时可能会超时,从而导致崩溃。
应用特有的错误:如果配置和外部依赖项看起来正确无误,则错误可能出在应用的代码中。检查应用日志中是否存在以下常见的内部错误:
- 未处理的异常情况:应用日志可能包含堆栈轨迹或错误消息,表明存在未处理的异常情况或其他与代码相关的 bug。
- 死锁或活锁:应用可能陷入死锁,即多个进程相互等待对方完成。在这种情况下,应用可能不会退出,但会无限期停止响应。
- 端口冲突:如果应用尝试绑定到已被其他进程使用的端口,则可能无法启动。
- 不兼容的库:应用可能依赖于运行时环境中缺少或不兼容的库或依赖项。
如需查找根本原因,请检查容器的日志中是否存在特定错误消息或堆栈轨迹。此信息有助于您决定是否要修复应用代码、调整资源限制或更正环境的配置。如需详细了解日志,请参阅 GKE 日志简介。
后续步骤
如果您在文档中找不到问题的解决方案,请参阅获取支持以获取进一步的帮助,包括以下主题的建议:
- 请与 Cloud Customer Care 联系,以提交支持请求。
- 通过在 StackOverflow 上提问并使用
google-kubernetes-engine
标记搜索类似问题,从社区获得支持。您还可以加入#kubernetes-engine
Slack 频道,以获得更多社区支持。 - 使用公开问题跟踪器提交 bug 或功能请求。