本文转载自微信公众号「运维开发故事」,作者没有文案的夏老师。转载本文请联系运维开发故事公众号。
pod状态为Terminating
在节点处于“NotReady”状态时,deployment控制器会迁移节点上的容器实例,并将节点上运行的pod置为“Terminating”状态。待节点恢复后,处于“Terminating”状态的pod会自动删除。偶现部分pod(实例)一直处于“Terminating ”状态,发现这部分的pod没有得到重新调度,不能提供服务。
Terminating不是pod生命周期PodStatus中的phase字段。会不会导致一些问题呢?我们来了解一下pod的生命周期与驱逐相关的概念。
pod的生命周期
Pod对象自从其创建开始至其终止退出的时间范围称为其生命周期。在这段时间中,Pod会处于多种不同的状态,并执行一些操作;其中,创建主容器(main container)为必需的操作,其他可选的操作还包括运行初始化容器(init container)、容器启动后钩子(post start hook)、容器的存活性探测(liveness probe)、就绪性探测(readiness probe)以及容器终止前钩子(pre stop hook)等,这些操作是否执行则取决于Pod的定义。如下图所示:
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。
Pod是kubernetes的基础单元,理解它的创建过程对于了解系统运作大有裨益。如下图描述了一个Pod资源对象的典型创建过程。
- 用户通过kubectl或其他API客户端提交了Pod Spec给API Server。
- API Server尝试着将Pod对象的相关信息存入etcd中,待写入操作执行完成,API Server即会返回确认信息至客户端。
- API Server开始反映etcd中的状态变化。
- 所有的kubernetes组件均使用“watch”机制来跟踪检查API Server上的相关的变动。
- kube-scheduler(调度器)通过其“watcher”觉察到API Server创建了新的Pod对象但尚未绑定至任何工作节点。
- kube-scheduler为Pod对象挑选一个工作节点并将结果信息更新至API Server。
- 调度结果信息由API Server更新至etcd存储系统,而且API Server也开始反映此Pod对象的调度结果。
- Pod被调度到的目标工作节点上的kubelet尝试在当前节点上调用Docker启动容器,并将容器的结果状态返回送至API Server。
- API Server将Pod状态信息存入etcd系统中。
- 在etcd确认写入操作成功完成后,API Server将确认信息发送至相关的kubelet,事件将通过它被接受。
删除 Pod的逻辑
当发起一个删除 Pod 的指令时 Pod 的删除逻辑是这样的:
- 调用 kube-apiserver 发起删除 Pod 请求,如果删除 Pod 时没有设置 grace period 参数那么就会使用 30 秒的默认值,否则就会使用用户指定的 grace period 进行优雅下线
- kube-apiserver 接受到这个请求以后给相应的 Pod 标记为“删除状态”。其实 Pod 没有“删除状态”,此时 Pod 的 status 还是 Running 状态,所谓的“删除状态”只是 deletionTimestamp 和 deletionGracePeriodSeconds 字段会被设置,这时候 kubelet 或者 kube-proxy 监听到这样的 Pod 就会认为此 Pod 已经不能提供服务了,然后开始做相应的清理操作。
- 此时如果通过 Dashbord 查看 Pod 的状态是 Terminating ,其实 Terminating 也不是 Pod status 的字段的值。只是因为设置了 deletionTimestamp 和 deletionGracePeriodSeconds 字段所以 Dashbord 就会把 Pod 标记为 Terminating 状态。
- (和第三条同时发生)当 kube-proxy 监听到 Pod 处于 Terminatiing 状态时就把 Pod 从 Service 的 EndPoint 中摘掉,这样对外暴露的服务就摘掉了这个 Pod,防止新的请求发送到这个 Pod 上来
- kubelet 监测到 Pod 处于 Terminating 状态的话会下线 Pod,下线的过程分成两个步骤。1. 执行 PreStop 2. 杀死容器。第一步:如果 Pod 设置了 PreStop hook 的话 kubelet 监测到 Pod 处于 Terminating 状态后就会执行 PreStop 操作,执行 PreStop 设置的超时时间和删除 Pod 时指定的 grace period 一致(如果没设置默认是 30 秒)
- PreStop 执行完以后还有第二步杀死容器,第二部也有超时时间,这个超时时间是 grace period 减去 PreStop 耗时。如果执行 PreStop 超时或者 grace period 减去 PreStop 耗时剩余的时间不够两秒(甚至可能是负数) kubelet 会强制设置成两秒。第二部的超时时间暂且称之为 tm2, kubelet 停止容器时执行的是 docker stop -t tm2 命令。所以 tm2 的逻辑是:首先发送 term 信号到容器的一号进程,如果容器在 tm2 时间内没有停止就强制发送 kill 信号杀死容器
- kubelet 执行完 PreStop 和杀死容器两步以后会回调 kube-apiserver,把 Pod 从 kube-apiserver 中删除,这次的删除是真的删除,这时候通过 API 就再也看不到这个 Pod 的信息了
Eviction介绍
Eviction,即驱逐的意思,意思是当节点出现异常时,为了保证工作负载的可用性,kubernetes将有相应的机制驱逐该节点上的Pod。目前kubernetes中存在两种eviction机制,分别由kube-controller-manager和kubelet实现。
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也有影响)根据以上描述deployment最好使用rollout滚动发布策略。
部分pod(实例)一直处于“Terminating ”状态,情况分为很多种,这里腾讯云做过一个总结:
《Pod 一直处于 Terminating 状态》。
https://cloud.tencent.com/document/product/457/43238
有兴趣的可以去了解一下。
想要删除这些状态的 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,强制删除容易导致脑裂或者数据丢失等问题。
参考文章:
https://feisky.gitbooks.io/kubernetes/content/troubleshooting/pod.html
https://v1-20.docs.kubernetes.io/docs/concepts/workloads/pods/#
https://v1-20.docs.kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/
https://cloud.tencent.com/document/product/457/43238