前言
之前简单了解了Pod的创建过程,也遇到过Pod无法删除的问题,但大部分都是强制删除。因此,此篇文档记录一下对这两个过程的细致理解。
对go语言不够熟悉,暂时无法达到阅读代码的能力,以下信息均来源于网络总结和自己的思考。
创建过程
- kubectl 将创建Pod的yaml文件提交给APIServer;
- APIServer 收到指令通知给controller-manager创建一个资源对象;
- controller-manager通过APIServer将Pod的配置信息存储到ETCD中;
- scheduler通过 watch机制监听到ETCD中有要创建Pod但未调度的请求后开始调度预选,
- 首先过滤掉不符合资源配置的要求的node;
- 然后开始调度选优,计算出更适合运行的节点。将Pod和节点绑定信息交给APIServer。
- APIServer将信息写入ETCD中,
- 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方法处理。
- 首先调用pod manager的updatePod方法来更新Pod信息;
- 然后判断pod是否为mirror pod,如果是则调用handleMirrorPod方法处理该Pod;
- 否则利用GetMirrorPodByPod方法得到该Pod的mirror pod,接着调用dispatchWork将pod删除分配给具体的worker处理;
- dispatchwork方法调用UpdatePod方法对Pod进行删除;
- 该方法会调用其他方法进行判断,进行删除;
- 杀掉Pod中的容器;
- 删除pod的pause容器。
- kubelet 判断Pod是否已经优雅的停止,资源是否删除干净。
- 如果删除干净则返回TRUE,向APIServer发送delete,再次删除Pod。优雅时间设置为0,表示强制删除Pod。因此APIServer会再次收到delete请求,继续执行delete的流程。与第一次不同的是,这次强制删除会执行完整的流程,操作ETCD删除最终的Pod信息。
- kubelete 接收到事件变化后,转为remove事件,完成Pod的最终清理工作。
以上内容可能描述的并不是很清晰,先占位,以后再补。
概括
以上流程中还有很多未细致拆分的事件,不再赘述,下面概况总结一下:
- 客户端发出请求删除Pod(可选传递优雅删除参数,时间秒为单位);
- APIServer 做优雅删除的检查,并更新Pod信息,设置删除时间戳和优雅删除时间,默认30s;
- kubelet优雅释放Pod资源;
- kubelet向APIServer请求删除Pod;
- APIServer删除etcd中Pod信息;
- Kubelet 完成最终Pod的资源清理。
如何删除Pod
强制删除
1 |
|
如果一个容器已经在运行,这时需要对一些容器属性进行修改,又不想删除容器,或不方便通过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 删除:
- 当删除请求选项中有设置 GracefulPeriodSeconds,以选项中为准。若没有,使用 pod.Spec.TerminationGracePeriodSeconds 。若 pod.Spec.TerminationGracePeriodSeconds 也没有设置,使用默认值 0 。
- 当 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)。
无法删除的原因
了解上述机制后,对象无法删除的原因无外乎以下两个方面:
- 对象存在finalizers,关联的控制权故障未能执行或执行finalizer函数卡主
- 对象需要优雅删除,但是执行者不能完成删除,比如以下情况:
- kubelet 无法通过container runtime杀死进程。比如进程进入Uninterruptible状态。
- kubelet进程停止或者node离线。这种情况下没有kubelet运行或运行中的kubelet与APIServer已经端口,无法收到Pod需要删除的消息。所以没有执行者来进行优雅删除。这种情况下恢复节点以及kubelet即可。