Delete pod main source analytic process

This paper analyzes the version to v1.12

When deleting a pod, client terminal sends a request to apiserver, apiserver deletionTimestamp marked time of the pod. kubelet watch the event to begin processing.

syncLoop

kubelet handling of the pod are mainly processed in syncLoop in.

func (kl *Kubelet) syncLoop(updates <-chan kubetypes.PodUpdate, handler SyncHandler) {
for {
...
        if !kl.syncLoopIteration(updates, handler, syncTicker.C, housekeepingTicker.C, plegCh) {
            break
        }
...

The main concern with the pod in syncLoopIteration delete the following two.

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)
            }
        }
    }

The first is due to be sent to apiserver the DELETE request triggered an increase deletionTimestamp events. Here corresponds to kubetypes.UPDATE. That is, it will come HandlePodUpdates function.

Another related delete is performed once every 2s from housekeepingCh timed event for the clean-up pod, execution is handler.HandlePodCleanups function. These two different effects are described separately below.

HandlePodUpdates

HandlePodUpdates look at this process. As long as marked deletionTimestamp, this process will inevitably come to go.

func (kl *Kubelet) HandlePodUpdates(pods []*v1.Pod) {
    for _, pod := range pods {
...
        kl.dispatchWork(pod, kubetypes.SyncPodUpdate, mirrorPod, start)
    }
}

In HandlePodUpdates in turn passes the information to the pod dispatchWork processing.

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) {
...

Here it is first determined by the kl.podIsTerminated (pod) Analyzing pod is not already in the Terminated state. If so, the following kl.podWorkers.UpdatePod not performed.

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))
}

This place is particularly noteworthy that not a DeletionTimestamp will be considered by the Terminated state, but there are DeletionTimestamp and all containers are not running. This means that if a pod is a normal operation, is also kl.podWorkers.UpdatePod went in. UpdatePod through a series of function calls, function into the final syncPod syncPod function will be executed by asynchronously.

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 {
...

In syncPod, call killPod thereby stopping the operation of the pod.

killPod

killPod is to stop the pod body. It will be used in many places. This introduces the next play a major workflow. Stop the pod process occurs mainly in killPodWithSyncResult function.

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 {
...

The main killPodWithSyncResult divided into two parts. killContainersWithSyncResult responsible pod in the container to stop off at the stop before the implementation of 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 main work is done in the killContainer, it can be seen here, in which the two main step is carried out in a vessel operated prestop. Let it succeed, a stop of work container. At this point all of the application container have been stopped. The next step is to stop the pause container. The StopPodSandbox is the implementation of this process. The sandbox, that is, pause vessel to stop off. StopPodSandbox is performed in dockershim in.

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 {

The main part of the first network StopPodSandbox is unloaded, and then stopping the corresponding container. After completing StopPodSandbox, all vessels have been stopped so far pod completed. As for the volume of unloading is carried out in volumeManager in. This article does not describe the individual. After the container is stopped after a thorough clean-up pod, it will be recycled gc. Here not start speaking up.

HandlePodCleanups

This process does not remove all the above processes. A typical case is that if the container is not running, so when UpdatePod all return, then who is going to handle it? Here we go back to the beginning, is that the implementation of a process of HandlePodCleanups every 2s. That such container in the case of crash, container, etc. just is not running, in fact, are processed in this process was. Of course, the role of HandlePodCleanups more than just cleaning up not running in the pod, and then forced to clean up such data has been lost in apiserver in, or due to other reasons for this node and some did not complete the clean-up pod, are handled in this process.

func (kl *Kubelet) HandlePodCleanups() error {
... 
    for _, pod := range runningPods {
        if _, found := desiredPods[pod.ID]; !found {
            kl.podKillingCh <- &kubecontainer.PodPair{APIPod: nil, RunningPod: pod}
        }
    }

runningPods pod is to obtain an existing node from the cache, while desiredPods is there should not stop the pod on the node. If there runningPods but there are no desiredPods the pod, then it should be stopped, it is sent to the podKillingCh in.

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)
        }
    }
}

In podKiller process, will receive a message from podKillingCh to thereby perform killPod, described above, it has been made of the function.

statusManager

In the final, syncPod statusManager in the process, it will detect, verify that all containers closed by canBeDeleted, volume uninstalled, cgroup clean up and so on. If these all done, from apiserver pod will completely remove the information.

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)
...

Guess you like

Origin www.cnblogs.com/xuxinkun/p/11923372.html