k8s Pod的几种异常介绍
简介
在 Kubernetes 中,Pod 作为工作负载的运行载体,是最为核心的一个资源对象。Pod 具有复杂的生命周期,在其生命周期的每一个阶段,可能发生多种不同的异常情况。Kubernetes 作为一个复杂系统,异常诊断往往要求强大的知识和经验储备。结合实战经历以及 EDAS 用户真实场景的归纳,我们总结了 Kubernetes Pod 的 13 种常见异常场景,给出各个场景的常见错误状态,分析其原因和排查思路。
Pod 生命周期
在整个生命周期中,Pod 会出现 5 种阶段(Phase)。
- Pending:Pod 被 Kubernetes 创建出来后,起始于 Pending 阶段。在 Pending 阶段,Pod 将经过调度,被分配至目标节点开始拉取镜像、加载依赖项、创建容器。
- Running:当 Pod 所有容器都已被创建,且至少一个容器已经在运行中,Pod 将进入 Running 阶段。
- Succeeded:当 Pod 中的所有容器都执行完成后终止,并且不会再重启,Pod 将进入 Succeeded 阶段。
- Failed:若 Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止,也就是说容器以非 0 状态异常退出或被系统终止,Pod 将进入 Failed 阶段。
- Unkonwn:因为某些原因无法取得 Pod 状态,这种情况 Pod 将被置为 Unkonwn 状态。
一般来说,对于 Job 类型的负载,Pod 在成功执行完任务之后将会以 Succeeded 状态为终态。而对于 Deployment 等负载,一般期望 Pod 能够持续提供服务,直到 Pod 因删除消失,或者因异常退出/被系统终止而进入 Failed 阶段。
Pod 的 5 个阶段是 Pod 在其生命周期中所处位置的简单宏观概述,并不是对容器或 Pod 状态的综合汇总。Pod 有一些细分状态( PodConditions ),例如 Ready/NotReady、Initialized、 PodScheduled/Unschedulable 等。这些细分状态描述造成 Pod 所处阶段的具体成因是什么。比如,Pod 当前阶段是 Pending,对应的细分状态是 Unschedulable,这就意味着 Pod 调度出现了问题。
容器也有其生命周期状态(State):Waiting、Running 和 Terminated。并且也有其对应的状态原因(Reason),例如 ContainerCreating、Error、OOMKilled、CrashLoopBackOff、Completed 等。
而对于发生过重启或终止的容器,上一个状态(LastState)字段不仅包含状态原因,还包含上一次退出的状态码(Exit Code)。例如容器上一次退出状态码是 137,状态原因是 OOMKilled,说明容器是因为 OOM 被系统强行终止。在异常诊断过程中,容器的退出状态是至关重要的信息。
除了必要的集群和应用监控,一般还需要通过 kubectl 命令搜集异常状态信息。
1 2 3 4 5 6 7 8 9 10 11 | // 获取Pod当前对象描述文件 kubectl get po <podName> -n <namespace> -o yaml // 获取Pod信息和事件(Events) kubectl describe pod <podName> -n <namespace> // 获取Pod容器日志 kubectl logs <podName> <containerName> -n <namespace> // 在容器中执行命令 kubectl exec <podName> -n <namespace> -c <containerName> -- <CMD> <ARGS> |
Pod 异常场景
Pod 在其生命周期的许多时间点可能发生不同的异常,按照 Pod 容器是否运行为标志点,我们将异常场景大致分为两类:
- 在 Pod 进行调度并创建容器过程中发生异常,此时 Pod 将卡在 Pending 阶段。
- Pod 容器运行中发生异常,此时 Pod 按照具体场景处在不同阶段。
下文将对这具体的 13 种场景进行描述和分析。
调度失败
常见错误状态:Unschedulable
Pod 被创建后进入调度阶段,Kubernetes 调度器依据 Pod 声明的资源请求量和调度规则,为 Pod 挑选一个适合运行的节点。当集群节点均不满足 Pod 调度需求时,Pod 将会处于 Pending 状态。造成调度失败的典型原因如下:
1、节点资源不足
Kubernetes 将节点资源(CPU、内存、磁盘等)进行数值量化,定义出节点资源容量(Capacity)和节点资源可分配额(Allocatable)。资源容量是指 Kubelet 获取的计算节点当前的资源信息,而资源可分配额是 Pod 可用的资源。
Pod 容器有两种资源额度概念:请求值 Request 和限制值 Limit,容器至少能获取请求值大小、至多能获取限制值的资源量。Pod 的资源请求量是 Pod 中所有容器的资源请求之和,Pod 的资源限制量是 Pod 中所有容器的资源限制之和。Kubernetes 默认调度器按照较小的请求值作为调度依据,保障可调度节点的资源可分配额一定不小于 Pod 资源请求值。当集群没有一个节点满足 Pod 的资源请求量,则 Pod 将卡在 Pending 状态。
Pod 因为无法满足资源需求而被 Pending,可能是因为集群资源不足,需要进行扩容,也有可能是集群碎片导致。以一个典型场景为例,用户集群有 10 几个 4c8g 的节点,整个集群资源使用率在 60%左右,每个节点都有碎片,但因为碎片太小导致扩不出来一个 2c4g 的 Pod。一般来说,小节点集群会更容易产生资源碎片,而碎片资源无法供 Pod 调度使用。如果想最大限度地减少资源浪费,使用更大的节点可能会带来更好的结果。
2、超过 Namespace 资源配额