解读 K8s Pod 的13种典范非常

打印 上一主题 下一主题

主题 870|帖子 870|积分 2610

在K8s中,Pod作为工作负载的运行载体,是最为核心的一个资源对象。Pod具有复杂的生命周期,在其生命周期的每一个阶段,大概发生多种不同的非常环境。K8s作为一个复杂系统,非常诊断通常要求强盛的知识和经验储备。联合实战经历以及EDAS用户真实场景的归纳,我们总结了K8s Pod的13种常见非常场景,给出各个场景的常见错误状态,分析其缘故原由和排查思路。
   本文篇幅超过7千字,通读全文大概需要20分钟。文章内容源自负量真实场景的沉淀和分析,发起收藏,以供查阅。  Pod生命周期

在整个生命周期中,Pod会出现5种阶段(Phase)。


  • Pending:Pod被K8s创建出来后,起始于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. // 获取Pod当前对象描述文件
  2. kubectl get pod <podName> -n <namespace> -o yaml
  3. // 获取Pod信息和事件(Events)
  4. kubectl describe pod <podName> -n <namespace>
  5. // 获取Pod容器日志
  6. kubectl logs <podName> <containerName> -n <namespace>
  7. // 在容器中执行命令
  8. kubectl exec <podName> -n <namespace> -c <containerName> -- <CMD> <ARGS>
复制代码
Pod非常场景

Pod在其生命周期的许多时间点大概发生不同的非常,按照Pod容器是否运行为标记点,我们将非常场景大致分为两类:

  • 在Pod进行调度并创建容器过程中发生非常,此时Pod将卡在Pending阶段。
  • Pod容器运行中发生非常,此时Pod按照详细场景处在不同阶段。
下文将对这详细的13种场景进行形貌和分析。

调度失败

   常见错误状态:Unschedulable  Pod被创建后进入调度阶段,K8s调度器依据Pod声明的资源请求量和调度规则,为Pod挑选一个适合运行的节点。当集群节点均不满意Pod调度需求时,Pod将会处于Pending状态。造成调度失败的典范缘故原由如下:


  • 节点资源不足
K8s将节点资源(CPU、内存、磁盘等)进行数值量化,定义出节点资源容量(Capacity)和节点资源可分配额(Allocatable)。资源容量是指 Kubelet 获取的计算节点当前的资源信息,而资源可分配额是Pod可用的资源。Pod容器有两种资源额度概念:请求值Request和限制值Limit,容器至少能获取请求值巨细、至多能获取限制值的资源量。Pod 的资源请求量是Pod中全部容器的资源请求之和,Pod的资源限制量是Pod中全部容器的资源限制之和。K8s默认调度器按照较小的请求值作为调度依据,保障可调度节点的资源可分配额肯定不小于Pod资源请求值。当集群没有一个节点满意Pod的资源请求量,则Pod将卡在Pending状态。
Pod由于无法满意资源需求而被Pending,大概是由于集群资源不足,需要进行扩容,也有大概是集群碎片导致。以一个典范场景为例,用户集群有10几个4c8g的节点,整个集群资源使用率在60%左右,每个节点都有碎片,但由于碎片太小导致扩不出来一个2c4g的Pod。一般来说,小节点集群会更容易产生资源碎片,而碎片资源无法供Pod调度使用。如果想最大限度地淘汰资源浪费,使用更大的节点大概会带来更好的结果。


  • 超过Namespace资源配额
K8s用户可以通过资源配额(Resource Quota)对Namespace进行资源使用量限制,包括两个维度:
1. 限定某个对象类型(如Pod)可创建对象的总数。
2. 限定某个对象类型可消耗的资源总数。
如果在创建或更新Pod时申请的资源超过了资源配额,则Pod将调度失败。此时需要查抄Namespace资源配额状态,做出得当调整。


  • 不满意 NodeSelector节点选择器
Pod通过NodeSelector节点选择器指定调度到带有特定Label的节点,若不存在满意 NodeSelector的可用节点,Pod将无法被调度,需要对NodeSelector或节点Label进行合理调整。


  • 不满意亲和性
节点亲和性(Affinity)和反亲和性(Anti-Affinity)用于约束Pod调度到哪些节点,而亲和性又细分为软亲和(Preferred)和硬亲和(Required)。对于软亲和规则,K8s调度器会尝试探求满意对应规则的节点,如果找不到匹配的节点,调度器仍旧会调度该 Pod。而当硬亲和规则不被满意时,Pod将无法被调度,需要查抄Pod调度规则和目的节点状态,对调度规则或节点进行合理调整。


  • 节点存在污点
