本文以 v1.12 版本进行分析
当一个 pod 删除时, client 端向 apiserver 发送请求, apiserver 将 pod 的 deletionTimestamp 打上时间. kubelet watch 到该事件, 开始处理.
syncLoop
kubelet 对 pod 的处理主要都是在 syncLoop 中处理的.
- func (kl *Kubelet) syncLoop(updates <-chan kubetypes.PodUpdate, handler SyncHandler) {
- for {
- ...
- if !kl.syncLoopIteration(updates, handler, syncTicker.C, housekeepingTicker.C, plegCh) {
- break
- }
- ...
与 pod 删除主要在 syncLoopIteration 中需要关注的是以下这两个.
- func (kl *Kubelet) syncLoopIteration(configCh <-chan kubetypes.PodUpdate, handler SyncHandler,
- syncCh <-chan time.Time, housekeepingCh <-chan time.Time, plegCh <-chan *pleg.PodLifecycleEvent) bool {
- select {
- case u, open := <-configCh:
- ...
- switch u.Op {
- ...
- case kubetypes.UPDATE:
- handler.HandlePodUpdates(u.Pods)
- ...
- case <-housekeepingCh:
- if !kl.sourcesReady.AllReady() {
- } else {
- if err := handler.HandlePodCleanups(); err != nil {
- glog.Errorf("Failed cleaning pods: %v", err)
- }
- }
- }
第一个是由于发送给 apiserver 的 DELETE 请求触发的, 增加了 deletionTimestamp 的事件. 这里对应于 kubetypes.UPDATE. 也就是会走到 HandlePodUpdates 函数.
另外一个与 delete 相关的是每 2s 执行一次的来自于 housekeepingCh 的定时事件, 用于清理 pod, 执行的是 handler.HandlePodCleanups 函数. 这两个作用不同, 下面分别进行介绍.
HandlePodUpdates
先看 HandlePodUpdates 这个流程. 只要打上了 deletionTimestamp, 就必然走到这个流程里去.
- func (kl *Kubelet) HandlePodUpdates(pods []*v1.Pod) {
- for _, pod := range pods {
- ...
- kl.dispatchWork(pod, kubetypes.SyncPodUpdate, mirrorPod, start)
- }
- }
在 HandlePodUpdates 中, 进而将 pod 的信息传递到 dispatchWork 中处理.
- func (kl *Kubelet) dispatchWork(pod *v1.Pod, syncType kubetypes.SyncPodType, mirrorPod *v1.Pod, start time.Time) {
- if kl.podIsTerminated(pod) {
- if pod.DeletionTimestamp != nil {
- kl.statusManager.TerminatePod(pod)
- }
- return
- }
- // Run the sync in an async worker.
- kl.podWorkers.UpdatePod(&UpdatePodOptions{
- Pod: pod,
- MirrorPod: mirrorPod,
- UpdateType: syncType,
- OnCompleteFunc: func(err error) {
- ...
这里首先通过判断了 kl.podIsTerminated(pod) 判断 pod 是不是已经处于了 Terminated 状态. 如果是的话, 则不进行下面的 kl.podWorkers.UpdatePod.
- func (kl *Kubelet) podIsTerminated(pod *v1.Pod) bool {
- status, ok := kl.statusManager.GetPodStatus(pod.UID)
- if !ok {
- status = pod.Status
- }
- return status.Phase == v1.PodFailed || status.Phase == v1.PodSucceeded || (pod.DeletionTimestamp != nil && notRunning(status.ContainerStatuses))
- }
这个地方特别值得注意的是, 并不是由了 DeletionTimestamp 就会认为是 Terminated 状态, 而是有 DeletionTimestamp 且所有的容器不在运行了. 也就是说如果是一个正在正常运行的 pod, 是也会走到 kl.podWorkers.UpdatePod 中的. UpdatePod 通过一系列函数调用, 最终会通过异步的方式执行 syncPod 函数中进入到 syncPod 函数中.
- func (kl *Kubelet) syncPod(o syncPodOptions) error {
- ...
- if !runnable.Admit || pod.DeletionTimestamp != nil || apiPodStatus.Phase == v1.PodFailed {
- var syncErr error
- if err := kl.killPod(pod, nil, podStatus, nil); err != nil {
- ...
在 syncPod 中, 调用 killPod 从而对 pod 进行停止操作.
killPod
killPod 是停止 pod 的主体. 在很多地方都会使用. 这里主要介绍下起主要的工作流程. 停止 pod 的过程主要发生在 killPodWithSyncResult 函数中.
- func (m *kubeGenericRuntimeManager) killPodWithSyncResult(pod *v1.Pod, runningPod kubecontainer.Pod, gracePeriodOverride *int64) (result kubecontainer.PodSyncResult) {
- killContainerResults := m.killContainersWithSyncResult(pod, runningPod, gracePeriodOverride)
- ...
- for _, podSandbox := range runningPod.Sandboxes {
- if err := m.runtimeService.StopPodSandbox(podSandbox.ID.ID); err != nil {
- ...
killPodWithSyncResult 的主要工作分为两个部分. killContainersWithSyncResult 负责将 pod 中的 container 停止掉, 在停止后再执行 StopPodSandbox.
- func (m *kubeGenericRuntimeManager) killContainer(pod *v1.Pod, containerID kubecontainer.ContainerID, containerName string, reason string, gracePeriodOverride *int64) error {
- if err := m.internalLifecycle.PreStopContainer(containerID.ID); err != nil {
- return err
- }
- ...
- err := m.runtimeService.StopContainer(containerID.ID, gracePeriod)
killContainersWithSyncResult 的主要工作是在 killContainer 中完成的, 这里可以看到, 其中的主要两个步骤是在容器中进行 prestop 的操作. 待其成功后, 进行 container 的 stop 工作. 至此所有的应用容器都已经停止了. 下一步是停止 pause 容器. 而 StopPodSandbox 就是执行这一过程的. 将 sandbox, 也就是 pause 容器停止掉. StopPodSandbox 是在 dockershim 中执行的.
- func (ds *dockerService) StopPodSandbox(ctx context.Context, r *runtimeapi.StopPodSandboxRequest) (*runtimeapi.StopPodSandboxResponse, error) {
- ...
- if !hostNetwork && (ready || !ok) {
- ...
- err := ds.network.TearDownPod(namespace, name, cID, annotations)
- ...
- }
- if err := ds.client.StopContainer(podSandboxID, defaultSandboxGracePeriod); err != nil {
StopPodSandbox 中主要的部分是先进行网络卸载, 再停止相应的容器. 在完成 StopPodSandbox 后, 至此 pod 的所有容器都已经停止完成. 至于 volume 的卸载, 是在 volumeManager 中进行的. 本文不做单独介绍了. 停止后的容器在 pod 彻底清理后, 会被 gc 回收. 这里也不展开讲了.
HandlePodCleanups
上面这个流程并不是删除流程的全部. 一个典型的情况就是, 如果 container 都不是 running, 那么在 UpdatePod 的时候都 return 了, 那么又由谁来处理呢? 这里我们回到最开始, 就是那个每 2s 执行一次的 HandlePodCleanups 的流程. 也就是说比如 container 处于 crash,container 正好不是 running 等情况, 其实是在这个流程里进行处理的. 当然 HandlePodCleanups 的作用不仅仅是清理 not running 的 pod, 再比如数据已经在 apiserver 中强制清理掉了, 或者由于其他原因这个节点上还有一些没有完成清理的 pod, 都是在这个流程中进行处理.
- func (kl *Kubelet) HandlePodCleanups() error {
- ...
- for _, pod := range runningPods {
- if _, found := desiredPods[pod.ID]; !found {
- kl.podKillingCh <- &kubecontainer.PodPair{APIPod: nil, RunningPod: pod}
- }
- }
runningPods 是从 cache 中获取节点现有的 pod, 而 desiredPods 则是节点上应该存在未被停止的 pod. 如果存在 runningPods 中有而 desiredPods 中没有的 pod, 那么它应该被停止, 所以发送到 podKillingCh 中.
- func (kl *Kubelet) podKiller() {
- ...
- for podPair := range kl.podKillingCh {
- ...
- if !exists {
- go func(apiPod *v1.Pod, runningPod *kubecontainer.Pod) {
- glog.V(2).Infof("Killing unwanted pod %q", runningPod.Name)
- err := kl.killPod(apiPod, runningPod, nil, nil)
- ...
- }(apiPod, runningPod)
- }
- }
- }
在 podKiller 流程中, 会去接收来自 podKillingCh 的消息, 从而执行 killPod, 上文已经做了该函数的介绍了.
statusManager
在最后, statusManager 中的 syncPod 流程, 将会进行检测, 通过 canBeDeleted 确认是否所有的容器关闭了, volume 卸载了, cgroup 清理了等等. 如果这些全部完成了, 则从 apiserver 中将 pod 信息彻底删除.
- func (m *manager) syncPod(uid types.UID, status versionedPodStatus) {
- ...
- if m.canBeDeleted(pod, status.status) {
- deleteOptions := metav1.NewDeleteOptions(0)
- deleteOptions.Preconditions = metav1.NewUIDPreconditions(string(pod.UID))
- err = m.kubeClient.CoreV1().Pods(pod.Namespace).Delete(pod.Name, deleteOptions)
- ...
来源: https://www.cnblogs.com/xuxinkun/p/11923372.html