kube-scheduler介紹
kube-schedulerkube-scheduler是 kubernetes 系統(tǒng)的核心組件之一,主要負(fù)責(zé)整個(gè)集群資源的調(diào)度功能,根據(jù)特定的調(diào)度算法和策略,將 Pod 調(diào)度到最優(yōu)的工作節(jié)點(diǎn)上面去,從而更加合理、更加充分的利用集群的資源。
kube-scheduler 是 kubernetes 的調(diào)度器,它的主要作用就是根據(jù)特定的調(diào)度算法和調(diào)度策略將 Pod 調(diào)度到合適的 Node 節(jié)點(diǎn)上去,是一個(gè)獨(dú)立的二進(jìn)制程序,啟動(dòng)之后會(huì)一直監(jiān)聽 API Server,獲取到 PodSpec.NodeName 為空的 Pod,對(duì)每個(gè) Pod 都會(huì)創(chuàng)建一個(gè) binding
調(diào)度主要分為以下幾個(gè)部分:
首先是預(yù)選過程,過濾掉不滿足條件的節(jié)點(diǎn),這個(gè)過程稱為Predicates然后是優(yōu)選過程,對(duì)通過的節(jié)點(diǎn)按照優(yōu)先級(jí)排序,稱之為Priorities最后從中選擇優(yōu)先級(jí)最高的節(jié)點(diǎn),如果中間任何一步驟有錯(cuò)誤,就直接返回錯(cuò)誤
scheduler調(diào)度流程
調(diào)度主要分為以下幾個(gè)部分:首先是預(yù)選過程,過濾掉不滿足條件的節(jié)點(diǎn),這個(gè)過程稱為Predicates然后是優(yōu)選過程,對(duì)通過的節(jié)點(diǎn)按照優(yōu)先級(jí)排序,稱之為Priorities最后從中選擇優(yōu)先級(jí)最高的節(jié)點(diǎn),如果中間任何一步驟有錯(cuò)誤,就直接返回錯(cuò)誤具體顯示為pod狀態(tài)會(huì)一直pending
詳細(xì)流程
首先,客戶端通過 API Server 的 REST API 或者 kubectl 工具創(chuàng)建 Pod 資源
API Server 收到用戶請(qǐng)求后,存儲(chǔ)相關(guān)數(shù)據(jù)到 etcd 數(shù)據(jù)庫中
調(diào)度器監(jiān)聽 API Server 查看為調(diào)度(bind)的 Pod 列表,循環(huán)遍歷地為每個(gè) Pod 嘗試分配節(jié)點(diǎn),這個(gè)分配過程就是我們上面提到的兩個(gè)階段:
預(yù)選階段(Predicates),過濾節(jié)點(diǎn),調(diào)度器用一組規(guī)則過濾掉不符合要求的 Node 節(jié)點(diǎn),比如 Pod 設(shè)置了資源的 request,那么可用資源比 Pod 需要的資源少的主機(jī)顯然就會(huì)被過濾掉
優(yōu)選階段(Priorities),為節(jié)點(diǎn)的優(yōu)先級(jí)打分,將上一階段過濾出來的 Node 列表進(jìn)行打分,調(diào)度器會(huì)考慮一些整體的優(yōu)化策略,比如把 Deployment 控制的多個(gè) Pod 副本分布到不同的主機(jī)上,使用最低負(fù)載的主機(jī)等等策略
經(jīng)過上面的階段過濾后選擇打分最高的 Node 節(jié)點(diǎn)和 Pod 進(jìn)行 binding 操作,然后將結(jié)果存儲(chǔ)到 etcd 中
最后被選擇出來的 Node 節(jié)點(diǎn)對(duì)應(yīng)的 kubelet 去執(zhí)行創(chuàng)建 Pod 的相關(guān)操作目前在插件化以后,scheduler更細(xì)化為多個(gè)階段
sort最先執(zhí)行的階段,該節(jié)點(diǎn)主要是對(duì)pod的排序,通過對(duì)PodPriority的比較進(jìn)行排序,將優(yōu)先度高的pod排在前面,也就是優(yōu)先級(jí)搶占策略 ,一般用在靜態(tài)pod這類需要高優(yōu)先級(jí)的pod上
Pre-filter 擴(kuò)展用于對(duì) Pod 的信息進(jìn)行預(yù)處理,或者檢查一些集群或 Pod 必須滿足的前提條件,如果 pre-filter 返回了 error,則調(diào)度過程終止。
Filter 擴(kuò)展用于排除那些不能運(yùn)行該 Pod 的節(jié)點(diǎn),對(duì)于每一個(gè)節(jié)點(diǎn),調(diào)度器將按順序執(zhí)行 filter 擴(kuò)展;如果任何一個(gè) filter 將節(jié)點(diǎn)標(biāo)記為不可選,則余下的 filter 擴(kuò)展將不會(huì)被執(zhí)行。調(diào)度器可以同時(shí)對(duì)多個(gè)節(jié)點(diǎn)執(zhí)行 filter 擴(kuò)展。
Post-filter 是一個(gè)通知類型的擴(kuò)展點(diǎn),調(diào)用該擴(kuò)展的參數(shù)是 filter 階段結(jié)束后被篩選為可選節(jié)點(diǎn)的節(jié)點(diǎn)列表,可以在擴(kuò)展中使用這些信息更新內(nèi)部狀態(tài),或者產(chǎn)生日志或 metrics 信息。
Scoring 擴(kuò)展用于為所有可選節(jié)點(diǎn)進(jìn)行打分,調(diào)度器將針對(duì)每一個(gè)節(jié)點(diǎn)調(diào)用 Soring 擴(kuò)展,評(píng)分結(jié)果是一個(gè)范圍內(nèi)的整數(shù)。在 normalize scoring 階段,調(diào)度器將會(huì)把每個(gè) scoring 擴(kuò)展對(duì)具體某個(gè)節(jié)點(diǎn)的評(píng)分結(jié)果和該擴(kuò)展的權(quán)重合并起來,作為最終評(píng)分結(jié)果。
Normalize scoring 擴(kuò)展在調(diào)度器對(duì)節(jié)點(diǎn)進(jìn)行最終排序之前修改每個(gè)節(jié)點(diǎn)的評(píng)分結(jié)果,注冊(cè)到該擴(kuò)展點(diǎn)的擴(kuò)展在被調(diào)用時(shí),將獲得同一個(gè)插件中的 scoring 擴(kuò)展的評(píng)分結(jié)果作為參數(shù),調(diào)度框架每執(zhí)行一次調(diào)度,都將調(diào)用所有插件中的一個(gè) normalize scoring 擴(kuò)展一次。
Reserve 是一個(gè)通知性質(zhì)的擴(kuò)展點(diǎn),有狀態(tài)的插件可以使用該擴(kuò)展點(diǎn)來獲得節(jié)點(diǎn)上為 Pod 預(yù)留的資源,該事件發(fā)生在調(diào)度器將 Pod 綁定到節(jié)點(diǎn)之前,目的是避免調(diào)度器在等待 Pod 與節(jié)點(diǎn)綁定的過程中調(diào)度新的 Pod 到節(jié)點(diǎn)上時(shí),發(fā)生實(shí)際使用資源超出可用資源的情況。(因?yàn)榻壎?Pod 到節(jié)點(diǎn)上是異步發(fā)生的)。這是調(diào)度過程的最后一個(gè)步驟,Pod 進(jìn)入 reserved 狀態(tài)以后,要么在綁定失敗時(shí)觸發(fā) Unreserve 擴(kuò)展,要么在綁定成功時(shí),由 Post-bind 擴(kuò)展結(jié)束綁定過程。
Permit 擴(kuò)展用于阻止或者延遲 Pod 與節(jié)點(diǎn)的綁定。Permit 擴(kuò)展可以做下面三件事中的一項(xiàng):
approve(批準(zhǔn)):當(dāng)所有的 permit 擴(kuò)展都 approve 了 Pod 與節(jié)點(diǎn)的綁定,調(diào)度器將繼續(xù)執(zhí)行綁定過程
deny(拒絕):如果任何一個(gè) permit 擴(kuò)展 deny 了 Pod 與節(jié)點(diǎn)的綁定,Pod 將被放回到待調(diào)度隊(duì)列,此時(shí)將觸發(fā) Unreserve 擴(kuò)展
wait(等待):如果一個(gè) permit 擴(kuò)展返回了 wait,則 Pod 將保持在 permit 階段,直到被其他擴(kuò)展 approve,如果超時(shí)事件發(fā)生,wait 狀態(tài)變成 deny,Pod 將被放回到待調(diào)度隊(duì)列,此時(shí)將觸發(fā) Unreserve 擴(kuò)展
Pre-bind 擴(kuò)展用于在 Pod 綁定之前執(zhí)行某些邏輯。例如,pre-bind 擴(kuò)展可以將一個(gè)基于網(wǎng)絡(luò)的數(shù)據(jù)卷掛載到節(jié)點(diǎn)上,以便 Pod 可以使用。如果任何一個(gè) pre-bind 擴(kuò)展返回錯(cuò)誤,Pod 將被放回到待調(diào)度隊(duì)列,此時(shí)將觸發(fā) Unreserve 擴(kuò)展。
Bind 擴(kuò)展用于將 Pod 綁定到節(jié)點(diǎn)上:只有所有的 pre-bind 擴(kuò)展都成功執(zhí)行了,bind 擴(kuò)展才會(huì)執(zhí)行 調(diào)度框架按照 bind 擴(kuò)展注冊(cè)的順序逐個(gè)調(diào)用 bind 擴(kuò)展 具體某個(gè) bind 擴(kuò)展可以選擇處理或者不處理該 Pod 如果某個(gè) bind 擴(kuò)展處理了該 Pod 與節(jié)點(diǎn)的綁定,余下的 bind 擴(kuò)展將被忽略
Post-bind 是一個(gè)通知性質(zhì)的擴(kuò)展:Post-bind 擴(kuò)展在 Pod 成功綁定到節(jié)點(diǎn)上之后被動(dòng)調(diào)用 Post-bind 擴(kuò)展是綁定過程的最后一個(gè)步驟,可以用來執(zhí)行資源清理的動(dòng)作
Unreserve 是一個(gè)通知性質(zhì)的擴(kuò)展,如果為 Pod 預(yù)留了資源,Pod 又在被綁定過程中被拒絕綁定,則 unreserve 擴(kuò)展將被調(diào)用。Unreserve 擴(kuò)展應(yīng)該釋放已經(jīng)為 Pod 預(yù)留的節(jié)點(diǎn)上的計(jì)算資源。在一個(gè)插件中,reserve 擴(kuò)展和 unreserve 擴(kuò)展應(yīng)該成對(duì)出現(xiàn)。
scheduler默認(rèn)調(diào)度算法
scheduler中默認(rèn)加載了許多調(diào)度算法具體如下
PodFitsResources:節(jié)點(diǎn)上剩余的資源是否大于 Pod 請(qǐng)求的資源
PodFitsHost:如果 Pod 指定了 NodeName,檢查節(jié)點(diǎn)名稱是否和 NodeName 匹配
PodFitsHostPorts:節(jié)點(diǎn)上已經(jīng)使用的 port 是否和 Pod 申請(qǐng)的 port 沖突
PodSelectorMatches:過濾掉和 Pod 指定的 label 不匹配的節(jié)點(diǎn)
NoDiskConflict:已經(jīng) mount 的 volume 和 Pod 指定的 volume 不沖突,除非它們都是只讀的
CheckNodeDiskPressure:檢查節(jié)點(diǎn)磁盤空間是否符合要求
CheckNodeMemoryPressure:檢查節(jié)點(diǎn)內(nèi)存是否夠用
scheduler代碼相關(guān)解析
kubernetes 調(diào)度器的源碼位于 kubernetes/pkg/scheduler中,具體結(jié)果如下所示
kube-scheduler的入口程序,對(duì)應(yīng)的代碼在 cmd/kube-scheduler/scheduler.go。
func main() {
? ? rand.Seed(time.Now().UnixNano())
? ? command := app.NewSchedulerCommand()
? ? // TODO: once we switch everything over to Cobra commands, we can go back to calling
? ? // utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
? ? // normalize func and add the go flag set by hand.
? ? pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
? ? // utilflag.InitFlags()
? ? logs.InitLogs()
? ? defer logs.FlushLogs()
? ? if err := command.Execute(); err != nil {
? ? ? ? os.Exit(1)
? ? }
}
在代碼中我們可以看到,mian方法在初始化時(shí),率先執(zhí)行了 command := app.NewSchedulerCommand()方法,在這個(gè)方法中可以看到支持參數(shù)Option,而Option則為out-of-tree的framework插件算法
// NewSchedulerCommand creates a *cobra.Command object with default parameters and registryOptions
func NewSchedulerCommand(registryOptions ...Option) *cobra.Command {
? ? opts, err := options.NewOptions()
? ? if err != nil {
? ? ? ? klog.Fatalf("unable to initialize command options: %v", err)
? ? }
? ? cmd := &cobra.Command{
? ? ? ? Use: "kube-scheduler",
? ? ? ? Long: `The Kubernetes scheduler is a control plane process which assigns
Pods to Nodes. The scheduler determines which Nodes are valid placements for
each Pod in the scheduling queue according to constraints and available
resources. The scheduler then ranks each valid Node and binds the Pod to a
suitable Node. Multiple different schedulers may be used within a cluster;
kube-scheduler is the reference implementation.
See [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/)
for more information about scheduling and the kube-scheduler component.`,
? ? ? ? Run: func(cmd *cobra.Command, args []string) {
? ? ? ? ? ? if err := runCommand(cmd, opts, registryOptions...); err != nil {
? ? ? ? ? ? ? ? fmt.Fprintf(os.Stderr, "%v\n", err)
? ? ? ? ? ? ? ? os.Exit(1)
? ? ? ? ? ? }
? ? ? ? },
? ? ? ? Args: func(cmd *cobra.Command, args []string) error {
? ? ? ? ? ? for _, arg := range args {
? ? ? ? ? ? ? ? if len(arg) > 0 {
? ? ? ? ? ? ? ? ? ? return fmt.Errorf("%q does not take any arguments, got %q", cmd.CommandPath(), args)
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? return nil
? ? ? ? },
? ? }
? ? fs := cmd.Flags()
? ? namedFlagSets := opts.Flags()
? ? verflag.AddFlags(namedFlagSets.FlagSet("global"))
? ? globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name())
? ? for _, f := range namedFlagSets.FlagSets {
? ? ? ? fs.AddFlagSet(f)
? ? }
? ? usageFmt := "Usage:\n? %s\n"
? ? cols, _, _ := term.TerminalSize(cmd.OutOrStdout())
? ? cmd.SetUsageFunc(func(cmd *cobra.Command) error {
? ? ? ? fmt.Fprintf(cmd.OutOrStderr(), usageFmt, cmd.UseLine())
? ? ? ? cliflag.PrintSections(cmd.OutOrStderr(), namedFlagSets, cols)
? ? ? ? return nil
? ? })
? ? cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
? ? ? ? fmt.Fprintf(cmd.OutOrStdout(), "%s\n\n"+usageFmt, cmd.Long, cmd.UseLine())
? ? ? ? cliflag.PrintSections(cmd.OutOrStdout(), namedFlagSets, cols)
? ? })
? ? cmd.MarkFlagFilename("config", "yaml", "yml", "json")
? ? return cmd
}
首先執(zhí)行 opts, err := options.NewOptions()函數(shù),該函數(shù)初始化各個(gè)模塊的默認(rèn)配置,例如HTTP或HTTPS服務(wù)等
// NewOptions returns default scheduler app options.
func NewOptions() (*Options, error) {
? ? cfg, err := newDefaultComponentConfig()
? ? if err != nil {
? ? ? ? return nil, err
? ? }
? ? hhost, hport, err := splitHostIntPort(cfg.HealthzBindAddress)
? ? if err != nil {
? ? ? ? return nil, err
? ? }
? ? o := &Options{
? ? ? ? ComponentConfig: *cfg,
? ? ? ? SecureServing:? apiserveroptions.NewSecureServingOptions().WithLoopback(),
? ? ? ? CombinedInsecureServing: &CombinedInsecureServingOptions{
? ? ? ? ? ? Healthz: (&apiserveroptions.DeprecatedInsecureServingOptions{
? ? ? ? ? ? ? ? BindNetwork: "tcp",
? ? ? ? ? ? }).WithLoopback(),
? ? ? ? ? ? Metrics: (&apiserveroptions.DeprecatedInsecureServingOptions{
? ? ? ? ? ? ? ? BindNetwork: "tcp",
? ? ? ? ? ? }).WithLoopback(),
? ? ? ? ? ? BindPort:? ? hport,
? ? ? ? ? ? BindAddress: hhost,
? ? ? ? },
? ? ? ? Authentication: apiserveroptions.NewDelegatingAuthenticationOptions(),
? ? ? ? Authorization:? apiserveroptions.NewDelegatingAuthorizationOptions(),
? ? ? ? Deprecated: &DeprecatedOptions{
? ? ? ? ? ? UseLegacyPolicyConfig:? ? ? ? ? false,
? ? ? ? ? ? PolicyConfigMapNamespace:? ? ? metav1.NamespaceSystem,
? ? ? ? ? ? SchedulerName:? ? ? ? ? ? ? ? ? corev1.DefaultSchedulerName,
? ? ? ? ? ? HardPodAffinitySymmetricWeight: 1,
? ? ? ? },
? ? ? ? Metrics: metrics.NewOptions(),
? ? ? ? Logs:? ? logs.NewOptions(),
? ? }
? ? o.Authentication.TolerateInClusterLookupFailure = true
? ? o.Authentication.RemoteKubeConfigFileOptional = true
? ? o.Authorization.RemoteKubeConfigFileOptional = true
? ? o.Authorization.AlwaysAllowPaths = []string{"/healthz"}
? ? // Set the PairName but leave certificate directory blank to generate in-memory by default
? ? o.SecureServing.ServerCert.CertDirectory = ""
? ? o.SecureServing.ServerCert.PairName = "kube-scheduler"
? ? o.SecureServing.BindPort = kubeschedulerconfig.DefaultKubeSchedulerPort
? ? return o, nil
interface.go文件interface.go文件中定義了scheduler插件中各個(gè)組件的接口信息如PreFilterPlugin FilterPlugin等,我們所有的自定義插件(out of tree)都需要繼承這個(gè)接口
plugins文件夾在插件化以后,所有的調(diào)度策略代碼都在該文件夾下,如imagelocality等。我們?nèi)绻枰獢U(kuò)展in-tree插件則也需要在該文件夾下實(shí)現(xiàn)對(duì)應(yīng)的方法如我們要實(shí)現(xiàn)的imagearch調(diào)度策略就需要在該文件夾下實(shí)現(xiàn)interface.go中對(duì)應(yīng)的接口,實(shí)現(xiàn)filter接口
factory.go文件
registry.go文件legacy_registry.go文件generic_scheduler.go文件
in-tree插件實(shí)現(xiàn)步驟
1.在/pkg/scheduler/framework/plugins目錄下建立自己的插件文件夾,參考源碼自帶插件編寫chajian.go以及BUILD文件,實(shí)現(xiàn)擴(kuò)展點(diǎn)對(duì)應(yīng)的接口2.修改/pkg/scheduler/framework/plugins/registry.go 在NewInTreeRegistry增加插件注冊(cè)3.修改/pkg/scheduler/framework/plugins/legacy_registry.go 增加有關(guān)枚舉和registerPredicateConfigProducer4.修改/pkg/scheduler/algorithmprovider/registry.go,在相應(yīng)的pluginSet里增加你自己實(shí)現(xiàn)的擴(kuò)展5.修改/pkg/scheduler/algorithmprovider/BUILD,在deps里增加你的插件目錄,如果不是通過Google的brzael編譯,這一步不需要6.編譯 make all WHAT=cmd/kube-scheduler,在./_output/bin目錄中可以看到編譯完成的kube-scheduler可執(zhí)行文件7.構(gòu)建kube-scheduler鏡像,直接使用原來的鏡像作為基礎(chǔ)鏡像,覆蓋/usr/local/bin里的kube-scheduler文件即可8.替換kube-scheduler鏡像并進(jìn)行測(cè)試
scheduler extender擴(kuò)展
1.16版本以后已經(jīng)不推薦使用extender擴(kuò)展的形式實(shí)現(xiàn)原理是通過實(shí)現(xiàn)了reset接口的形式,所謂的scheduler extender其實(shí)就是一個(gè)可配置的 Webhook 而已,里面包含 過濾器 和 優(yōu)先級(jí) 兩個(gè)端點(diǎn),分別對(duì)應(yīng)調(diào)度周期中的兩個(gè)主要階段(過濾和打分)。
scheduler framework擴(kuò)展
1.15以后推薦的實(shí)現(xiàn)方式scheduler插件化以后,主流的擴(kuò)展方式為framework擴(kuò)展,目前社區(qū)基于framework形式建立了項(xiàng)目https://github.com/kubernetes-sigs/scheduler-plugins,在該項(xiàng)目中增加了許多scheduler調(diào)度算法調(diào)度框架定義了一組擴(kuò)展點(diǎn),用戶可以實(shí)現(xiàn)擴(kuò)展點(diǎn)定義的接口(實(shí)現(xiàn)pkg/scheduler/framework/interface下Framework的接口)來定義自己的調(diào)度邏輯(我們稱之為擴(kuò)展),并將擴(kuò)展注冊(cè)到擴(kuò)展點(diǎn)上,調(diào)度框架在執(zhí)行調(diào)度工作流時(shí),遇到對(duì)應(yīng)的擴(kuò)展點(diǎn)時(shí),將調(diào)用用戶注冊(cè)的擴(kuò)展。framework的實(shí)現(xiàn)方式如上述源碼分析,我們需要在啟動(dòng)命令時(shí),增加我們自己實(shí)現(xiàn)的plugin插件
? ? command := app.NewSchedulerCommand(
? ? ? ? app.WithPlugin(sample.Name, sample.New),?
? ? )
type PluginFactory = func(configuration *runtime.Unknown, f FrameworkHandle) (Plugin, error)如我們的業(yè)務(wù)需求是需要實(shí)現(xiàn)filter接口,則我們可以基于上次的源碼分析中,在官方提供的https://github.com/kubernetes-sigs/scheduler-plugins中,實(shí)現(xiàn)對(duì)應(yīng)的接口。并執(zhí)行make文件等創(chuàng)建出對(duì)應(yīng)的二進(jìn)制文件構(gòu)建相應(yīng)的鏡像。如果只是想在默認(rèn)的default-schedule中增加算法,則配置文件中只需要如此配置
如果是想生成新的調(diào)度算法則要增加以下諸多配置ClusterRole、ServiceAccount、ClusterRoleBinding、部署ConfigMap,包含一個(gè)KubeSchedulerConfiguration類型的配置文件以及啟動(dòng)插件用的deployment(正式環(huán)境建議使用靜態(tài)pod的形式)demo如下:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
? name: sample-scheduler-clusterrole
rules:
? - apiGroups:
? ? ? - ""
? ? resources:
? ? ? - endpoints
? ? ? - events
? ? verbs:
? ? ? - create
? ? ? - get
? ? ? - update
? - apiGroups:
? ? ? - ""
? ? resources:
? ? ? - nodes
? ? verbs:
? ? ? - get
? ? ? - list
? ? ? - watch
? - apiGroups:
? ? ? - ""
? ? resources:
? ? ? - pods
? ? verbs:
? ? ? - delete
? ? ? - get
? ? ? - list
? ? ? - watch
? ? ? - update
? - apiGroups:
? ? ? - ""
? ? resources:
? ? ? - bindings
? ? ? - pods/binding
? ? verbs:
? ? ? - create
? - apiGroups:
? ? ? - ""
? ? resources:
? ? ? - pods/status
? ? verbs:
? ? ? - patch
? ? ? - update
? - apiGroups:
? ? ? - ""
? ? resources:
? ? ? - replicationcontrollers
? ? ? - services
? ? verbs:
? ? ? - get
? ? ? - list
? ? ? - watch
? - apiGroups:
? ? ? - apps
? ? ? - extensions
? ? resources:
? ? ? - replicasets
? ? verbs:
? ? ? - get
? ? ? - list
? ? ? - watch
? - apiGroups:
? ? ? - apps
? ? resources:
? ? ? - statefulsets
? ? verbs:
? ? ? - get
? ? ? - list
? ? ? - watch
? - apiGroups:
? ? ? - policy
? ? resources:
? ? ? - poddisruptionbudgets
? ? verbs:
? ? ? - get
? ? ? - list
? ? ? - watch
? - apiGroups:
? ? ? - ""
? ? resources:
? ? ? - persistentvolumeclaims
? ? ? - persistentvolumes
? ? verbs:
? ? ? - get
? ? ? - list
? ? ? - watch
? - apiGroups:
? ? ? - ""
? ? resources:
? ? ? - configmaps
? ? verbs:
? ? ? - get
? ? ? - list
? ? ? - watch
? - apiGroups:
? ? ? - "storage.k8s.io"
? ? resources:
? ? ? - storageclasses
? ? ? - csinodes
? ? verbs:
? ? ? - get
? ? ? - list
? ? ? - watch
? - apiGroups:
? ? ? - "coordination.k8s.io"
? ? resources:
? ? ? - leases
? ? verbs:
? ? ? - create
? ? ? - get
? ? ? - list
? ? ? - update
? - apiGroups:
? ? ? - "events.k8s.io"
? ? resources:
? ? ? - events
? ? verbs:
? ? ? - create
? ? ? - patch
? ? ? - update
---
apiVersion: v1
kind: ServiceAccount
metadata:
? name: sample-scheduler-sa
? namespace: kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
? name: sample-scheduler-clusterrolebinding
? namespace: kube-system
roleRef:
? apiGroup: rbac.authorization.k8s.io
? kind: ClusterRole
? name: sample-scheduler-clusterrole
subjects:
- kind: ServiceAccount
? name: sample-scheduler-sa
? namespace: kube-system
---
apiVersion: v1
kind: ConfigMap
metadata:
? name: scheduler-config
? namespace: kube-system
data:
? scheduler-config.yaml: |
? ? apiVersion: kubescheduler.config.k8s.io/v1alpha1
? ? kind: KubeSchedulerConfiguration
? ? schedulerName: sample-scheduler
? ? leaderElection:
? ? ? leaderElect: true
? ? ? lockObjectName: sample-scheduler
? ? ? lockObjectNamespace: kube-system
? ? plugins:
? ? ? preFilter:
? ? ? ? enabled:
? ? ? ? - name: "sample-plugin"
? ? ? filter:
? ? ? ? enabled:
? ? ? ? - name: "sample-plugin"
? ? ? preBind:
? ? ? ? enabled:
? ? ? ? - name: "sample-plugin"
? ? pluginConfig:
? ? - name: "sample-plugin"
? ? ? args:
? ? ? ? favorite_color: "#326CE5"
? ? ? ? favorite_number: 7
? ? ? ? thanks_to: "thockin"
---
apiVersion: apps/v1
kind: Deployment
metadata:
? name: sample-scheduler
? namespace: kube-system
? labels:
? ? component: sample-scheduler
spec:
? replicas: 1
? selector:
? ? matchLabels:
? ? ? component: sample-scheduler
? template:
? ? metadata:
? ? ? labels:
? ? ? ? component: sample-scheduler
? ? spec:
? ? ? serviceAccount: sample-scheduler-sa
? ? ? priorityClassName: system-cluster-critical
? ? ? volumes:
? ? ? ? - name: scheduler-config
? ? ? ? ? configMap:
? ? ? ? ? ? name: scheduler-config
? ? ? containers:
? ? ? ? - name: scheduler-ctrl
? ? ? ? ? image: cnych/sample-scheduler:v0.1.6
? ? ? ? ? imagePullPolicy: IfNotPresent
? ? ? ? ? args:
? ? ? ? ? ? - sample-scheduler-framework
? ? ? ? ? ? - --config=/etc/kubernetes/scheduler-config.yaml
? ? ? ? ? ? - --v=3
? ? ? ? ? resources:
? ? ? ? ? ? requests:
? ? ? ? ? ? ? cpu: "50m"
? ? ? ? ? volumeMounts:
? ? ? ? ? ? - name: scheduler-config
? ? ? ? ? ? ? mountPath: /etc/kubernetes
這樣在我們?cè)诓渴鹑萜鲿r(shí),只需要通過手動(dòng)指定了一個(gè) schedulerName 的字段,將其設(shè)置成上面我們自定義的調(diào)度器名稱 sample-scheduler即可。