1. 程式人生 > 其它 >kube-scheduler排程器排程框架原始碼學習篇1

kube-scheduler排程器排程框架原始碼學習篇1

目錄

queueSort擴充套件點

概述

該擴充套件點需要完成的工作為:對兩個pod的排程優先順序進行比較

該擴充套件點有且只有一個外掛實現,預設的實現外掛為下面的PrioritySort外掛。

PrioritySort

pkg/scheduler/framework/plugins/queuesort/priority_sort.go

// Less is the function used by the activeQ heap algorithm to sort pods.
// It sorts pods based on their priority. When priorities are equal, it uses
// PodQueueInfo.timestamp.
func (pl *PrioritySort) Less(pInfo1, pInfo2 *framework.QueuedPodInfo) bool {
	p1 := corev1helpers.PodPriority(pInfo1.Pod)
	p2 := corev1helpers.PodPriority(pInfo2.Pod)
	return (p1 > p2) || (p1 == p2 && pInfo1.Timestamp.Before(pInfo2.Timestamp))
}
  • 核心邏輯:通過Less方法比較兩個pod的排程優先順序,如果pod1的優先順序比pod2優先順序高,則返回true

  • 比較的依據是先比較podSpec裡的priority,priority越高則優先順序越高;如果priority相等,則時間早的排序靠前

  • podSpec裡的priority欄位在pod到達排程器之前由pod關聯的PriorityClass物件解析而來

  • 一個排程器框架中,只有一個queueSort plugin可以被啟用,程式碼中預設啟用了第一個

裝載過程

pkg/scheduler/factory.go

Configurator.create()

資料的流動:config->profile->framework.Framework->QueueSortFunc()->framework.LessFunc

preFilter擴充套件點

概述

對於每一個排程框架下的plugin,處理該擴充套件點的大致套路如下:

  • 關鍵輸入:cycleState,pod
    • cycleState為各個plugin的共用儲存,其包裝了一個map[string]StateData,可以通過Read、Write方法安全地讀寫
    • pod即為v1 api組的Pod結構體,可以從中取得pod的資訊
  • 輸出:正常情況返回nil,有錯誤的情況,通過framework.NewStatus()返回類似於Error、Unschedulable等狀態
  • 核心操作:每個外掛定義一個獨有的key,以及一個獨有的StateData,按照需求將需要後續使用的資料封裝到StateData中,寫入到cycleState這個map中

以下為不同外掛對該擴充套件點的具體實現

NodeResourcesFit

pkg/scheduler/framework/plugins/noderesources/fit.go

func computePodResourceRequest(pod *v1.Pod) *preFilterState {
	result := &preFilterState{}
	for _, container := range pod.Spec.Containers {
		result.Add(container.Resources.Requests)
	}

	// take max_resource(sum_pod, any_init_container)
	for _, container := range pod.Spec.InitContainers {
		result.SetMaxResource(container.Resources.Requests)
	}

	// If Overhead is being utilized, add to the total requests for the pod
	if pod.Spec.Overhead != nil && utilfeature.DefaultFeatureGate.Enabled(features.PodOverhead) {
		result.Add(pod.Spec.Overhead)
	}

	return result
}
  • 核心邏輯:對於一個進入排程過程的pod,計算其整體的資源需求量,為後續流程做準備

  • 由於init container順序啟動,所以對於它們的同種資源需求取最大值;普通container的同種資源需求累加

  • 除了統計一個pod內所有容器的資源需求外,排程器還支援將pod本身除容器以外的額外資源開銷納入排程流程中,詳情見Pod開銷 。因此函式的最後會檢查該特性門控是否開啟,pod是否有overhead欄位,如果滿足條件,會把這類資源消耗也納入統計中

NodePorts

pkg/scheduler/framework/plugins/nodeports/node_ports.go

// getContainerPorts returns the used host ports of Pods: if 'port' was used, a 'port:true' pair
// will be in the result; but it does not resolve port conflict.
func getContainerPorts(pods ...*v1.Pod) []*v1.ContainerPort {
	ports := []*v1.ContainerPort{}
	for _, pod := range pods {
		for j := range pod.Spec.Containers {
			container := &pod.Spec.Containers[j]
			for k := range container.Ports {
				ports = append(ports, &container.Ports[k])
			}
		}
	}
	return ports
}
  • 核心邏輯:遍歷pod的所有容器的所有埠,將其展平後放入一個slice中

PodTopologySpread

pkg/scheduler/framework/plugins/podtopologyspread/filtering.go

該擴充套件點主要處理pod的拓撲域打散資訊,略

InterPodAffinity

pkg/scheduler/framework/plugins/interpodaffinity/filtering.go

該擴充套件點主要處理pod的affinity和antifinity資訊,略

VolumeBinding

pkg/scheduler/framework/plugins/volumebinding/volume_binding.go

  • 核心邏輯:遍歷podSpec的volume,判斷是否用到了pvc,如果沒有用到,則該擴充套件點沒有意義,跳過;如果有pvc,則解析pvc的資訊

  • 解析出的PVC狀態分為三類:bound, tobind, unboundImmediate,其中的unboundImmediate狀態屬於非正常狀態,如果存在這類pvc,會直接返回錯誤資訊pod has unbound immediate PersistentVolumeClaims,並將pod重新放回排程佇列

  • 最後會初始化一個map:podVolumesByNode,在filter擴充套件點階段會用到

NodeAffinity

pkg/scheduler/framework/plugins/nodeaffinity/node_affinity.go

func GetRequiredNodeAffinity(pod *v1.Pod) RequiredNodeAffinity {
	var selector labels.Selector
	if len(pod.Spec.NodeSelector) > 0 {
		selector = labels.SelectorFromSet(pod.Spec.NodeSelector)
	}
	// Use LazyErrorNodeSelector for backwards compatibility of parsing errors.
	var affinity *LazyErrorNodeSelector
	if pod.Spec.Affinity != nil &&
		pod.Spec.Affinity.NodeAffinity != nil &&
		pod.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
		affinity = NewLazyErrorNodeSelector(pod.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution)
	}
	return RequiredNodeAffinity{labelSelector: selector, nodeSelector: affinity}
}
  • 核心邏輯:解析podSpec裡的nodeSelector欄位和nodeAffinity欄位,儲存
  • 此處只處理了RequiredDuringSchedulingIgnoredDuringExecution型別的nodeAffinity