这是我于2020年在 Kubernetes sig-scheduling 小组的 scheduler-plugin 开源项目贡献的第一个调度器插件。
1、 背景
相关PR:PR103: Pod State Scheduling Plugin
源码地址:Pod State Scheduling
- 当前 Kubernetes 原生的调度器打分算法(Score)没有考虑节点上已有的 Terminating 状态的 Pod
- 当前 Kubernetes 原生的调度器打分算法(Score)没有考虑节点上已有的 Nominated 状态的 Pod
2、功能简介
Pod State scheduling 调度器插件实现了一个打分的扩展插件(Score Plugin)
- 节点上有越多 Terminating 状态的 Pod 在打分阶段会获得越高的分数(Pod 即将和节点解绑释放资源,期望获得更高分数)
- 节点上有越多 Nominted 状态的 Pod 在打分阶段会获得越低的分数(Pod 即将和节点绑定占用资源,期望获得更低分数)
3、实现原理
打分算法的实现原理:
- 分别统计每个节点上 Terminating 和 Nominated 状态的 Pod 数量
- 对每个 Terminating 状态的 Pod 分数加 1
- 对每个 Nominated 状态的 Pod 分数减 1
func (ps *PodState) score(nodeInfo *framework.NodeInfo) (int64, *framework.Status) {
var terminatingPodNum, nominatedPodNum int64
// get nominated Pods for node from nominatedPodMap
nominatedPodNum = int64(len(ps.handle.PreemptHandle().NominatedPodsForNode(nodeInfo.Node().Name)))
for _, p := range nodeInfo.Pods {
// Pod is terminating if DeletionTimestamp has been set
if p.Pod.DeletionTimestamp != nil {
terminatingPodNum++
}
}
return terminatingPodNum - nominatedPodNum, nil
}
规整分数范围:
- 分别统计得分最高和最低节点的分数
- 用最高分减去最低分确定源分数范围(oldRange)
- 用打分插件配置的最高分减去最低分确定目标分数范围(newRange)
- 计算公式:((每个节点的真实得分 - 所有节点的最低分) * newRange / oldRange) + 打分插件配置的最低分
func (ps *PodState) NormalizeScore(ctx context.Context, state *framework.CycleState, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status {
// Find highest and lowest scores.
var highest int64 = -math.MaxInt64
var lowest int64 = math.MaxInt64
for _, nodeScore := range scores {
if nodeScore.Score > highest {
highest = nodeScore.Score
}
if nodeScore.Score < lowest {
lowest = nodeScore.Score
}
}
// Transform the highest to lowest score range to fit the framework's min to max node score range.
oldRange := highest - lowest
newRange := framework.MaxNodeScore - framework.MinNodeScore
for i, nodeScore := range scores {
if oldRange == 0 {
scores[i].Score = framework.MinNodeScore
} else {
scores[i].Score = ((nodeScore.Score - lowest) * newRange / oldRange) + framework.MinNodeScore
}
}
return nil
}
3、使用手册
调度器插件配置样例:
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: KubeSchedulerConfiguration
leaderElection:
leaderElect: false
clientConnection:
kubeconfig: "REPLACE_ME_WITH_KUBE_CONFIG_PATH"
profiles:
- schedulerName: default-scheduler
plugins:
score:
enabled:
- name: PodState