日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何利用shell脚本和client-go实现自己的k8s调度器

發(fā)布時間:2025/3/11 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何利用shell脚本和client-go实现自己的k8s调度器 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

調(diào)度器介紹

scheduler 是k8s master的一部分,作為插件存在于k8s生態(tài)體系。

自定義調(diào)度器方式

?

  • 添加功能重新編譯
  • 實現(xiàn)自己的調(diào)度器(multi-scheduler)
  • scheduler調(diào)用擴(kuò)展程序?qū)崿F(xiàn)最終調(diào)度(Kubernetes scheduler extender)

添加調(diào)度功能

k8s中的調(diào)度算法介紹

預(yù)選?優(yōu)選

實現(xiàn)自己的調(diào)度器(配置多個scheduler)

scheduler以插件形式存在,集群中可以存在多個scheduler,可以顯式指定scheduler

配置pod使用自己的調(diào)度器

下面pod顯式指定使用my-scheduler調(diào)度器

apiVersion: v1 kind: Pod metadata:name: nginxlabels:app: nginx spec:schedulerName: my-schedulercontainers:- name: nginximage: nginx:1.10

官方給出的shell版本scheduler示例

#!/bin/bash SERVER='localhost:8001' while true; dofor PODNAME in $(kubectl --server $SERVER get pods -o json | jq '.items[] | select(.spec.schedulerName == "my-scheduler") | select(.spec.nodeName == null) | .metadata.name' | tr -d '"') ;doNODES=($(kubectl --server $SERVER get nodes -o json | jq '.items[].metadata.name' | tr -d '"'))NUMNODES=${#NODES[@]}CHOSEN=${NODES[$[ $RANDOM % $NUMNODES ]]}curl --header "Content-Type:application/json" --request POST --data '{"apiVersion":"v1", "kind": "Binding", "metadata": {"name": "'$PODNAME'"}, "target": {"apiVersion": "v1", "kind" : "Node", "name": "'$CHOSEN'"}}' http://$SERVER/api/v1/namespaces/default/pods/$PODNAME/binding/echo "Assigned $PODNAME to $CHOSEN"donesleep 1 done

影響pod調(diào)度的因素

https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/

預(yù)選

過濾不符合運行條件的node

優(yōu)選

對node進(jìn)行打分

搶占

Kubernetes 1.8 及其以后的版本中可以指定 Pod 的優(yōu)先級。優(yōu)先級表明了一個 Pod 相對于其它 Pod 的重要性。
當(dāng) Pod 無法被調(diào)度時,scheduler 會嘗試搶占(驅(qū)逐)低優(yōu)先級的 Pod,使得這些掛起的 pod 可以被調(diào)度。
在 Kubernetes 未來的發(fā)布版本中,優(yōu)先級也會影響節(jié)點上資源回收的排序。

1.9+支持pdb,優(yōu)先支持PDB策略,但在無法搶占其他pod的情況下,配置pdb策略的pod依舊會被搶占

Kubernetes scheduler extender

scheduler策略配置

{"kind" : "Policy","apiVersion" : "v1","predicates" : [{"name" : "PodFitsHostPorts"},{"name" : "PodFitsResources"},{"name" : "NoDiskConflict"},{"name" : "MatchNodeSelector"},{"name" : "HostName"}],"priorities" : [{"name" : "LeastRequestedPriority", "weight" : 1},{"name" : "BalancedResourceAllocation", "weight" : 1},{"name" : "ServiceSpreadingPriority", "weight" : 1},{"name" : "EqualPriority", "weight" : 1}],"extenders" : [{"urlPrefix": "http://localhost/scheduler","apiVersion": "v1beta1","filterVerb": "predicates/always_true","bindVerb": "","prioritizeVerb": "priorities/zero_score","weight": 1,"enableHttps": false,"nodeCacheCapable": false"httpTimeout": 10000000000}],"hardPodAffinitySymmetricWeight" : 10}

包含extender的配置