K8s提供污点(Taints)和容忍(Tolerations)机制,用于克制 Pod 被分配到不符合的节点上。如果节点上存在污点,而 Pod 没有设置相应的容忍,Pod 将不会调度到该 节点。此时需要确认节点是否有携带污点的须要,如果不须要的话可以移除污点;若Pod可以分配到带有污点的节点,则可以给Pod增长污点容忍。


  • 没有可用节点
节点大概会由于资源不足、网络不通、Kubelet未停当等缘故原由导致不可用(NotReady)。当集群中没有可调度的节点,也会导致Pod卡在Pending状态。此时需要检察节点状态,排查不可用节点问题并修复,或进行集群扩容。
镜像拉取失败

   常见错误状态:ImagePullBackOff  Pod经过调度后分配到目的节点,节点需要拉取Pod所需的镜像为创建容器做预备。拉取镜像阶段大概存在以下几种缘故原由导致失败:


  • 镜像名字拼写错误或设置了错误的镜像
出现镜像拉取失败后首先要确认镜像地点是否设置错误。


  • 私有仓库的免密设置错误
集群需要进行免密设置才气拉取私有镜像。自建镜像仓库时需要在集群创建免密凭据Secret,在Pod指定ImagePullSecrets,或者将Secret嵌入ServicAccount,让Pod使用对应的ServiceAccount。而对于acr等镜像服务云产物一般会提供免密插件,需要在集群中正确安装免密插件才气拉取仓库内的镜像。免密插件的非常包括:集群免密插件未安装、免密插件Pod非常、免密插件设置错误,需要检察相关信息进行进一步排查。


  • 网络不通
网络不通的常见场景有三个:
1. 集群通过公网访问镜像仓库,而镜像仓库未设置公网的访问计谋。对于自建仓库,大概是端口未开放,或是镜像服务未监听公网IP;对于acr等镜像服务云产物,需要确认开启公网的访问入口,设置白名单等访问控制计谋。
2. 集群位于专有网络,需要为镜像服务设置专有网络的访问控制,才气创建集群节点与镜像服务之间的毗连。
3. 拉取外洋镜像例如http://gcr.io仓库镜像,需设置镜像加快服务。


  • 镜像拉取超时
常见于带宽不足或镜像体积太大,导致拉取超时。可以尝试在节点上手动拉取镜像,观察传输速率和传输时间,须要时可以对集群带宽进行升配,或者得当调整 Kubelet 的 --image-pull-progress-deadline 和 --runtime-request-timeout 选项。


  • 同时拉取多个镜像,触发并行度控制
常见于用户弹性扩容出一个节点,大量待调度Pod被同时调度上去,导致一个节点同时有大量Pod启动,同时从镜像仓库拉取多个镜像。而受限于集群带宽、镜像仓库服务稳固性、容器运行时镜像拉取并行度控制等因素,镜像拉取并不支持大量并行。这种环境可以手动打断一些镜像的拉取,按照优先级让镜像分批拉取。
依靠项错误

   常见错误状态:Error  

在 Pod 启动之前,Kubelet将尝试查抄与其他 K8s 元素的全部依靠关系。主要存在的依靠项有三种:PersistentVolume、ConfigMap和Secret。当这些依靠项不存在或者无法读取时,Pod容器将无法正常创建,Pod会处于Pending状态直到满意依靠性。当这些依靠项能被正确读取,但出现设置错误时,也会出现无法创建容器的环境。比如将一个只读的持久化存储卷PersistentVolume以可读写的形式挂载到容器,或者将存储卷挂载到/proc等非法路径,也会导致容器创建失败。
容器创建失败

   常见错误状态:Error  Pod容器创建过程中出现了错误。常见缘故原由包括:


  • 违背集群的安全计谋,比如违背了 PodSecurityPolicy 等。
  • 容器无权操纵集群内的资源,比如开启 RBAC 后,需要为 ServiceAccount 设置角色绑定。
  • 缺少启动命令,Pod形貌文件和镜像Dockerfile中均未指定启动命令。
  • 启动命令设置错误。Pod设置文件可以通过command字段定义命令行,通过args字段给命令行定义参数。启动命令设置错误的环境非常多见,要格外注意命令及参数的格式。正确的填写方式可参考:

初始化失败

   常见错误状态:CrashLoopBackOff  K8s提供Init Container特性,用于在启动应用容器之前启动一个或多个初始化容器,完成应用程序所需的预置条件。Init container与应用容器本质上是一样的,但它们是仅运行一次就结束的任务,并且必须在执行完成后,系统才气继续执行下一个容器。如果 Pod 的Init Container执行失败,将会block业务容器的启动。通过检察Pod状态和事件定位到Init Container故障后,需要检察Init Container日志进一步排查故障点。
回调失败

   常见错误状态:FailedPostStartHook或FailedPreStopHook事件  K8s提供PostStart和PreStop两种容器生命周期回调,分别在容器中的进程启动前或者容器中的进程停止之前运行。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  容器退出分为两种场景:


  • 启动后立刻退出,大概缘故原由是:
1. 启动命令的路径未包含在环境变量PATH中。
2. 启动命令引用了不存在的文件或目次。
3. 启动命令执行失败,大概由于运行环境缺少依靠,也大概是程序自己缘故原由。
4. 启动命令没有执行权限。
5. 容器中没有前台进程。容器应该至少包含一个long-running的前台进程,不能配景运行,比如通过nohup这种方式去启动进程,或是用tomcat的startup.sh脚本。
对于容器启动后立刻退出的环境,通常由于容器直接消散,无法获取其输出流日志,很难直接通过现场定位问题。一个简易的排查方式是,通过设置特别的启动命令卡住容器(比如使用tail -f /dev/null),然后进到容器中手动执行命令看看结果,确认问题缘故原由。


  • 运行一段时间后退出,这种环境一般是容器内1进程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 OOMKilled的场景:


  • Container Limit Reached,容器内存用量超限
Pod内的每一个容器都可以设置其内存资源限额,当容器实际占用的内存超额,该容器将被OOMKilled并以状态码137退出。OOMKilled通常发生在Pod已经正常运行一段时间后,大概是由于流量增长或是长期运行累积的内存渐渐增长。这种环境需要检察程序日志以了解为什么Pod使用的内存超出了预期,是否出现非常行为。如果发现程序只是按照预期运行就发生了OOM,就需要得当提高Pod内存限制值。一个很常见的错误场景是,JAVA容器设置了内存资源限制值Limit,然而JVM堆巨细限制值比内存Limit更大,导致进程在运行期间堆空间越开越大,终极由于OOM被停止。对于JAVA容器来说,一般发起容器内存限制值Limit需要比JVM 最大堆内存稍大一些。


  • Limit Overcommit,节点内存耗尽
K8s有两种资源额度概念:请求值Request和限制值Limit,默认调度器按照较小的请求值作为调度依据,保障节点的全部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处于Unkonwn状态,无法获取其详细信息,一般是由于地点节点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调度需求的非常场景,变更预检结果将表现资源查抄不通过,用户能够第一时间做出针对性调整。

应用事件观测

EDAS对应用生命周期中的事件进行追踪提供可观测能力。对于应用变更过程提供完整的事项展示,让用户能够白屏观测到变更中的每一个步调和相关上下文信息。当出现非常变更环境时,将详细的事件和相关资源信息在白屏透出,并对非常事件进行分析解读并给出操纵发起。例如给Pod设置了容器服务仓库镜像,但并未正确设置集群免密插件,EDAS将镜像拉取失败事件抛出,并引导用户查抄镜像拉取权限。

诊断工具箱

对于非常Pod,通常需要毗连到Pod容器,对业务进程进行诊断,须要时候还需要对非常进行复现。EDAS提供云原生工具箱,让用户在网页上毗连Pod容器Shell,并且提供Arthas、Tcpdump等工具,补充镜像软件工具包的缺失。对于Pod已经消散、不适合在业务Pod进行诊断等场景,云原生工具箱提供Pod复制能力,根据诊断场景不同,用户可以按需选择开启诊断Pod。
对于上文中提到的容器进程被大流量阻塞,导致Pod被Liveness打挂的场景,用户可以通过云原生工具箱,开启一个移除Liveness的诊断Pod,设置全链路流量控制规则,打入一些测试流量,使用Arthas提供的trace、stack、watch等工具精准定位问题

参考文档



  • https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/
  • https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
  • https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod/
  • https://docs.docker.com/engine/reference/commandline/pull/#concurrent-downloads
  • https://developer.aliyun.com/article/1066441
  • https://alibaba.github.io/arthas
原文链接
本文为阿里云原创内容,未经允许不得转载。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

光之使者

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表