Node工作负载异常,一部分pod状态为Terminating

278 阅读9分钟

微信公众号:运维开发故事,作者:夏老师

pod状态为Terminating

我们需要从pod的生命周期与Node的NotReady来分析。在节点处于“NotReady”状态时,deployment控制器会迁移节点上的容器实例,并将节点上运行的pod置为“Terminating”状态。待节点恢复后,处于“Terminating”状态的pod会自动删除。偶现部分pod(实例)一直处于“Terminating ”状态,发现这部分的pod没有得到重新调度,不能提供服务。

pod的生命周期

Pod对象自从其创建开始至其终止退出的时间范围称为其生命周期。在这段时间中,Pod会处于多种不同的状态,并执行一些操作;其中,创建主容器(main container)为必需的操作,其他可选的操作还包括运行初始化容器(init container)、容器启动后钩子(post start hook)、容器的存活性探测(liveness probe)、就绪性探测(readiness probe)以及容器终止前钩子(pre stop hook)等,这些操作是否执行则取决于Pod的定义。如下图所示:

image.png

Pod 的生命周期

Pod的status字段是一个PodStatus的对象,PodStatus中有一个phase字段。 无论是手动创建还是通过Deployment等控制器创建,Pod对象总是应该处于其生命进程中以下几个相位(phase)之一。

  • 挂起(Pending):API Server创建了pod资源对象已存入etcd中,但它尚未被调度完成,或者仍处于从仓库下载镜像的过程中。
  • 运行中(Running):Pod已经被调度至某节点,并且所有容器都已经被kubelet创建完成。
  • 成功(Succeeded):Pod中的所有容器都已经成功终止并且不会被重启
  • 失败(Failed):Pod中的所有容器都已终止了,并且至少有一个容器是因为失败终止。即容器以非0状态退出或者被系统禁止。
  • 未知(Unknown):Api Server无法正常获取到Pod对象的状态信息,通常是由于无法与所在工作节点的kubelet通信所致。

注意:当一个 Pod 被删除时,它会Terminating被一些 kubectl 命令显示为。此Terminating状态不是 Pod 阶段之一。Pod 被授予正常终止的期限,默认为 30 秒。您可以使用该标志--force来强行终止pod。 image.png Pod是kubernetes的基础单元,理解它的创建过程对于了解系统运作大有裨益。如下图描述了一个Pod资源对象的典型创建过程。

image.png

  1. 用户通过kubectl或其他API客户端提交了Pod Spec给API Server。
  2. API Server尝试着将Pod对象的相关信息存入etcd中,待写入操作执行完成,API Server即会返回确认信息至客户端。
  3. API Server开始反映etcd中的状态变化。
  4. 所有的kubernetes组件均使用“watch”机制来跟踪检查API Server上的相关的变动。
  5. kube-scheduler(调度器)通过其“watcher”觉察到API Server创建了新的Pod对象但尚未绑定至任何工作节点。
  6. kube-scheduler为Pod对象挑选一个工作节点并将结果信息更新至API Server。
  7. 调度结果信息由API Server更新至etcd存储系统,而且API Server也开始反映此Pod对象的调度结果。
  8. Pod被调度到的目标工作节点上的kubelet尝试在当前节点上调用Docker启动容器,并将容器的结果状态返回送至API Server。
  9. API Server将Pod状态信息存入etcd系统中。
  10. 在etcd确认写入操作成功完成后,API Server将确认信息发送至相关的kubelet,事件将通过它被接受。

删除 Pod的逻辑

