13种pod的状态

13种pod的状态

生命周期

  • Pending:Pod被创建后进入调度阶段,k8s调度器依据pod声明的资源请求量和调度规则,为pod挑选一个适合运行的节点。当集群节点不满足pod调度需求时,pod将会处于pending状态。
  • Running:Pod被调度到节点上,k8s将pod调度到节点上后,进入running状态。
  • Succeeded:Pod运行成功,Pod中的所有容器都退出,且退出码为0。
  • Failed:Pod运行失败,Pod中的所有容器都退出,且退出码不为0。或被系统终止,pod将进入failed状态。
  • Unknown:Pod运行异常,因为某些原因无法取得pod状态,Pod处于unknown状态。

调度失败

常见错误状态(Unschedulable)

pod被创建后进入调度阶段,k8s调度器依据pod声明的资源请求量和调度规则,为pod挑选一个适合运行的节点。当集群节点不满足pod调度需求时,pod将会处于pending状态。造成调度失败的典型原因有:

  • 节点资源不足

k8s将节点资源(cpu,内存,磁盘等)进行数字量化,定义出节点资源容量(capacity)和节点资源可分配额(allocatable)。资源容量是指kubelet获取的计算节点当前的资源信息,而iyuan个分配额是pod的可用的资源。
pod容器有两种资源额度概念:

  • 请求值 (Request 容器至少能获得请求值大小)
  • 限制值 (Limit 容器至多能获得限制值大小)
    pod的资源请求量是pod中所有容器的资源请求之和
    pod的资源限制量是pod中所有容器的资源限制之和
    k8s默认调度器按照较小的请求值作为调度依据,保障可调度节点的资源可分配额一定不小于pod资源请求值。当集群没有一个节点满足pod的资源请求量,pod将会卡在pending状态。
    pod因为无法满足资源需求而被pending,可能是因为集群资源不足,需要进行扩容,也有可能是集群碎片化导致。
  • 超过Namespace资源配额

k8s用户可以通过资源配额对ns进行资源使用量限制,包括两个维度:

  • 限制某个对象类型(pod)可创建对象的总数
  • 限定某个对象类型可消耗的资源总数
    如果在创建或更新pod时申请的资源超过了资源配额,则pod将调度失败。此时需要检查ns资源配额状态,做出适当调整
  • 不满足nodeselector节点选择器

节点亲和性和反亲和性用于约束pod调度到哪些节点,而亲和性有细分为软亲和和硬亲和。对于软亲和规则,k8s调度器会尝试寻找满足对应规则的节点,如果找不到匹配的节点,调度器仍然会调度该pod。而当硬亲和规则不被满足时,pod将无法被调度,需要检查pod调度规则和目标节点状态,对调度规则或节点进行合理调整

  • 节点存在污点

k8s提供污点和容忍机制,用于避免pod被分配到不合适的节点上。家啊如节点上存在污点,而pod没有设置及相应的容忍,pod将不会调度到该节点。此时需要确认节点是否有携带污点的必要。如果不必要,移除污点,若pod可以分配到带有污点的节点,则可以给pod增加污点容忍

  • 没有可用的节点

节点可能会因为资源不足,网络不通,kubelet未就绪等原因导致不可用(notready)。
当集群中没有可调度的节点,也会导致pod卡在pending状态。此时需要查看节点状态,排查不可用节点问题并修复,或进行集群扩容

镜像拉取失败

常见错误状态(ImagePullBackOff)

pod进过调度后分配到目标节点,节点需要拉取pod所需的镜像为创建容器做准备。
拉取镜像错误的原因:

  • 镜像名字拼写错误或配置了错误的镜像
  • 私有仓库的免密配置错误
  • 网络不通
    • 集群通过公网访问镜像仓库,而镜像仓库未配置公网的访问策略。
    • 集群位于专有网络,需要为镜像服务配置专有网络的访问控制,才能建立集群节点与镜像服务之间的连接
    • 拉取海外镜像,需要配置镜像加速服务
  • 拉取镜像超时候
  • 同时拉取多个镜像,出发并行度控制

