详解Kubernetes中Pod的创建和删除过程

前言

之前简单了解了Pod的创建过程,也遇到过Pod无法删除的问题,但大部分都是强制删除。因此,此篇文档记录一下对这两个过程的细致理解。

对go语言不够熟悉,暂时无法达到阅读代码的能力,以下信息均来源于网络总结和自己的思考。

创建过程

1660112505748.png

  1. kubectl 将创建Pod的yaml文件提交给APIServer;
  2. APIServer 收到指令通知给controller-manager创建一个资源对象;
  3. controller-manager通过APIServer将Pod的配置信息存储到ETCD中;
  4. scheduler通过 watch机制监听到ETCD中有要创建Pod但未调度的请求后开始调度预选,
    1. 首先过滤掉不符合资源配置的要求的node;
    2. 然后开始调度选优,计算出更适合运行的节点。将Pod和节点绑定信息交给APIServer。
  5. APIServer将信息写入ETCD中,
  6. kubelet根据调度结果执行pod创建操作,运行成功后将创建结果返回给APIServer。

删除过程

所谓删除Pod的过程,主要指用户通过kubectl delete pod命令,或者利用HTTP调用接口去执行。

代码解读

DeleteResource

首先调用BeforeDelete方法,查看要删除的Resource瑞祥是否支持优雅删除,如果支持,则优雅变量为TRUE。还执行两个设定,设置删除的时间戳为now,以及优雅删除的时间限制,由用户来决定。

优雅变量如果未TRUE,那么就会调用updateForGracefulDeletionAndFinalizers方法,该方法用于改变Pod的两个字段,DeletionTimestamp和DeletionGracePeriodSeconds。

调用完该方法后会返回deleteImmediately字段,表示是否需要立刻删除,也就是不支持优雅删除。如果支持优雅删除,则delete方法不删除ETCD中的Resource数据,直接返回,APIServer处理逻辑到此结束。

kubelet删除Pod

kubelet使用syncLoopIteration监听APIServer,一旦出现删除时间,则调用HandlePodUpdates方法处理。

  1. 首先调用pod manager的updatePod方法来更新Pod信息;
  2. 然后判断pod是否为mirror pod,如果是则调用handleMirrorPod方法处理该Pod;
  3. 否则利用GetMirrorPodByPod方法得到该Pod的mirror pod,接着调用dispatchWork将pod删除分配给具体的worker处理;
  4. dispatchwork方法调用UpdatePod方法对Pod进行删除;
    1. 该方法会调用其他方法进行判断,进行删除;
    2. 杀掉Pod中的容器;
    3. 删除pod的pause容器。
  5. kubelet 判断Pod是否已经优雅的停止,资源是否删除干净。
    1. 如果删除干净则返回TRUE,向APIServer发送delete,再次删除Pod。优雅时间设置为0,表示强制删除Pod。因此APIServer会再次收到delete请求,继续执行delete的流程。与第一次不同的是,这次强制删除会执行完整的流程,操作ETCD删除最终的Pod信息。
  6. kubelete 接收到事件变化后,转为remove事件,完成Pod的最终清理工作。

以上内容可能描述的并不是很清晰,先占位,以后再补。

概括

以上流程中还有很多未细致拆分的事件,不再赘述,下面概况总结一下:

  1. 客户端发出请求删除Pod(可选传递优雅删除参数,时间秒为单位);
  2. APIServer 做优雅删除的检查,并更新Pod信息,设置删除时间戳和优雅删除时间,默认30s;
  3. kubelet优雅释放Pod资源;
  4. kubelet向APIServer请求删除Pod;
  5. APIServer删除etcd中Pod信息;
  6. Kubelet 完成最终Pod的资源清理。

如何删除Pod

强制删除

delete pod xxx -n xxx --force --grace-period
1
2
3
4

#### finalizers 删除

```kubectl patch pod xxx -n xxx -p '{"metadata":{"finalizers":null}}'

如果一个容器已经在运行,这时需要对一些容器属性进行修改,又不想删除容器,或不方便通过replace的方式进行更新。kubernetes还提供了一种在容器运行时,直接对容器进行修改的方式,就是patch命令。这时就需要edit该资源,将字段finalizers设置为null,之后Kubernetes资源就正常删除了。

APIServer在检查Finalizers并结合是否需要优雅删除来决定是否立刻删除对象。如果对象不需要进行优雅删除:metadata.Finalizers为空,则直接删除。

Finalizers

Finalizers属于kubernetes GC垃圾收集器,是一种删除拦截机制,能够让控制权实现异步的删除前回调。其存在任何一个资源对象的meta中。

Graceful Deletion

APIServer在处理Pod删除请求时,会根据pod 的 pod.Spec.TerminationGracePeriodSeconds 和 deleteOptions.GracefulPeriodSeconds 综合判断,是否进行 Graceful 删除:

  1. 当删除请求选项中有设置 GracefulPeriodSeconds,以选项中为准。若没有,使用 pod.Spec.TerminationGracePeriodSeconds 。若 pod.Spec.TerminationGracePeriodSeconds 也没有设置,使用默认值 0 。
  2. 当 Pod 没有调度,或者已经结束(无论成功还是失败)。GracePeriodSeconds 都重置为 0.GracePeriodSeconds 为 0 表示不进行优雅删除。非 0 表示进行优雅删除。Pod 的默认优雅删除时间为 30 s ,在对象创建时配置在 pod.Spec.TerminationGracePeriodSeconds 字段。

优雅删除的目的是给予 Kubelet 一定时间对 Pod 实行优雅退出。在用户对 Pod 执行 Delete 操作时,Pod 对象不会立即从 API Server 删除,而只是进入 Termination 阶段。Kubelet 会对运行中的 Pod 的容器发送 TERM 信号,通知其退出。并执行用户配置的 preStop hooks 逻辑。当优雅时间过了之后,再开始使用 KILL 信号尝试强制杀容器。

当 kubelet 将 Pod 清理干净后,就会使用 GracefulPeriodSeconds==0 的参数执行删除操作。

因为 Pod 实现优雅删除目的是为了给予 Kubelet 时间做资源清理操作,所以这也是为什么在设置 GracePeriodSeconds 阶段,若 Pod 没有被调度或者已经退出,也就可以直接允许立即删除 (GracePeriodSeconds = 0)。

无法删除的原因

了解上述机制后,对象无法删除的原因无外乎以下两个方面:

  1. 对象存在finalizers,关联的控制权故障未能执行或执行finalizer函数卡主
  2. 对象需要优雅删除,但是执行者不能完成删除,比如以下情况:
    1. kubelet 无法通过container runtime杀死进程。比如进程进入Uninterruptible状态。
    2. kubelet进程停止或者node离线。这种情况下没有kubelet运行或运行中的kubelet与APIServer已经端口,无法收到Pod需要删除的消息。所以没有执行者来进行优雅删除。这种情况下恢复节点以及kubelet即可。
------ 本文结束 ------

版权声明

Medivh's Notes by Medivh is licensed under a Creative Commons BY-NC-ND 4.0 International License.
Medivh创作并维护的Medivh's Notes博客采用创作共用保留署名-非商业-禁止演绎4.0国际许可证
本文首发于Medivh 博客( http://www.mknight.cn ),版权所有,侵权必究。