当发起一个删除 Pod 的指令时 Pod 的删除逻辑是这样的:

  1. 调用 kube-apiserver 发起删除 Pod 请求,如果删除 Pod 时没有设置 grace period 参数那么就会使用 30 秒的默认值,否则就会使用用户指定的 grace period 进行优雅下线
  2. kube-apiserver 接受到这个请求以后给相应的 Pod 标记为“删除状态”。其实 Pod 没有“删除状态”,此时 Pod 的 status 还是 Running 状态,所谓的“删除状态”只是 deletionTimestamp 和 deletionGracePeriodSeconds 字段会被设置,这时候 kubelet 或者 kube-proxy 监听到这样的 Pod 就会认为此 Pod 已经不能提供服务了,然后开始做相应的清理操作。
  3. 此时如果通过 Dashbord 查看 Pod 的状态是 Terminating ,其实 Terminating 也不是 Pod status 的字段的值。只是因为设置了 deletionTimestamp 和 deletionGracePeriodSeconds 字段所以 Dashbord 就会把 Pod 标记为 Terminating 状态。
  4. (和第三条同时发生)当 kube-proxy 监听到 Pod 处于 Terminatiing 状态时就把 Pod 从 Service 的 EndPoint 中摘掉,这样对外暴露的服务就摘掉了这个 Pod,防止新的请求发送到这个 Pod 上来
  5. kubelet 监测到 Pod 处于 Terminating 状态的话会下线 Pod,下线的过程分成两个步骤。1. 执行 PreStop 2. 杀死容器。第一步:如果 Pod 设置了 PreStop hook 的话 kubelet 监测到 Pod 处于 Terminating 状态后就会执行 PreStop 操作,执行 PreStop 设置的超时时间和删除 Pod 时指定的 grace period 一致(如果没设置默认是 30 秒)
  6. PreStop 执行完以后还有第二步杀死容器,第二部也有超时时间,这个超时时间是 grace period 减去 PreStop 耗时。如果执行 PreStop 超时或者 grace period 减去 PreStop 耗时剩余的时间不够两秒(甚至可能是负数) kubelet 会强制设置成两秒。第二部的超时时间暂且称之为 tm2, kubelet 停止容器时执行的是 docker stop -t tm2 命令。所以 tm2 的逻辑是:首先发送 term 信号到容器的一号进程,如果容器在 tm2 时间内没有停止就强制发送 kill 信号杀死容器
  7. kubelet 执行完 PreStop 和杀死容器两步以后会回调 kube-apiserver,把 Pod 从 kube-apiserver 中删除,这次的删除是真的删除,这时候通过 API 就再也看不到这个 Pod 的信息了

Eviction介绍

Eviction,即驱逐的意思,意思是当节点出现异常时,为了保证工作负载的可用性,kubernetes将有相应的机制驱逐该节点上的Pod。 目前kubernetes中存在两种eviction机制,分别由kube-controller-managerkubelet实现。

kube-controller-manager实现的eviction

kube-controller-manager主要由多个控制器构成,而eviction的功能主要由node controller这个控制器实现。该Eviction会周期性检查所有节点状态,当节点处于NotReady状态超过一段时间后,驱逐该节点上所有pod。kube-controller-manager提供了以下启动参数控制eviction:

  • **pod-eviction-timeout:**即当节点宕机该时间间隔后,开始eviction机制,驱赶宕机节点上的Pod,默认为5min。
  • **node-eviction-rate:**驱赶速率,即驱赶Node的速率,由令牌桶流控算法实现,默认为0.1,即每秒驱赶0.1个节点,注意这里不是驱赶Pod的速率,而是驱赶节点的速率。相当于每隔10s,清空一个节点。
  • **secondary-node-eviction-rate:**二级驱赶速率,当集群中宕机节点过多时,相应的驱赶速率也降低,默认为0.01。
  • **unhealthy-zone-threshold:**不健康zone阈值,会影响什么时候开启二级驱赶速率,默认为0.55,即当该zone中节点宕机数目超过55%,而认为该zone不健康。
  • **large-cluster-size-threshold:**大集群阈值,当该zone的节点多余该阈值时,则认为该zone是一个大集群。大集群节点宕机数目超过55%时,则将驱赶速率降为0.01,假如是小集群,则将速率直接降为0。

