调度需求
k8s的默认调度器在调度pod时,分两个阶段,第一个阶段:根据请求资源和pod、node的亲和性等配置筛选出符合要求的node列表。第二阶段:对筛选出来的node资源情况进行打分排序,最终选择打分最高的node作为pod的调度节点。在一些场景,我们想要自定义筛选节点的算法,该如何做呢?下面以slurm on k8s的需求举例,通过两种方式对k8s的调度器进行扩展
需求
- 部署slurm集群时需要根据物理架构选择性能最优的节点进行部署
- 在节点资源不足时,希望所有的pod都不要调度
物理架构
在slurm worker节点调度时,希望slurm cluster最好运行在一个leaf Pod网络内,且尽可能占用最少的leaf Pod数,对leaf Pod网络拓扑碎片化的影响最小
测试用例(如下su即是一个leaf Pod):
假设:su中空闲的服务器从大到小排序后依次是su(m) 、su(m-1)、... su(m-7),申请的计算服务器数量为n.
用例一:n > sum(su(m) + su(m-1)+ ... + su(m-7))时,调度失败
用例二:n < su(m-7)时,服务器全部从su(m-7)进行调度
用例三:n < su(m-k) & n > su(m-k+1)时,服务器全部从su(m-k)进行调度, k的范围 (0, 1, 2, 3, 4, 5, 6, 7)
用例四:n < sum(su(m) + su(m-1)+ ... + su(m-7)) & n > su(m-7)时,服务器根据su(m)、sum(m-1)... 顺序进行优先调度,直到满足数量要求
通过k8s 调度器框架进行扩展
对PreScore、Score扩展点进行扩展, 不支持pod group调度。同一个集群的部分pod调度完成后实际的leafpod拓扑结构已经发生变化
func (n *leafPodPlugin) PreScore(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodes []*v1.Node) *framework.Status {
// 1. 获取pod group的实例个数
podAnnotations := pod.GetAnnotations()
podGroupReplicas, _ := strconv.Atoi(podAnnotations["replicas"])
// 2. 遍历nodes, 计算node所属leafpod node的个数
nodeLeafPodCount := make(map[string]int)
for _, node := range nodes {
nodeAnnotations := node.GetAnnotations()
if v, ok := nodeAnnotations["leafpod"]; ok {
nodeLeafPodCount[v]++
}
}
klog.Infof("nodeLeafPodCount: %v", nodeLeafPodCount)
// 3. 遍历node, 计算k值
for _, node := range nodes {
nodeAnnotations := node.GetAnnotations()
if v, ok := nodeAnnotations["leafpod"]; ok {
klog.Infof("node %s leafpod count: %d, k: %d", node.GetName(), nodeLeafPodCount[v], podGroupReplicas-nodeLeafPodCount[v])
podAnnotations[node.GetName()] = fmt.Sprintf("%d", nodeLeafPodCount[v]-podGroupReplicas)
}
}
// PreScore的时候,判断pod group实例的个数m,nodeInfo所属POD组的node的个数n,k = n -m, k越小则约倾向于调度到该node,k < 0, 则万不得已不要调度到该节点
// 将node对应k值记录到pod的annotation中
pod.SetAnnotations(podAnnotations)
return nil
}
func (n *NetworkSpeedPlugin) Score(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) (int64, *framework.Status) {
// 当k < 0时,即该node所属的leafpod不满足足够pod实例数的调度。当k > 0时,k值越小,调度到该node对整个集群的碎片化影响最小,优先调度
podAnnotations := pod.GetAnnotations()
k := podAnnotations[nodeName]
if k > 0 {
return 100 -k
}
return 0
}
引入volvano对调度器进行扩展
-
配置了volcano podgroup后可以支持按组调度。对于资源的利用率更高效。
image.png -
通过extendor 对volcano prioritize扩展点进行扩展从而实现同一leaf POD优先调度
image.png
参考:
1. https://blog.csdn.net/lin2ur/article/details/136400365
2. https://blog.csdn.net/Forever_wj/article/details/124849567
3. volcano/pkg/scheduler/plugins/extender/extender.go at master · volcano-sh/volcano (github.com)