Draino源碼分析

啟動參數(shù)

參考:draino 入門

系統(tǒng)指標(biāo)

指標(biāo)名稱 Measure 說明 聚合函數(shù)
cordoned_nodes_total draino/nodes_cordoned 被禁用(cordon)的節(jié)點數(shù)量 Count
uncordoned_nodes_total draino/nodes_uncordoned 解除禁用(uncordon)的節(jié)點數(shù)量 Count
drained_nodes_total draino/nodes_drained 被排干(drain)的節(jié)點數(shù)量 Count
drain_scheduled_nodes_total draino/nodes_drainScheduled 排干計劃數(shù)量 Count

啟動過程

  1. 解析命令行參數(shù)

  2. 注冊Prometheus系統(tǒng)指標(biāo)

  3. 初始化 kubernetes client

  4. 注冊 PodFilterFunc,用來過濾要驅(qū)逐的Pods

    1. 不驅(qū)逐mirror pods

    2. 如果 evictLocalStoragePods == false,不驅(qū)逐使用 emptyDir 的 pods

    3. 如果 evictUnreplicatedPods == false,不驅(qū)逐 OwnerReference 不為空的 pods

    4. 如果 evictDaemonSetPods == false,不驅(qū)逐 OwnerReference 為 DaemonSet 的 pods

    5. 如果 evictStatefulSetPods == false,不驅(qū)逐 OwnerReference 為 StatefulSet 的 pods

    6. 不驅(qū)逐配置有 cluster-autoscaler.kubernetes.io/safe-to-evict=false 注解,及 --protected-pod-annotation 參數(shù)中指定注解的 pods

  5. 構(gòu)建 DrainingResourceEventHandler 對象

  6. 解析 --node-label 和 --node-label-expr 參數(shù),并封裝成節(jié)點標(biāo)簽過濾函數(shù)(nodeLabelFilterFunc)

  7. 通過 informer 機(jī)制監(jiān)聽 Node 變更,并生成 NodeWatch 對象

  8. Leader選舉,選舉完成后執(zhí)行 NodeWatch 的 Run() 方法

核心接口

Cordoner

該接口的功能是對指定的節(jié)點執(zhí)行禁用(cordon)或解禁(uncordon)的操作。

type Cordoner interface {
    // 將指定的 Node 設(shè)置為不可調(diào)度
    Cordon(n *core.Node, mutators ...nodeMutatorFn) error
    // 將指定的 Node 設(shè)置為可調(diào)度
    Uncordon(n *core.Node, mutators ...nodeMutatorFn) error
}

Drainer

該接口的功能是對指定的節(jié)點執(zhí)行排干(drain)操作,并給指定節(jié)點設(shè)置一個 condition,用于記錄排干(drain)操作的開始和結(jié)束信息。

type Drainer interface {
    // 排干指定的Node。驅(qū)逐該節(jié)點上除 mirror pods 和 DaemonSet pods 之外的所有 pods
    Drain(n *core.Node) error
  // 給指定節(jié)點設(shè)置一個 condition,用于記錄排干(drain)操作的開始和結(jié)束信息
    MarkDrain(n *core.Node, when, finish time.Time, failed bool) error
}

CordonDrainer

從其接口定義可知,CordonDrainer 兼具 Cordoner 和 Drainer兩者的功能。

type CordonDrainer interface {
    Cordoner
    Drainer
}

DrainScheduler

由于節(jié)點排干(drain)是一個耗時較長的過程,Draino會為每一個節(jié)點的排干過程生成一個執(zhí)行計劃,DrainScheduler 接口定義了排干執(zhí)行計劃相關(guān)的操作。

type DrainScheduler interface {
  // 目標(biāo)節(jié)點是否正在執(zhí)行排干(drain)操作,操作是否失敗
    HasSchedule(name string) (has, failed bool)
  // 創(chuàng)建模板節(jié)點排干執(zhí)行計劃
    Schedule(node *v1.Node) (time.Time, error)
  // 刪除目標(biāo)節(jié)點排干執(zhí)行計劃
    DeleteSchedule(name string)
}

核心對象

APICordonDrainer

APICordonDrainer 實現(xiàn)了 CordonDrainer 接口,具備對指定的節(jié)點執(zhí)行禁用(cordon)或解禁(uncordon)的操作,及對指定的節(jié)點執(zhí)行排干(drain)操作的能力。它通過調(diào)用 Kubernetes API 實現(xiàn)對應(yīng)的功能。

Cordon() 方法是將目標(biāo)節(jié)點的 .spec.unschedulable 設(shè)為 true,Uncordon() 方法是將目標(biāo)節(jié)點的 .spec.unschedulable 設(shè)為 false。

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

    filter PodFilterFunc

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

當(dāng)一次排干動作開始時,Draino 會給目標(biāo)節(jié)點的 status 中添加一個 DrainScheduled 類型的 condition,這個 condition 會記錄此次排干動作的開始和結(jié)束信息。之后,當(dāng)排干動作執(zhí)行完成后,Draino 會將執(zhí)行結(jié)果補(bǔ)充到 condition 中,以便你能知道執(zhí)行是成功還是失敗。

  1. 獲取目標(biāo)節(jié)點的最新信息,如果找不到目標(biāo)節(jié)點則返回nil

  2. 如果結(jié)束時間不為空,記錄此次排干(drain)操作的結(jié)束狀態(tài)和結(jié)束時間

  3. 給目標(biāo)節(jié)點添加一個 DrainScheduled 類型的 condition,并更新到 API Server

Drain()

Drain() 方法用于執(zhí)行排干操作,執(zhí)行過程為:

  1. 如果 --skip-drain 為 true,則返回nil

  2. 獲取目標(biāo)節(jié)點上的所有 pods,并過濾掉不需要處理的 pods

  3. 執(zhí)行 pod 驅(qū)逐操作,如果驅(qū)逐失敗或超時,返回錯誤信息

    1. 如果 pod 未設(shè)置 .Spec.TerminationGracePeriodSeconds,則默認(rèn)為 --max-grace-period

    2. 調(diào)用 Kubernetes API 的 Evict() 接口執(zhí)行驅(qū)逐

    3. 如果 Kubernetes 返回請求過于頻繁,則睡眠5s;如果返回 Pod 不存在,則返回 nil;否則將 error 信息寫入 channel 并返回

DrainSchedules

DrainSchedules 實現(xiàn)了 DrainScheduler 接口

DrainingResourceEventHandler

DrainingResourceEventHandler 實現(xiàn)了 ResourceEventHandler 接口,其 OnAdd() 和 OnUpdate() 方法底層都依賴于 HandleNode() 方法,主要是對目標(biāo)節(jié)點執(zhí)行禁用(cordon)和排干(drain)操作。OnDelete() 實現(xiàn)較為簡單,只是從 DrainSchedules 中刪除目標(biāo)節(jié)點排干操作相關(guān)信息。

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

    lastDrainScheduledFor time.Time
    buffer                time.Duration

    conditions []SuppliedCondition
}
HandleNode()
  1. 遍歷目標(biāo)節(jié)點的 conditions,獲取目標(biāo)節(jié)點有哪些異常的、需要處理的conditions

  2. 如果節(jié)點需要解禁(uncordon),則執(zhí)行解禁(uncordon)操作

  3. 如果節(jié)點當(dāng)前是可調(diào)度狀態(tài),則執(zhí)行禁用(cordon)操作

  4. 如果該節(jié)點尚未創(chuàng)建排干執(zhí)行計劃,則為其創(chuàng)建排干執(zhí)行計劃

  5. 如果排除操作失敗,并且節(jié)點配置了draino/drain-retry注解,則再次為其創(chuàng)建排干執(zhí)行計劃

FilteringResourceEventHandler

FilteringResourceEventHandler 是 client-go 提供的工具類,它在 ResourceEventHandler 的基礎(chǔ)上增加了對象過濾功能,在執(zhí)行 OnAdd()、OnUpdate()、OnDelete()方法前,會先調(diào)用 FilterFunc 方法判斷當(dāng)前對象是否需要處理,如果不需要就直接返回。

Draino 中將 FilteringResourceEventHandler 與 --node-label 和 --node-label-expr 參數(shù)結(jié)合使用,用于實現(xiàn)對被處理 Node 的過濾。

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

NodeWatch

NodeWatch 繼承自 SharedInformer。在構(gòu)造 NodeWatch 時,會將 FilteringResourceEventHandler 注冊到其 EventHandler 列表中。

type NodeWatch struct {
    cache.SharedInformer
}

NodeWatch 的構(gòu)造方法:

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}
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容