Draino源码分析

启动参数

参考:draino 入门

系统指标

指标名称 Measure 说明 聚合函数
cordoned_nodes_total draino/nodes_cordoned 被禁用(cordon)的节点数量 Count
uncordoned_nodes_total draino/nodes_uncordoned 解除禁用(uncordon)的节点数量 Count
drained_nodes_total draino/nodes_drained 被排干(drain)的节点数量 Count
drain_scheduled_nodes_total draino/nodes_drainScheduled 排干计划数量 Count

启动过程

  1. 解析命令行参数

  2. 注册Prometheus系统指标

  3. 初始化 kubernetes client

  4. 注册 PodFilterFunc,用来过滤要驱逐的Pods

    1. 不驱逐mirror pods

    2. 如果 evictLocalStoragePods == false,不驱逐使用 emptyDir 的 pods

    3. 如果 evictUnreplicatedPods == false,不驱逐 OwnerReference 不为空的 pods

    4. 如果 evictDaemonSetPods == false,不驱逐 OwnerReference 为 DaemonSet 的 pods

    5. 如果 evictStatefulSetPods == false,不驱逐 OwnerReference 为 StatefulSet 的 pods

    6. 不驱逐配置有 cluster-autoscaler.kubernetes.io/safe-to-evict=false 注解,及 --protected-pod-annotation 参数中指定注解的 pods

  5. 构建 DrainingResourceEventHandler 对象

  6. 解析 --node-label 和 --node-label-expr 参数,并封装成节点标签过滤函数(nodeLabelFilterFunc)

  7. 通过 informer 机制监听 Node 变更,并生成 NodeWatch 对象

  8. Leader选举,选举完成后执行 NodeWatch 的 Run() 方法

核心接口

Cordoner

该接口的功能是对指定的节点执行禁用(cordon)或解禁(uncordon)的操作。

type Cordoner interface {
    // 将指定的 Node 设置为不可调度
    Cordon(n *core.Node, mutators ...nodeMutatorFn) error
    // 将指定的 Node 设置为可调度
    Uncordon(n *core.Node, mutators ...nodeMutatorFn) error
}

Drainer

该接口的功能是对指定的节点执行排干(drain)操作,并给指定节点设置一个 condition,用于记录排干(drain)操作的开始和结束信息。

type Drainer interface {
    // 排干指定的Node。驱逐该节点上除 mirror pods 和 DaemonSet pods 之外的所有 pods
    Drain(n *core.Node) error
  // 给指定节点设置一个 condition,用于记录排干(drain)操作的开始和结束信息
    MarkDrain(n *core.Node, when, finish time.Time, failed bool) error
}

CordonDrainer

从其接口定义可知,CordonDrainer 兼具 Cordoner 和 Drainer两者的功能。

type CordonDrainer interface {
    Cordoner
    Drainer
}

DrainScheduler

由于节点排干(drain)是一个耗时较长的过程,Draino会为每一个节点的排干过程生成一个执行计划,DrainScheduler 接口定义了排干执行计划相关的操作。

type DrainScheduler interface {
  // 目标节点是否正在执行排干(drain)操作,操作是否失败
    HasSchedule(name string) (has, failed bool)
  // 创建模板节点排干执行计划
    Schedule(node *v1.Node) (time.Time, error)
  // 删除目标节点排干执行计划
    DeleteSchedule(name string)
}

核心对象

APICordonDrainer

APICordonDrainer 实现了 CordonDrainer 接口,具备对指定的节点执行禁用(cordon)或解禁(uncordon)的操作,及对指定的节点执行排干(drain)操作的能力。它通过调用 Kubernetes API 实现对应的功能。

Cordon() 方法是将目标节点的 .spec.unschedulable 设为 true,Uncordon() 方法是将目标节点的 .spec.unschedulable 设为 false。

type APICordonDrainer struct {
    c kubernetes.Interface
    l *zap.Logger

    filter PodFilterFunc

    maxGracePeriod   time.Duration
    evictionHeadroom time.Duration
    skipDrain        bool
}
MarkDrain()