// ExtenderConfig保存用于與擴(kuò)展器通信的參數(shù)。如果動詞是未指定/空的即認(rèn)為該擴(kuò)展器選擇不提供該擴(kuò)展。 type ExtenderConfig struct {// 訪問該extender的url前綴URLPrefix string `json:"urlPrefix"`//過濾器調(diào)用的動詞,如果不支持則為空。當(dāng)向擴(kuò)展程序發(fā)出過濾器調(diào)用時,此謂詞將附加到URLPrefixFilterVerb string `json:"filterVerb,omitempty"`//prioritize調(diào)用的動詞,如果不支持則為空。當(dāng)向擴(kuò)展程序發(fā)出優(yōu)先級調(diào)用時,此謂詞被附加到URLPrefix。PrioritizeVerb string `json:"prioritizeVerb,omitempty"`//優(yōu)先級調(diào)用生成的節(jié)點分?jǐn)?shù)的數(shù)字乘數(shù),權(quán)重應(yīng)該是一個正整數(shù)Weight int `json:"weight,omitempty"`//綁定調(diào)用的動詞,如果不支持則為空。在向擴(kuò)展器發(fā)出綁定調(diào)用時,此謂詞會附加到URLPrefix。//如果此方法由擴(kuò)展器實現(xiàn),則將pod綁定動作將由擴(kuò)展器返回給apiserver。只有一個擴(kuò)展可以實現(xiàn)這個功能BindVerb string// EnableHTTPS指定是否應(yīng)使用https與擴(kuò)展器進(jìn)行通信EnableHTTPS bool `json:"enableHttps,omitempty"`// TLSConfig指定傳輸層安全配置TLSConfig *restclient.TLSClientConfig `json:"tlsConfig,omitempty"`// HTTPTimeout指定對擴(kuò)展器的調(diào)用的超時持續(xù)時間,過濾器超時無法調(diào)度pod。Prioritize超時被忽略//k8s或其他擴(kuò)展器優(yōu)先級被用來選擇節(jié)點HTTPTimeout time.Duration `json:"httpTimeout,omitempty"`//NodeCacheCapable指定擴(kuò)展器能夠緩存節(jié)點信息//所以調(diào)度器應(yīng)該只發(fā)送關(guān)于合格節(jié)點的最少信息//假定擴(kuò)展器已經(jīng)緩存了群集中所有節(jié)點的完整詳細(xì)信息NodeCacheCapable bool `json:"nodeCacheCapable,omitempty"`// ManagedResources是由擴(kuò)展器管理的擴(kuò)展資源列表.// - 如果pod請求此列表中的至少一個擴(kuò)展資源,則將在Filter,Prioritize和Bind(如果擴(kuò)展程序是活頁夾)//階段將一個窗格發(fā)送到擴(kuò)展程序。如果空或未指定,所有pod將被發(fā)送到這個擴(kuò)展器。// 如果pod請求此列表中的至少一個擴(kuò)展資源,則將在Filter,Prioritize和Bind(如果擴(kuò)展程序是活頁夾)階段將一個pod發(fā)送到擴(kuò)展程序。如果空或未指定,所有pod將被發(fā)送到這個擴(kuò)展器。ManagedResources []ExtenderManagedResource `json:"managedResources,omitempty"` }

通過k8s predicates和pod過濾的節(jié)點集傳遞給擴(kuò)展器上的FilterVerb端點的參數(shù)。
通過k8s predicates和擴(kuò)展predicates以及pod過濾的節(jié)點集傳遞給擴(kuò)展器上的PrioritizeVerb端點的參數(shù)。

// ExtenderArgs代表被擴(kuò)展器用于為pod filter/prioritize node所需要的參數(shù) type ExtenderArgs struct {// 被調(diào)度的podPod api.Pod `json:"pod"`// 可被調(diào)度的候選列表Nodes api.NodeList `json:"nodes"` }

"filter"被調(diào)用時返回節(jié)點列表(schedulerapi.ExtenderFilterResult),
"prioritize"返回節(jié)點的優(yōu)先級(schedulerapi.HostPriorityList).

"filter"可以根據(jù)對應(yīng)動作對節(jié)點列表進(jìn)行剪裁,"prioritize"返回的分?jǐn)?shù)將添加到k8s最終分?jǐn)?shù)(通過其優(yōu)先函數(shù)進(jìn)行計算),用于最終宿主選擇。

“bind”調(diào)用用于將pod綁定到節(jié)點的代理綁定到擴(kuò)展器。它可以選擇由擴(kuò)展器實現(xiàn)。當(dāng)它被實現(xiàn)時,
它是向apiserver發(fā)出綁定調(diào)用的擴(kuò)展器的響應(yīng)。 Pod名稱,名稱空間,UID和節(jié)點名稱被傳遞給擴(kuò)展器

ExtenderBindingArgs表示將pod綁定到節(jié)點的擴(kuò)展器的參數(shù)