依赖项错误

常见状态(Error)

在pod启动之前,kubelt将尝试检查与其他k8s元素的所有依赖关系。主要存在的依赖项有三种:PersistentVolumeClaim、ServiceAccount和ConfigMap。当这些依赖项能被正确读取,但出现配置错误时,也会出现无法创建容器的情况。比如讲一个只读的持久化存储卷以可读写的形式挂载到容器,或者将存储卷到/proc等非法路径,也会导致容器创建失败。

容器创建失败

常见状态(Error)

pod容器创建过程中出现了错误。常见原因:

  • 违反集群的安全策略,比如违反了PodSecurityPolicy等
  • 容器无权操作集群内的资源,比如开启rbac后,需要为ServiceAccount配置角色绑定
  • 缺少启动命令,pod描述文件和镜像dockerfile中均未配置启动命令
  • 启动命令配置错误。pod配置文件可以通过command字段定义命令行,通过args字段给命令行定义参数。启动命令配置错误的情况非常多见,要格外注意命令及参数的格式。

初始化失败

常见错误状态(CrashLoopBackOff)

k8s提供init Container特性,用于在启动应用容器之前启动一个或多个初始化容器,完成应用程序所需的预置条件。初始化容器与应用容器本质上是一样的,但它们是仅运行一次就结束的任务,兵器必须在执行完成后,系统才能继续执行下一个容器。如果pod的init Container失败 将会block业务容器的启动。通过查看pod状态和事件定位到init Container故障后,需要查看init Container的日志,找出问题所在。

回调失败

常见错误状态(FailedPostStartHook|FailedPreStopHook)

k8s提供PostStartHook和PreStopHook,用于在pod启动和停止时执行回调操作。PostStartHook在pod启动后执行,PreStopHook在pod停止前执行。
PostStart在容器创建之后立即执行,但由于是异步执行,无法保证和容器启动命令的执行顺序相关联。PreStop在容器停止之前被同步阻塞调用,常用与在容器结束前优雅的释放资源。如果PostStart或者PreStop 回调程序执行失败,容器将被终止,按照重启策略决定是否重启。当出现回调失败,会出现FailedPostStartHook或FailedPreStopHook事件,进一步结合容器打出的日志进行故障排查

就绪探针失败

常见错误状态(容器全部启动,但是pod处于 notready 服务流量无法从service到pod)

k8s使用readiness probe来确定容器是否已经就绪可以接受流量。只有当pod中的容器都处于就绪状态时,k8s才认定该pod处于就绪状态,才会将服务流量转发到该容器。

一般就绪探针失败:

  • 容器内应用原因:健康检查多配置规则对应的端口或者脚本,无法成功探测,如容器内应用没正常启动等。
  • 探针配置不当:写错检查端口导致探测失败;检测间隔和失败阈值设置不合理,例如每次检查间隔1s,一次不通过即失败;启动延迟设置太短,例如应用正常启动要15s,而设置容器启动10s后启动探针。
  • 系统层问题:节点负载高,导致容器进程hang住
  • cpu资源不足:cpu资源限制值过低,导致容器进程相应慢

需要特别说明的是,对于微服务应用,服务的注册和发现由注册中心管理,流量不会经过Service,直接从上游Pod流到下游Pod。然而注册中心并没有如K8s就绪探针的检查机制,对于启动较慢的JAVA应用来说,服务注册成功后所需资源仍然可能在初始化中,导致出现上线后流量有损的情况。对于这一类场景,EDAS提供延迟注册和服务预热等解决方案,解决K8s微服务应用上线有损的问题

存活探针失败

常见错误状态(CrashLoopBackOff)

k8s使用liveness probe来确定容器是否正在运行。如果存活探测失败,则容器会被杀死,随之按照重启策略决定是否重启。存活探针失败的原因与就绪探针类似,然而存活探针失败后容器会被kill掉,拍错难度上升。