由kube-controller-manager触发的驱逐,会留下一个状态为Terminating的pod,想要删除这些状态的 Pod 有三种方法:

  • 从集群中删除该 Node。使用公有云时,kube-controller-manager 会在 VM 删除后自动删除对应的 Node。而在物理机部署的集群中,需要管理员手动删除 Node(如 kubectl delete node 。
  • Node 恢复正常。Kubelet 会重新跟 kube-apiserver 通信确认这些 Pod 的期待状态,进而再决定删除或者继续运行这些 Pod。
  • 用户强制删除。用户可以执行 kubectl delete pods --grace-period=0 --force 强制删除 Pod。除非明确知道 Pod 的确处于停止状态(比如 Node 所在 VM 或物理机已经关机),否则不建议使用该方法。特别是 StatefulSet 管理的 Pod,强制删除容易导致脑裂或者数据丢失等问题。

kubelet的eviction机制

如果节点处于资源压力,那么kubelet就会执行驱逐策略。驱逐会考虑Pod的优先级,资源使用和资源申请。当优先级相同时,资源使用/资源申请最大的Pod会被首先驱逐。kube-controller-manager的eviction机制是粗粒度的,即驱赶一个节点上的所有pod,而kubelet则是细粒度的,它驱赶的是节点上的某些Pod,驱赶哪些Pod与Pod的Qos机制有关。该Eviction会周期性检查本节点内存、磁盘等资源,当资源不足时,按照优先级驱逐部分pod。驱逐阈值分为软驱逐阈值(Soft Eviction Thresholds)和强制驱逐(Hard Eviction Thresholds)两种机制,如下:kubelet提供了以下参数控制eviction:

  • **软驱逐阈值:**当node的内存/磁盘空间达到一定的阈值后,kubelet不会马上回收资源,如果改善到低于阈值就不进行驱逐,若这段时间一直高于阈值就进行驱逐。
  • **强制驱逐:**强制驱逐机制则简单的多,一旦达到阈值,直接把pod从本地驱逐。
  • **eviction-soft:**软驱逐阈值设置,具有一系列阈值,比如memory.available<1.5Gi时,它不会立即执行pod eviction,而会等待eviction-soft-grace-period时间,假如该时间过后,依然还是达到了eviction-soft,则触发一次pod eviction。
  • **eviction-soft-grace-period:**默认为90秒,当eviction-soft时,终止Pod的grace的时间,即软驱逐宽限期,软驱逐信号与驱逐处理之间的时间差。
  • **eviction-max-pod-grace-period:**最大驱逐pod宽限期,停止信号与kill之间的时间差。
  • **eviction-pressure-transition-period:**默认为5分钟,脱离pressure condition的时间,超过阈值时,节点会被设置为memory pressure或者disk pressure,然后开启pod eviction。
  • **eviction-minimum-reclaim:**表示每一次eviction必须至少回收多少资源。
  • **eviction-hard:**强制驱逐设置,也具有一系列的阈值,比如memory.available<1Gi,即当节点可用内存低于1Gi时,会立即触发一次pod eviction。

由kubelet触发的驱逐,会留下一个状态为Evicted的pod,此pod只是方便后期定位的记录,可以直接删除。

总结:

偶现部分pod(实例)一直处于“Terminating ”状态,发现这部分的pod没有得到重新调度,不能提供服务。 这一类deployment其发布策略是Recreate模式(先删旧POD,再启动新POD)。该问题对于rollout滚动发布的deployment没有影响,仅对recreate的造成影响(类似statefulset也有影响)。,想要删除这些状态的 Pod 有三种方法:

  • 从集群中删除该 Node。使用公有云时,kube-controller-manager 会在 VM 删除后自动删除对应的 Node。而在物理机部署的集群中,需要管理员手动删除 Node(如 kubectl delete node 。
  • Node 恢复正常。Kubelet 会重新跟 kube-apiserver 通信确认这些 Pod 的期待状态,进而再决定删除或者继续运行这些 Pod。
  • 用户强制删除。用户可以执行 kubectl delete pods --grace-period=0 --force 强制删除 Pod。除非明确知道 Pod 的确处于停止状态(比如 Node 所在 VM 或物理机已经关机),否则不建议使用该方法。特别是 StatefulSet 管理的 Pod,强制删除容易导致脑裂或者数据丢失等问题。

参考文章: feisky.gitbooks.io/kubernetes/… v1-20.docs.kubernetes.io/docs/concep… v1-20.docs.kubernetes.io/docs/concep…