type ExtenderBindingArgs struct {// 將被綁定的podPodName string// 將被綁定的namespacePodNamespace string// poduidPodUID types.UID// 最終調(diào)度到的podNode string }

實現(xiàn)

package mainimport ("bytes""encoding/json""io""k8s.io/api/core/v1"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/client-go/kubernetes""k8s.io/client-go/tools/clientcmd"schedulerapi "k8s.io/kubernetes/pkg/scheduler/api/v1""log""net/http" )var (kubeconfig string = "xxx" )func main() {http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {w.Write([]byte("hellowrold"))})http.HandleFunc("/predicates/test", testPredicateHandler)http.HandleFunc("/prioritize/test", testPrioritizeHandler)http.HandleFunc("/bind/test", BindHandler)http.ListenAndServe(":8880", nil) }func testPredicateHandler(w http.ResponseWriter, r *http.Request) {var buf bytes.Bufferbody := io.TeeReader(r.Body, &buf)log.Println(buf.String())var extenderArgs schedulerapi.ExtenderArgsvar extenderFilterResult *schedulerapi.ExtenderFilterResultif err := json.NewDecoder(body).Decode(&extenderArgs); err != nil {extenderFilterResult = &schedulerapi.ExtenderFilterResult{Nodes: nil,FailedNodes: nil,Error: err.Error(),}} else {extenderFilterResult = predicateFunc(extenderArgs)}if resultBody, err := json.Marshal(extenderFilterResult); err != nil {panic(err)} else {w.Header().Set("Content-Type", "application/json")w.WriteHeader(http.StatusOK)w.Write(resultBody)}}func testPrioritizeHandler(w http.ResponseWriter, r *http.Request) {var buf bytes.Bufferbody := io.TeeReader(r.Body, &buf)var extenderArgs schedulerapi.ExtenderArgsvar hostPriorityList *schedulerapi.HostPriorityListif err := json.NewDecoder(body).Decode(&extenderArgs); err != nil {panic(err)}if list, err := prioritizeFunc(extenderArgs); err != nil {panic(err)} else {hostPriorityList = list}if resultBody, err := json.Marshal(hostPriorityList); err != nil {panic(err)} else {w.Header().Set("Content-Type", "application/json")w.WriteHeader(http.StatusOK)w.Write(resultBody)} }func predicateFunc(args schedulerapi.ExtenderArgs) *schedulerapi.ExtenderFilterResult {pod := args.PodcanSchedule := make([]v1.Node, 0, len(args.Nodes.Items))canNotSchedule := make(map[string]string)for _, node := range args.Nodes.Items {result, err := func(pod v1.Pod, node v1.Node) (bool, error) {return true, nil}(pod, node)if err != nil {canNotSchedule[node.Name] = err.Error()} else {if result {canSchedule = append(canSchedule, node)}}}result := schedulerapi.ExtenderFilterResult{Nodes: &v1.NodeList{Items: canSchedule,},FailedNodes: canNotSchedule,Error: "",}return &result }func prioritizeFunc(args schedulerapi.ExtenderArgs) (*schedulerapi.HostPriorityList, error) {nodes := args.Nodes.Itemsvar priorityList schedulerapi.HostPriorityListpriorityList = make([]schedulerapi.HostPriority, len(nodes))for i, node := range nodes {priorityList[i] = schedulerapi.HostPriority{Host: node.Name,Score: 0,}}return &priorityList, nil }func BindHandler(w http.ResponseWriter, r *http.Request) {var buf bytes.Bufferbody := io.TeeReader(r.Body, &buf)var extenderBindingArgs schedulerapi.ExtenderBindingArgsif err := json.NewDecoder(body).Decode(&extenderBindingArgs); err != nil {panic(err)}b := &v1.Binding{ObjectMeta: metav1.ObjectMeta{Namespace: extenderBindingArgs.PodNamespace, Name: extenderBindingArgs.PodName, UID: extenderBindingArgs.PodUID},Target: v1.ObjectReference{Kind: "Node",Name: extenderBindingArgs.Node,},}bind(b)}func bind(b *v1.Binding) error {config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)if err != nil {panic(err)}clientset, err := kubernetes.NewForConfig(config)if err != nil {panic(err)}return clientset.CoreV1().Pods(b.Namespace).Bind(b) }

參考:
https://github.com/kubernetes/community/blob/master/contributors/devel/scheduler.md

https://github.com/kubernetes/community/blob/master/contributors/design-proposals/scheduling/scheduler_extender.md

https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/

https://github.com/kubernetes/kubernetes-docs-cn/blob/master/docs/concepts/overview/extending.md

歡迎加入QQ群:k8s開發(fā)與實踐

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的如何利用shell脚本和client-go实现自己的k8s调度器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。