13

图解kubernetes Pod生命周期事件生成器

 4 years ago
source link: https://studygolang.com/articles/26702
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

PLEG(PodLifecycleEventGenerator)主要是用于周期性检测Pod的运行状态,从而对比Pod前后状态生成事件从而触发kubelet进行Pod容器状态的校证,让我们一起来初探下其内部实现机制

1. 图解设计

1.1 Pod事件生成

MzAjIjq.png!web

Pod事件生成主要是根据对应Pod前后的状态对比来实现,首先通过runtime来获取当前节点的所有Pod的列表,并将对应的状态进行保存,这样在下一个轮训周期就可以通过前后状态的对比去发现状态发生改变的Pod的容器,并且产生对应的事件

1.2 事件通知与状态同步

fUnuimZ.png!web

Pod事件生成之后会通过管道将对应的事件同步给状态同步线程,状态同步线程感知到Pod的变更事件后,会与Pod的目标状态进行对比同步,并调用Runtime来进行最终校证操作的执行,同时在下个轮询周期中又会重新从Runtime获取状态,从而不断校证Pod的状态,直至目标状态

2. Pod记录

Pod记录其实就是一个map,并通过podRecord来保存前后轮询周期Runtime返回的Pod的信息

type podRecord struct {
    old     *kubecontainer.Pod
    current *kubecontainer.Pod
}

type podRecords map[types.UID]*podRecord

3. Pod事件生成器

3.1 获取Pod状态

首先通过runtime来获取当前节点的所有pod的状态

// Get all the pods.
    podList, err := g.runtime.GetPods(true)
    if err != nil {
        klog.Errorf("GenericPLEG: Unable to retrieve pods: %v", err)
        return
    }

3.2 对比Pod信息生成事件

eventsByPodID := map[types.UID][]*PodLifecycleEvent{}
    for pid := range g.podRecords {
        // 获取之前的Pod信息
        oldPod := g.podRecords.getOld(pid)
        pod := g.podRecords.getCurrent(pid)
        // 获取当前Pod的所有容器集合
        allContainers := getContainersFromPods(oldPod, pod)
        for _, container := range allContainers {
            //
            events := computeEvents(oldPod, pod, &container.ID)
            for _, e := range events {
                // 更新pod的events事件
                updateEvents(eventsByPodID, e)
            }
        }
    }

3.3对比容器状态事件生成

Pod的事件主要是通过底层容器的状态来生成的,会最终对比每个容器的前后状态,从而获取变更事件

func generateEvents(podID types.UID, cid string, oldState, newState plegContainerState) []*PodLifecycleEvent {
    if newState == oldState {
        return nil
    }

    klog.V(4).Infof("GenericPLEG: %v/%v: %v -> %v", podID, cid, oldState, newState)
    switch newState {
    case plegContainerRunning:
        return []*PodLifecycleEvent{{ID: podID, Type: ContainerStarted, Data: cid}}
    case plegContainerExited:
        return []*PodLifecycleEvent{{ID: podID, Type: ContainerDied, Data: cid}}
    case plegContainerUnknown:
        return []*PodLifecycleEvent{{ID: podID, Type: ContainerChanged, Data: cid}}
    case plegContainerNonExistent:
        switch oldState {
        case plegContainerExited:
            // We already reported that the container died before.
            return []*PodLifecycleEvent{{ID: podID, Type: ContainerRemoved, Data: cid}}
        default:
            return []*PodLifecycleEvent{{ID: podID, Type: ContainerDied, Data: cid}, {ID: podID, Type: ContainerRemoved, Data: cid}}
        }
    default:
        panic(fmt.Sprintf("unrecognized container state: %v", newState))
    }
}

4. 整体事件流程总览

IRJfiab.png!web

在k8s中有很多类似PLEG的设计,总的设计目标都是为了通过事件的变更和实际期望状态,不断的进行调整,从而达到最终的期望状态, 以后我尽量只给出组件最核心的一点代码,梳理清除整个流程中核心的数据结构与算法

k8s源码阅读电子书地址: https://www.yuque.com/baxiaoshi/tyado3

微信号:baxiaoshi2020 3eyUv2n.jpg!web

关注公告号阅读更多源码分析文章 IVBzm26.jpg!web

更多文章关注 www.sreguide.com

本文由博客一文多发平台 OpenWrite 发布!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK