啟動參數
參考: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 |
啟動過程
解析命令行參數
注冊Prometheus系統指標
初始化 kubernetes client
-
注冊 PodFilterFunc,用來過濾要驅逐的Pods
不驅逐mirror pods
如果 evictLocalStoragePods == false,不驅逐使用 emptyDir 的 pods
如果 evictUnreplicatedPods == false,不驅逐 OwnerReference 不為空的 pods
如果 evictDaemonSetPods == false,不驅逐 OwnerReference 為 DaemonSet 的 pods
如果 evictStatefulSetPods == false,不驅逐 OwnerReference 為 StatefulSet 的 pods
不驅逐配置有 cluster-autoscaler.kubernetes.io/safe-to-evict=false 注解,及 --protected-pod-annotation 參數中指定注解的 pods
構建 DrainingResourceEventHandler 對象
解析 --node-label 和 --node-label-expr 參數,并封裝成節點標簽過濾函數(nodeLabelFilterFunc)
通過 informer 機制監聽 Node 變更,并生成 NodeWatch 對象
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 中,以便你能知道執行是成功還是失敗。
獲取目標節點的最新信息,如果找不到目標節點則返回nil
如果結束時間不為空,記錄此次排干(drain)操作的結束狀態和結束時間
給目標節點添加一個 DrainScheduled 類型的 condition,并更新到 API Server
Drain()
Drain() 方法用于執行排干操作,執行過程為:
如果 --skip-drain 為 true,則返回nil
獲取目標節點上的所有 pods,并過濾掉不需要處理的 pods
-
執行 pod 驅逐操作,如果驅逐失敗或超時,返回錯誤信息
如果 pod 未設置 .Spec.TerminationGracePeriodSeconds,則默認為 --max-grace-period
調用 Kubernetes API 的 Evict() 接口執行驅逐
如果 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()
遍歷目標節點的 conditions,獲取目標節點有哪些異常的、需要處理的conditions
如果節點需要解禁(uncordon),則執行解禁(uncordon)操作
如果節點當前是可調度狀態,則執行禁用(cordon)操作
如果該節點尚未創建排干執行計劃,則為其創建排干執行計劃
如果排除操作失敗,并且節點配置了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}
}