1.9中,kube-scheduler仍然是做爲一個「plugin」放在k8s代碼中,在k8s根目錄下的plugin目錄中,cmd/kube-scheduler目錄是其編譯入口,pkg/scheduler目錄是其主要核心代碼。如圖:算法
在即將發佈的1.10中,社區將kube-scheduler從plugin中移出,嵌入到與api-server、kubelet等組件平級的目錄。也即根目錄下的cmd、pkg目錄:api
調度器能夠在啓動時指定其算法的來源。算法來源有三種:a)本地policy文件;b)policy configMap;c)指定提供者。 ide
對象*scheduler.Config
記錄了算法來源,當啓動參數中policy相關參數不爲空時,會從相應的文件或者configMap中讀取調度策略;不然檢查algorithm-provider
參數,這個參數會列出當前可用的provider,若是沒有明確指定,那麼代碼將啓動默認的provider:default函數
從policy讀取的調度策略,其內容是一個policy
結構ui
type Policy struct { metav1.TypeMeta // Holds the information to configure the fit predicate functions Predicates []PredicatePolicy // Holds the information to configure the priority functions Priorities []PriorityPolicy // Holds the information to communicate with the extender(s) ExtenderConfigs []ExtenderConfig // RequiredDuringScheduling affinity is not symmetric, but there is an implicit PreferredDuringScheduling affinity rule // corresponding to every RequiredDuringScheduling affinity rule. // HardPodAffinitySymmetricWeight represents the weight of implicit PreferredDuringScheduling affinity rule, in the range 1-100. HardPodAffinitySymmetricWeight int32 }
代碼會直接根據policy
的內容,調用CreateFromKeys
方法去構建最終的scheduler
spa
當沒有指定policy時,若是沒有指定provider,最後會執行下面這個函數code
// Create creates a scheduler with the default algorithm provider. func (f *configFactory) Create() (*scheduler.Config, error) { return f.CreateFromProvider(DefaultProvider) }
隨後也會調用CreateFromKeys
方法構建最終的genericScheduler
orm
上面的過程當中,會最終都調用到func (f *configFactory) CreateFromKeys
。 這個函數將參數中的predicate算法、priority算法等注入到調用鏈中,這個調用鏈中的函數,會在每次調度pod時被調用。兩個調用鏈分別是genericScheduler
結構中的:server
type genericScheduler struct { ... predicates map[string]algorithm.FitPredicate ... prioritizers []algorithm.PriorityConfig ... }
當經過policy啓動時,CreateFromKeys
方法的參數中的算法都記錄到了policy
對象中的成員變量裏。而若是經過指定provider啓動,參數中的算法都來自provider 的init
方法。對象
咱們經過閱讀provider的init
方法,以及init過程當中引用到的plugins.go
的一些方法,就能知道大概的流程是:
1.調度器的algorithmprovider
目錄下存放了一個defaults
provider,以及一個plugins.go
的文件,plugins.go
提供了provider登記須要的一些方法。
2.plugins.go
中維護了一個全局的map:algorithmProviderMap
, 這個map的key即provider的名字,value是一個結構,維護了兩個string集合,用於記錄該provider須要的prodicate算法名和priority算法名:
type AlgorithmProviderConfig struct {
FitPredicateKeys sets.String PriorityFunctionKeys sets.String
}
3.provider的init
方法中調用factory.RegisterAlgorithmProvider
方法,向上文的map中登記本身。登記時會提供本身自己包含的兩類算法的集合。可參考defaults/defaults.go
中的:
registerAlgorithmProvider(defaultPredicates(), defaultPriorities())
defaultPredicates()
、defaultPriorities()
兩個函數返回的就是兩個集合,只有集合中的字符串對應的算法纔會注入到genericScheduler
,從而被調用。而這裏字符串和真實算法function的映射關係,分別記錄在兩個全局map:
fitPredicateMap
和priorityFunctionMap
中,defaults.go
中 調用的RegisterFitPredicate
、RegisterMandatoryFitPredicate
等許多方法均會將算法名和算法方法的映射記錄到map中。
這裏注意到,並非全部的算法都會登記到集合中的,這裏PodFitsPorts
、PodFitsHostPorts
、PodFitsResources
等算法只是記錄到map中,並無登記到set中,可是也被調用了,這是由於這些算法都屬於GeneralPredicates
算法,在GeneralPredicates
算法中被調用。而代碼中下文咱們會看到在default provider 中登記了GeneralPredicates
算法
總結下來就是:要將predicate算法或prioirity算法的映射關係註冊到全局map中,而後將算法名登記到provider中,再將provider登記到全局map中,在啓動scheduler時指定provider的name,就可使用相應的provider名下登記的算法來構造genericScheduler
。
上文中說起的plugins.go
中, 還提供了一些額外的方法,好比:InsertPredicateKeyToAlgoProvider
方法,能夠將某個算法登記到指定的provider中。
所以,咱們只要在init時將自定義的算法先註冊到全局map中:
func init() { factory.RegisterFitPredicate("PodFitsNeteaseResources", predicates.PodFitsNeteaseResources)) }
而後在defaults/defaults.go
的init方法尾部,調用InsertPredicateKeyToAlgoProvider
將帶有自定義算法的名字的set加入default provider便可:
factory.InsertPredicateKeyToAlgoProvider(factory.DefaultProvider, sets.NewString("PodFitsNeteaseResources"))
上述是一個比較規範的註冊方式,也有投機取巧的方式,好比在default provider 的func defaultPredicates()
方法尾部增長一行:
factory.RegisterFitPredicate("PodFitsNeteaseResources", predicates.PodFitsNeteaseResources))