典型例子:
一个典型的用户场景是,用户在压测期间通过HPA弹性扩容出多个新Pod,然而新Pod一启动就被大流量阻塞,无法响应存活探针,导致Pod被kill。kill后又重启,重启完又挂掉,一直在Running和CrashLoopBackOff状态中振荡。微服务场景下可以使用延迟注册和服务预热等手段,避免瞬时流量打挂容器。如果是程序本身问题导致运行阻塞,建议先将Liveness探针移除,通过Pod启动后的监控和进程堆栈信息,找出流量涌入后进程阻塞的根因

容器退出

常见错误状态(CrashLoopBackOff)

容器退出分两种场景:

  • 启动后立即退出
    • 启动命令的路径未包含在环境变量path中
    • 启动命令引用了不存在的文件或目录
    • 启动命令执行失败,可能因为运行环境缺少依赖,也可能是程序本身0原因
    • 容器中没有前台进程。容器应该至少包含一个long-running的前台进程,不能后台运行,比如通过nohup这种方式去启动进程,或是用tomcat的startup.sh脚本。
      对于容器启动后立即退出的情况,通常因为容器直接消失,无法获取其输出流日志,很难直接通过现场定位问题。
      一个建议的排查方式,通过设置特殊的启动命令卡住容器(如 tail -f /dev/null),然后进到容器中手动执行命令看结果,确认问题原因。
  • 运行一段时间后退出,这种情况一般是容器内进程crash或者被系统终止导致退出。
    此时,首先查看容器退出状态码,然后进一步查看上下文信息进行错误定位。
    一般这种情况发生时,容器已经删除消失,无法进入容器中查看日志和堆栈等现场信息,所以一般推荐用户对日志,错误记录等文件配置持久化存储,留存更多现场信息。

常见退出码:

退出码 含义 分析
0 正常退出 容器的启动程序不是一个long-running的前台进程。如果正常退出不符合预期,需要检查容器日志,对程序的执行逻辑进行调整
137 外部终止 137表示容器已收到来自主机操作系统的SIGKILL信号。该信号指示进程立即终止,没有宽限期。可能原因包含: 容器运行时将容器kill,例如docker kill命令;linux用户向进程发送kill -9 命令出发;k8s尝试终止容器,超过优雅下线窗口期后直接kill容器;有节点系统触发,比如遭遇了OOM。
139 段错误 139表示容器收到了来自操作系统的SIGSEGV信号。这表示分段错误——内存违约,由容器试图访问它无权访问的内存位置引起。
143 优雅终止 143表示容器收到来自操作系统的SIGTERM信号。该信号要求容器正常终止。该退出码可能得原因是:容器引擎停止容器,例如使用docker stop停止了容器;k8s终止了容器,比如缩容行为将pod删除。

OOMKilled

常见错误状态:(OOMKilled)

k8s中有两种资源概念: 可压缩资源(cpu)和不可压缩资源(内存,磁盘)。
当cpu这种可压缩资源不足时,pod只会“饥饿”,但不会退出;
而当内存和磁盘io这种不可压缩资源不足时,pod会被kill或者驱逐。
因为内存资源不足/超限所导致的pod异常退出的现象被称为Pod OOMKilled。
k8s中存在两种导致Pod OOMKiulled的场景:

  • Container Limit Reached 容器内存量超限
    pod内的每一个容器都可以配置其内存资源限额,当容器实际占用的内存超额,该容器将被OOMKilled并以状态码137退出。OOMKilled往往发生在pod已经正常运行一段时间后,可能是由于流量增长或是长期运行累积的内存逐渐增加。这种情况需要查看程序日志以了解为什么pod使用的内存超出了预期,是否出现异常行为。如果发现程序只是按照预期运行就发生了OOM,就需要适当提高pod的内存限制值。
    一个常见的错误场景:JAVA容器设置了内存资源限制值Limit,然而然而JVM堆大小限制值比内存Limit更大,导致进程在运行期间堆空间越开越大,最终因为OOM被终止。对于JAVA容器来说,一般建议容器内存限制值Limit需要比JVM 最大堆内存稍大一些。
  • Limit Overconmmit 节点内存耗尽
    k8s有两种资源额度概念:请求值和限制值。默认调度器按照较小的请求值作为调度依据,保障节点的所有pod资源值综合不超过节点容量,而限制值总和允许超过节点容量,这就是k8s资源设计中的Overcommit(超卖)现象。超卖设计在一定程度身上能提高吞吐量和资源利用率,但会出现节点资源被耗尽的情况。当节点上的pod实际使用的内存综合超过某个阈值,k8s将会终止其中的一个或多个pod。为了尽量避免这种情况,建议在创建pod时选择大小相等或相近的内存请求值和限制值,也可以利用调度规则将内存敏感型pod打散到不同节点。