当一次排干动作开始时,Draino 会给目标节点的 status 中添加一个 DrainScheduled 类型的 condition,这个 condition 会记录此次排干动作的开始和结束信息。之后,当排干动作执行完成后,Draino 会将执行结果补充到 condition 中,以便你能知道执行是成功还是失败。

  1. 获取目标节点的最新信息,如果找不到目标节点则返回nil

  2. 如果结束时间不为空,记录此次排干(drain)操作的结束状态和结束时间

  3. 给目标节点添加一个 DrainScheduled 类型的 condition,并更新到 API Server

Drain()

Drain() 方法用于执行排干操作,执行过程为:

  1. 如果 --skip-drain 为 true,则返回nil

  2. 获取目标节点上的所有 pods,并过滤掉不需要处理的 pods

  3. 执行 pod 驱逐操作,如果驱逐失败或超时,返回错误信息

    1. 如果 pod 未设置 .Spec.TerminationGracePeriodSeconds,则默认为 --max-grace-period

    2. 调用 Kubernetes API 的 Evict() 接口执行驱逐

    3. 如果 Kubernetes 返回请求过于频繁,则睡眠5s;如果返回 Pod 不存在,则返回 nil;否则将 error 信息写入 channel 并返回

DrainSchedules

DrainSchedules 实现了 DrainScheduler 接口

DrainingResourceEventHandler

DrainingResourceEventHandler 实现了 ResourceEventHandler 接口,其 OnAdd() 和 OnUpdate() 方法底层都依赖于 HandleNode() 方法,主要是对目标节点执行禁用(cordon)和排干(drain)操作。OnDelete() 实现较为简单,只是从 DrainSchedules 中删除目标节点排干操作相关信息。

type DrainingResourceEventHandler struct {
    logger         *zap.Logger
    cordonDrainer  CordonDrainer        // 即 APICordonDrainer 对象
    eventRecorder  record.EventRecorder
    drainScheduler DrainScheduler

    lastDrainScheduledFor time.Time
    buffer                time.Duration

    conditions []SuppliedCondition
}
HandleNode()
  1. 遍历目标节点的 conditions,获取目标节点有哪些异常的、需要处理的conditions

  2. 如果节点需要解禁(uncordon),则执行解禁(uncordon)操作

  3. 如果节点当前是可调度状态,则执行禁用(cordon)操作

  4. 如果该节点尚未创建排干执行计划,则为其创建排干执行计划

  5. 如果排除操作失败,并且节点配置了draino/drain-retry注解,则再次为其创建排干执行计划

FilteringResourceEventHandler

FilteringResourceEventHandler 是 client-go 提供的工具类,它在 ResourceEventHandler 的基础上增加了对象过滤功能,在执行 OnAdd()、OnUpdate()、OnDelete()方法前,会先调用 FilterFunc 方法判断当前对象是否需要处理,如果不需要就直接返回。

Draino 中将 FilteringResourceEventHandler 与 --node-label 和 --node-label-expr 参数结合使用,用于实现对被处理 Node 的过滤。

type FilteringResourceEventHandler struct {
    FilterFunc func(obj interface{}) bool
    Handler    ResourceEventHandler
}

NodeWatch

NodeWatch 继承自 SharedInformer。在构造 NodeWatch 时,会将 FilteringResourceEventHandler 注册到其 EventHandler 列表中。

type NodeWatch struct {
    cache.SharedInformer
}

NodeWatch 的构造方法:

func NewNodeWatch(c kubernetes.Interface, rs ...cache.ResourceEventHandler) *NodeWatch {
    lw := &cache.ListWatch{
        ListFunc:  func(o meta.ListOptions) (runtime.Object, error) { return c.CoreV1().Nodes().List(o) },
        WatchFunc: func(o meta.ListOptions) (watch.Interface, error) { return c.CoreV1().Nodes().Watch(o) },
    }
    i := cache.NewSharedInformer(lw, &core.Node{}, 30*time.Minute)
    for _, r := range rs {
        i.AddEventHandler(r)
    }
    return &NodeWatch{i}
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,695评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,569评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,130评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,648评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,655评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,268评论 1 309
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,835评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,740评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,286评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,375评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,505评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,873评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,357评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,466评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,921评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,515评论 2 359

推荐阅读更多精彩内容