启动参数
参考: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}
}
网友评论