小編今天帶大家了解怎么進(jìn)行Scheduling Framework 應(yīng)用實(shí)踐,文中知識(shí)點(diǎn)介紹的非常詳細(xì)。覺(jué)得有幫助的朋友可以跟著小編一起瀏覽文章的內(nèi)容,希望能夠幫助更多想解決這個(gè)問(wèn)題的朋友找到問(wèn)題的答案,下面跟著小編一起深入學(xué)習(xí)“怎么進(jìn)行Scheduling Framework 應(yīng)用實(shí)踐”的知識(shí)吧。
專注于為中小企業(yè)提供網(wǎng)站設(shè)計(jì)制作、成都做網(wǎng)站服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)斗門免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了千余家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
Kubernetes 是目前最受歡迎的?動(dòng)化容器管理平臺(tái),它提供了靈活的聲明式容器編排、自動(dòng)部署、資源調(diào)度等功能。Kube-Scheduler 作為 Kubernetes 的核心組件之一,主要負(fù)責(zé)整個(gè)集群資源的調(diào)度功能,根據(jù)特定的調(diào)度算法和策略,將 Pod 調(diào)度到最優(yōu)的工作節(jié)點(diǎn)上面去,從而更加合理、充分地利用集群資源。但是隨著 Kubernetes 部署的任務(wù)類型越來(lái)越多,原生 Kube-Scheduler 已經(jīng)不能應(yīng)對(duì)多樣的調(diào)度需求:比如機(jī)器學(xué)習(xí)、深度學(xué)習(xí)訓(xùn)練任務(wù)對(duì)于協(xié)同調(diào)度功能的需求;高性能計(jì)算作業(yè),基因計(jì)算工作流對(duì)于一些動(dòng)態(tài)資源 GPU、網(wǎng)絡(luò)、存儲(chǔ)卷的動(dòng)態(tài)資源綁定需求等。因此自定義 Kubernetes 調(diào)度器的需求愈發(fā)迫切,下面討論了擴(kuò)展 Kubernetes 調(diào)度程序的各種方法,然后使用目前最佳的擴(kuò)展方式 Scheduling Framework,演示如何擴(kuò)展 Scheduler。
如下圖所示,調(diào)度框架提供了豐富的擴(kuò)展點(diǎn),在這幅圖中,F(xiàn)ilter 相當(dāng)于之前 Predicate 預(yù)選模塊, Score 相當(dāng)于 Priority 優(yōu)選模塊,每一個(gè)擴(kuò)展點(diǎn)模塊都提供了接口,我們可以實(shí)現(xiàn)擴(kuò)展點(diǎn)定義的接口來(lái)實(shí)現(xiàn)自己的調(diào)度邏輯,并將實(shí)現(xiàn)的插件注冊(cè)到擴(kuò)展點(diǎn)。
Scheduling Framework 在執(zhí)行調(diào)度流程時(shí),當(dāng)運(yùn)行到擴(kuò)展點(diǎn)時(shí),會(huì)調(diào)用我們注冊(cè)的插件,通過(guò)執(zhí)行自定義插件的策略,滿足調(diào)度需求。此外,一個(gè)插件可以在多個(gè)擴(kuò)展點(diǎn)注冊(cè),用以執(zhí)行更復(fù)雜或有狀態(tài)的任務(wù)。
Scheduling Framework 每次調(diào)度一個(gè) Pod ,都分為調(diào)度周期和綁定周期兩部分來(lái)執(zhí)行,調(diào)度周期為 Pod 選擇一個(gè)節(jié)點(diǎn),綁定周期則調(diào)用 Apiserver,用選好的 Node,更新 Pod 的 spec.nodeName 字段。調(diào)度周期和綁定周期統(tǒng)稱為 “Scheduling Context” (調(diào)度上下文)。調(diào)度周期是串行運(yùn)行的,同一時(shí)間只能有一個(gè) Pod 被調(diào)度,是線程安全的;而綁定周期因?yàn)樾枰L問(wèn) Apiserver 的接口,耗時(shí)較長(zhǎng),為了提高調(diào)度的效率,需要異步執(zhí)行,即同一時(shí)間,可執(zhí)行多個(gè) bind 操作,是非線程安全的。
如果 Pod 被確定為不可調(diào)度或存在內(nèi)部錯(cuò)誤,那么調(diào)度周期或綁定周期將被中止。Pod 將返回隊(duì)列并等待下一次重試。如果一個(gè)綁定周期被終止,它將觸發(fā) Reserve 插件中的 UnReserve 方法。
用于給調(diào)度隊(duì)列排序,默認(rèn)情況下,所有的 Pod 都會(huì)被放到一個(gè)隊(duì)列中,此擴(kuò)展用于對(duì) Pod 的待調(diào)度隊(duì)列進(jìn)行排序,以決定先調(diào)度哪個(gè) Pod,QueueSort 擴(kuò)展本質(zhì)上只需要實(shí)現(xiàn)一個(gè)方法 Less(Pod1, Pod2) 用于比較兩個(gè) Pod 誰(shuí)更優(yōu)先獲得調(diào)度,同一時(shí)間點(diǎn)只能有一個(gè) QueueSort 插件生效。
用于對(duì) Pod 的信息進(jìn)行預(yù)處理,或者檢查一些集群或 Pod 必須滿足的前提條件,比如 Pod 是否包含指定的 annotations 或 labels,如果 PreFilter 返回了 error ,則調(diào)度過(guò)程終止。
用于排除那些不能運(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í)行。如果對(duì)默認(rèn)調(diào)度器提供的預(yù)選規(guī)則不滿意,可以在配置中禁用默認(rèn)調(diào)度器的預(yù)選算法,在這個(gè)擴(kuò)展點(diǎn)只執(zhí)行自己自定義的過(guò)濾邏輯。Node 節(jié)點(diǎn)執(zhí)行 Filter 策略是并發(fā)執(zhí)行的,所以在同一調(diào)度周期中多次調(diào)用過(guò)濾器。
實(shí)現(xiàn)此擴(kuò)展的插件是在 Filter 階段之后被調(diào)用,僅當(dāng)沒(méi)有為 Pod 找到可行的節(jié)點(diǎn)時(shí)才調(diào)用。如果有任何 PostFilter 插件將節(jié)點(diǎn)標(biāo)記為可調(diào)度節(jié)點(diǎn),則后面的 PostFilter 插件就不會(huì)被調(diào)用了。一個(gè)典型的 PostFilter 實(shí)現(xiàn)是搶占,它試圖通過(guò)搶占其他 Pod 來(lái)使 Pod 可調(diào)度。
在預(yù)選后被調(diào)用,通常用來(lái)在 Score 之前進(jìn)行一些信息生成或者記錄日志和監(jiān)控信息
實(shí)現(xiàn)此擴(kuò)展的插件為已通過(guò)過(guò)濾階段的所有節(jié)點(diǎn)進(jìn)行打分,調(diào)度器將針對(duì)每一個(gè)節(jié)點(diǎn)調(diào)用 Score 擴(kuò)展。
在 NormalizeScore 階段,調(diào)度器將會(huì)把每個(gè) Score 擴(kuò)展對(duì)具體某個(gè)節(jié)點(diǎn)的評(píng)分結(jié)果和該擴(kuò)展的權(quán)重合并起來(lái),作為最終評(píng)分結(jié)果,評(píng)分結(jié)果是一個(gè)范圍內(nèi)的整數(shù)。如果 Score 或 NormalizeScore 返回錯(cuò)誤,則調(diào)度周期將中止。
此擴(kuò)展點(diǎn)為 Pod 預(yù)留的在要運(yùn)行節(jié)點(diǎn)上的資源,目的是避免調(diào)度器在等待 Pod 與節(jié)點(diǎn)綁定的過(guò)程中調(diào)度新的 Pod 到節(jié)點(diǎn)上時(shí),發(fā)生實(shí)際使用資源超出可用資源的情況。(因?yàn)榻壎?Pod 到節(jié)點(diǎn)上是異步發(fā)生的)。這是調(diào)度過(guò)程的最后一個(gè)步驟,Pod 進(jìn)入 Reserved 狀態(tài)以后,要么在綁定失敗時(shí),觸發(fā) Unreserve 擴(kuò)展,要么在綁定成功時(shí),由 PostBind 擴(kuò)展結(jié)束綁定過(guò)程。
Permit 擴(kuò)展,發(fā)生在 Pod 使用 Reserve 插件預(yù)留資源之后, Bind 擴(kuò)展點(diǎn) bind 之前,主要有三種策略,批準(zhǔn)、拒絕、等待。
1)approve(批準(zhǔn)):當(dāng)所有的 Permit 擴(kuò)展都批準(zhǔn)了 Pod 與節(jié)點(diǎn)的綁定,調(diào)度器將繼續(xù)執(zhí)行綁定過(guò)程
2)deny(拒絕):如果任何一個(gè) Permit 擴(kuò)展 deny 了 Pod 與節(jié)點(diǎn)的綁定,Pod 將被放回到待調(diào)度隊(duì)列,此時(shí)將觸發(fā) Unreserve 擴(kuò)展
3)wait(等待):如果一個(gè) Permit 擴(kuò)展返回了 wait,則 Pod 將保持在 Permit 階段,直到被其他擴(kuò)展 approve,如果超時(shí)事件發(fā)生,wait 狀態(tài)變成 deny,Pod 將被放回到待調(diào)度隊(duì)列,此時(shí)將觸發(fā) UnReserve 擴(kuò)展
擴(kuò)展用于在 Pod 綁定之前執(zhí)行某些邏輯。這個(gè)插件引入的原因,是有一些資源,是在不在調(diào)度 Pod 時(shí),立即確定可用的節(jié)點(diǎn)的資源,所以調(diào)度程序需要確保,這些資源已經(jīng)成功綁定到選定的節(jié)點(diǎn)后,才能將 Pod 調(diào)度到此節(jié)點(diǎn)。例如,PreBind 擴(kuò)展可以將一個(gè)基于網(wǎng)絡(luò)的數(shù)據(jù)卷掛載到節(jié)點(diǎn)上,以Pod 可以使用。如果任何一個(gè) PreBind 擴(kuò)展返回錯(cuò)誤,Pod 將被放回到待調(diào)度隊(duì)列,此時(shí)將觸發(fā) Unreserve 擴(kuò)展。
Bind 擴(kuò)展會(huì)調(diào)用 apiserver 提供的接口,將 Pod 綁定到對(duì)應(yīng)的節(jié)點(diǎn)上。
PostBind 是一個(gè)信息擴(kuò)展點(diǎn)。成功綁定 Pod 后,將調(diào)用 PostBind 插件,可用于清理關(guān)聯(lián)的資源。
是一個(gè)通知性質(zhì)的擴(kuò)展,如果為 Pod 預(yù)留了資源,Pod 又在被綁定過(guò)程中被拒絕綁定,則 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)。
自定義插件需要兩個(gè)步驟:
1)實(shí)現(xiàn)插件的接口
2)注冊(cè)插件并配置插件
這里我們實(shí)現(xiàn) QueueSort 擴(kuò)展點(diǎn),先看看 QueueSort 擴(kuò)展點(diǎn)定義的接口:
// QueueSortPlugin is an interface that must be implemented by "QueueSort" plugins.// These plugins are used to sort pods in the scheduling queue. Only one queue sort// plugin may be enabled at a time.type QueueSortPlugin interface { Plugin // Less are used to sort pods in the scheduling queue. Less(*QueuedPodInfo, *QueuedPodInfo) bool}
默認(rèn)的調(diào)度器會(huì)優(yōu)先調(diào)度優(yōu)先級(jí)較高的 Pod , 其具體實(shí)現(xiàn)的方式是使用 QueueSort 這個(gè)插件,默認(rèn)的實(shí)現(xiàn),是對(duì) Pod 的 Priority 值進(jìn)行排序,但當(dāng)優(yōu)先級(jí)相同時(shí),再比較 Pod 的 timestamp , timestamp 是 Pod 加入 queue 的時(shí)間。我們現(xiàn)在想先根據(jù) Pod 的 Priority 值進(jìn)行排序,當(dāng) Priority 值相同,再根據(jù) Pod 的 QoS 類型進(jìn)行排序,最后再根據(jù) Pod 的 timestamp 排序。
1)Guaranteed : resources limits 和 requests 相等
2)Burstable : resources limits 和 requests 不相等
3)BestEffort : 未設(shè)置 resources limits 和 requests
具體是,Guaranteed 優(yōu)先級(jí) 高于 Burstable,Burstable 優(yōu)先級(jí)高于 BestEffort。
插件的實(shí)現(xiàn),其實(shí)我們只需要實(shí)現(xiàn) QueueSortPlugin 的 Less 方法:
package qosimport ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/kubernetes/pkg/api/v1/pod" v1qos "k8s.io/kubernetes/pkg/apis/core/v1/helper/qos" framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1")// Name is the name of the plugin used in the plugin registry and configurations.const Name = "QOSSort"http:// Sort is a plugin that implements QoS class based sorting.type Sort struct{}var _ framework.QueueSortPlugin = &Sort{}// Name returns name of the plugin.func (pl *Sort) Name() string { return Name}// Less is the function used by the activeQ heap algorithm to sort pods.// It sorts pods based on their priorities. When the priorities are equal, it uses// the Pod QoS classes to break the tie.func (*Sort) Less(pInfo1, pInfo2 *framework.PodInfo) bool { p1 := pod.GetPodPriority(pInfo1.Pod) p2 := pod.GetPodPriority(pInfo2.Pod) return (p1 > p2) || (p1 == p2 && compQOS(pInfo1.Pod, pInfo2.Pod)) || (p1 == p2 && pInfo1.Timestamp.Before(pInfo2.Timestamp))}func compQOS(p1, p2 *v1.Pod) bool { p1QOS, p2QOS := v1qos.GetPodQOS(p1), v1qos.GetPodQOS(p2) if p1QOS == v1.PodQOSGuaranteed { return true } if p1QOS == v1.PodQOSBurstable { return p2QOS != v1.PodQOSGuaranteed } return p2QOS == v1.PodQOSBestEffort}// New initializes a new plugin and returns it.func New(_ *runtime.Unknown, _ framework.FrameworkHandle) (framework.Plugin, error) { return &Sort{}, nil}
注意:一個(gè) Plugin 可以實(shí)現(xiàn)多個(gè)擴(kuò)展點(diǎn)。即在一個(gè) Plugin 中既可以實(shí)現(xiàn) Filter,又可以實(shí)現(xiàn) Score,也可以再實(shí)現(xiàn) PreBind。
1)注冊(cè)指向默認(rèn)調(diào)度器中注冊(cè)插件。
2)配置是通過(guò)配置來(lái)決定哪些插件需要被初始化。
func main() { rand.Seed(time.Now().UnixNano()) command := app.NewSchedulerCommand( app.WithPlugin(qos.Name, qos.New), ) logs.InitLogs() defer logs.FlushLogs() if err := command.Execute(); err != nil { os.Exit(1) }}
1)配置
通過(guò)配置讓 Sheduler 知道那些插件需要被初始化,如下面指定了 QueueSort 的插件 Qos,其他的擴(kuò)展點(diǎn)的插件沒(méi)有被指定,則都會(huì) Kube-Scheduler 的默認(rèn)的實(shí)現(xiàn)??梢钥吹?,schedulerName 字段代表擴(kuò)展的調(diào)度器名稱, plugins 字段中各個(gè)擴(kuò)展點(diǎn)的插件名稱,enable 代表該擴(kuò)展點(diǎn)關(guān)于運(yùn)行你的插件。
apiVersion: v1kind: ConfigMapmetadata: name: scheduler-config3 namespace: kube-systemdata: scheduler-config.yaml: | apiVersion: kubescheduler.config.k8s.io/v1alpha1 kind: KubeSchedulerConfiguration schedulerName: qos-scheduler leaderElection: leaderElect: true lockObjectName: qos-scheduler lockObjectNamespace: kube-system plugins: queueSort: enabled: - name: "QOSSort"
2)接著為調(diào)度器創(chuàng)建 RBAC
kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata: name: qos-crrules: - apiGroups: - '*' resources: - '*' verbs: - '*' - nonResourceURLs: - '*' verbs: - '*'---apiVersion: v1kind: ServiceAccountmetadata: name: qos-sa namespace: kube-system---kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata: name: qos-crb namespace: kube-systemroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: qos-crsubjects: - kind: ServiceAccount name: qos-sa namespace: kube-system
3)配置調(diào)度器的 Deployment
apiVersion: apps/v1kind: Deploymentmetadata: name: qos-scheduler namespace: kube-system labels: component: qos-schedulerspec: replicas: 1 selector: matchLabels: component: qos-scheduler template: metadata: labels: component: qos-scheduler spec: imagePullSecrets: - name: hybrid-regsecret serviceAccount: qos-sa priorityClassName: system-cluster-critical volumes: - name: scheduler-config3 configMap: name: scheduler-config3 containers: - name: qos-scheduler image: hub.baidubce.com/kun/sxy/qos-scheduler:v1.0.0 imagePullPolicy: Always args: - /qos-sample-scheduler - --config=/scheduler/scheduler-config.yaml - --v=3 resources: requests: cpu: "50m" volumeMounts: - name: scheduler-config3 mountPath: /scheduler
4)使用 kubectl apply 部署后,可以看到 qos-scheduler 已經(jīng)啟動(dòng)了
$ kubectl get pods -n kube-systemNAME READY STATUS RESTARTS AGEqos-scheduler-79c767954f-225mr 1/1 Running 0 44m
5) 使用自定義調(diào)度器調(diào)度 Pod
在 Pod 中的 spec.schedulerName 上指定 qos-scheduler,自定義調(diào)度器將會(huì)為 Pod 執(zhí)行調(diào)度邏輯。
apiVersion: v1kind: Podmetadata: name: test labels: app: testspec: schedulerName: qos-scheduler containers: - image: nginx name: nginx ports: - containerPort: 80
創(chuàng)建后,可以看到 Pod 已經(jīng)被正常調(diào)度,并啟動(dòng)成功。
$ kubectl get podsNAME READY STATUS RESTARTS AGEtest 1/1 Running 0 15s
有時(shí)候,我們需要使用協(xié)同調(diào)度,類似于 Kube-batch 的功能(也稱為“ Gang 調(diào)度”)。Gang 調(diào)度允許同時(shí)安排一定數(shù)量的 Pod 。如果 Gang 的所有成員不能同時(shí)調(diào)度,他們都不應(yīng)該調(diào)度。Scheduling Framework 中的 Gang 調(diào)度可以使用 “Permit” 插件完成。
1)主調(diào)度線程逐個(gè)處理 Pod 并為它們預(yù)留節(jié)點(diǎn),每個(gè) Pod 都會(huì)調(diào)用準(zhǔn)入階段的 Gang 調(diào)度插件。
2) 當(dāng)它發(fā)現(xiàn) Pod 屬于一個(gè) Gang 時(shí),它會(huì)檢查 Gang 的屬性。如果沒(méi)有足夠的成員定期或處于“等待”狀態(tài),該插件返回“等待”。
3) 當(dāng)數(shù)字達(dá)到期望值時(shí),處于等待狀態(tài)的所有 Pod 均被批準(zhǔn)并發(fā)送進(jìn)行綁定。
在調(diào)度 Pod 時(shí),有一些動(dòng)態(tài)的資源比如 volumn ,還不屬于備選節(jié)點(diǎn)的資源,調(diào)度程序需要確保此類集群級(jí)資源綁定到選定的節(jié)點(diǎn),然后才能將pod調(diào)度到有此類資源的節(jié)點(diǎn)的節(jié)點(diǎn)??梢允褂?Scheduling Framework 的 PreBind 擴(kuò)展點(diǎn)實(shí)現(xiàn)插件,完成這種動(dòng)態(tài)資源的綁定功能。
感謝大家的閱讀,以上就是“怎么進(jìn)行Scheduling Framework 應(yīng)用實(shí)踐”的全部?jī)?nèi)容了,學(xué)會(huì)的朋友趕緊操作起來(lái)吧。相信創(chuàng)新互聯(lián)小編一定會(huì)給大家?guī)?lái)更優(yōu)質(zhì)的文章。謝謝大家對(duì)創(chuàng)新互聯(lián)網(wǎng)站的支持!