pod驱逐

常见错误状态:(Pod Evicted)

当节点内存,磁盘这种不可压缩资源不足时,k8s会按照QoS等级对节点上的某些Pod进行驱逐,释放资源保证节点可用性。当pod发生驱逐后,上层控制器(例如deployment)会新建pod以维持副本数,新pod会经过调度分配到其他节点创建运行。对于内存资源,可以设置合理的请求值和限制值,避免节点内存耗尽。而对于磁盘资源,pod在运行期间会昌盛临时文件,日志,所以必须对pod磁盘容器进行限制,否则某些pod会会快将磁盘写满。类似限制内存、CPU 用量的方式,在创建Pod时可以对本地临时存储用量(ephemeral-storage)进行限制。同时,Kubelet驱逐条件默认磁盘可用空间在10%以下,可以调整云监控磁盘告警阈值以提前告警。

pod失联

常见错误状态:(Unkonwn)

pod处于Unknown状态,无法获取其详细信息,一般是因为所在节点kubelet异常,无法向APIServer上报Pod信息。首先检查节点状态,通过kubelet和容器运行时地 日志信息定位错误,进行修复。如果无法及时修复节点,可以先将该节点从集群中删除。

无法被删除

常见错误状态:(卡在Terminating)

当一个Pod被执行删除操作后,却长时间处于Terminating状态,这种情况的原因有几种:

  • Pod关联的finalizer未完成。首先查看Pod的metadata字段是否包含finalizer,通过一些特定上下文信息确认finalizer任务具体是什么 通常finalizer的任务未完成可能是因为Volume相关。 如果finalizer无法被完成,可以通过patch操作移除对应的Pod上的finalizer完成删除操作。
  • Pod对中断信号没有响应。Pod没有被终止可能是进程对信号没有响应,可以尝试强制删除Pod
  • 节点孤战。通过查看相同节点上的其他Pod状态确认是否节点故障,尝试重启Kubelet和容器运行时。如果无法修复,先将该节点从集群中删除。

EDAS 排障工具链

EDAS对应用全生命周期的大部分异常都有沉淀和分析,降低用户学习成本,缩短排障时间,EDAS提供一系列解决方案和工具帮助用户解决应用生命周期中的异常问题,包括应用变更前的变更预检,应用变更和运行的事件追踪可观测,应用异常时地诊断工具

应用变更预检

EDAS在应用变更任务下发前将经过预检环节,应用变更预检可以在应用部署前检查集群状态及变更参数是否有效,能够有效避免应用变更过程出错,降低变更风险。当前应用变更预检提供集群可用资源检查,集群健康检查,各项依赖配置检查等项目,对于非预期得我预检结果给出分析和处置建议。例如对于集群资源余量不满足Pod调度需求的异常场景,变更预检结果将显示资源检查不通过,用户能够第一时间做出针对性调整。

posted on 2024-06-04 18:58  代码你敲我不敲  阅读(95)  评论(0编辑  收藏  举报

导航

返回顶端