调度器介绍

scheduler 是k8s master的一部分,作为插件存在于k8s生态体系。

自定义调度器方式

  • 添加功能重新编译
  • 实现自己的调度器(multi-scheduler)
  • scheduler调用扩展程序实现最终调度(Kubernetes scheduler extender)

添加调度功能

k8s中的调度算法介绍

预选 优选

实现自己的调度器(配置多个scheduler)

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

配置pod使用自己的调度器

下面pod显式指定使用my-scheduler调度器

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调度的因素

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

预选

过滤不符合运行条件的node

优选

对node进行打分

抢占

Kubernetes 1.8 及其以后的版本中可以指定 Pod 的优先级。优先级表明了一个 Pod 相对于其它 Pod 的重要性。
当 Pod 无法被调度时,scheduler 会尝试抢占(驱逐)低优先级的 Pod,使得这些挂起的 pod 可以被调度。
在 Kubernetes 未来的发布版本中,优先级也会影响节点上资源回收的排序。

1.9+支持pdb,优先支持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保存用于与扩展器通信的参数。如果动词是未指定/空的即认为该扩展器选择不提供该扩展。
type ExtenderConfig struct {// 访问该extender的url前缀URLPrefix string `json:"urlPrefix"`//过滤器调用的动词,如果不支持则为空。当向扩展程序发出过滤器调用时,此谓词将附加到URLPrefixFilterVerb string `json:"filterVerb,omitempty"`//prioritize调用的动词,如果不支持则为空。当向扩展程序发出优先级调用时,此谓词被附加到URLPrefix。PrioritizeVerb string `json:"prioritizeVerb,omitempty"`//优先级调用生成的节点分数的数字乘数,权重应该是一个正整数Weight int `json:"weight,omitempty"`//绑定调用的动词,如果不支持则为空。在向扩展器发出绑定调用时,此谓词会附加到URLPrefix。//如果此方法由扩展器实现,则将pod绑定动作将由扩展器返回给apiserver。只有一个扩展可以实现这个功能BindVerb string// EnableHTTPS指定是否应使用https与扩展器进行通信EnableHTTPS bool `json:"enableHttps,omitempty"`// TLSConfig指定传输层安全配置TLSConfig *restclient.TLSClientConfig `json:"tlsConfig,omitempty"`// HTTPTimeout指定对扩展器的调用的超时持续时间,过滤器超时无法调度pod。Prioritize超时被忽略//k8s或其他扩展器优先级被用来选择节点HTTPTimeout time.Duration `json:"httpTimeout,omitempty"`//NodeCacheCapable指定扩展器能够缓存节点信息//所以调度器应该只发送关于合格节点的最少信息//假定扩展器已经缓存了群集中所有节点的完整详细信息NodeCacheCapable bool `json:"nodeCacheCapable,omitempty"`// ManagedResources是由扩展器管理的扩展资源列表.// - 如果pod请求此列表中的至少一个扩展资源,则将在Filter,Prioritize和Bind(如果扩展程序是活页夹)//阶段将一个窗格发送到扩展程序。如果空或未指定,所有pod将被发送到这个扩展器。// 如果pod请求此列表中的至少一个扩展资源,则将在Filter,Prioritize和Bind(如果扩展程序是活页夹)阶段将一个pod发送到扩展程序。如果空或未指定,所有pod将被发送到这个扩展器。ManagedResources []ExtenderManagedResource `json:"managedResources,omitempty"`
}

通过k8s predicates和pod过滤的节点集传递给扩展器上的FilterVerb端点的参数。
通过k8s predicates和扩展predicates以及pod过滤的节点集传递给扩展器上的PrioritizeVerb端点的参数。

// ExtenderArgs代表被扩展器用于为pod filter/prioritize node所需要的参数
type ExtenderArgs struct {// 被调度的podPod   api.Pod      `json:"pod"`// 可被调度的候选列表Nodes api.NodeList `json:"nodes"`
}

"filter"被调用时返回节点列表(schedulerapi.ExtenderFilterResult),
"prioritize"返回节点的优先级(schedulerapi.HostPriorityList).

"filter"可以根据对应动作对节点列表进行剪裁,"prioritize"返回的分数将添加到k8s最终分数(通过其优先函数进行计算),用于最终宿主选择。

“bind”调用用于将pod绑定到节点的代理绑定到扩展器。它可以选择由扩展器实现。当它被实现时,
它是向apiserver发出绑定调用的扩展器的响应。 Pod名称,名称空间,UID和节点名称被传递给扩展器

ExtenderBindingArgs表示将pod绑定到节点的扩展器的参数

type ExtenderBindingArgs struct {// 将被绑定的podPodName string// 将被绑定的namespacePodNamespace string// poduidPodUID types.UID// 最终调度到的podNode string
}

实现

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开发与实践

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

  1. linux shell ddos木马,利用Shell 脚本解决DDOS攻击问题

    思路:主要利用 awk ,if结构,sort,uniq #!/bin/bash FilePath="access.log" awk '{print $1}' $FilePath | ...

  2. mysql shell可视化_shell编程系列24--shell操作数据库实战之利用shell脚本将文本数据导入到mysql中...

    shell编程系列24--shell操作数据库实战之利用shell脚本将文本数据导入到mysql中 利用shell脚本将文本数据导入到mysql中 需求1:处理文本中的数据,将文本中的数据插入到mys ...

  3. linux 循环显示所有的sh.*文件.,利用shell脚本遍历文件夹内所有的文件并作整理统计的方法...

    环境: Ubuntu下采用shell脚本实现 案例简述:文件夹内有许多子文件夹,这里需要自动读取所有的文件,包括他们的地址和文件名.通过观察文件名的规律,按照一定的规则裁剪出文件名的某一部分,该部分为 ...

  4. linux中利用shell脚本条件执行linux命令

    linux中利用shell脚本条件执行命令 在linux环境中,我们总会有一些命令需要经常用,例如经常跳转到某些目录下或者执行某些命令,输入一连串的命令是很烦的,此时我们可以预先写一些脚本然后根据我们 ...

  5. 解决Linux下无法利用shell脚本启动conda虚拟环境问题

    解决Linux下无法利用shell脚本启动conda虚拟环境问题 问题 直接在脚本中激活conda环境时遇到了一个问题 解决 查看.bashrc文件 .bashrc文件在 /home/用户名 里面,因 ...

  6. 利用shell脚本将json文件导入es

    现要将保存在一个目录下所有后缀名为json文件导入es集群,每个json文件中都按回车行分隔的json数据,下面是利用shell脚本完成此功能的代码. 在运行脚本之前,先创建索引. [root@nod ...

  7. linux遍历目录删除指定文件,利用shell脚本遍历文件夹内所有的文件并作整理统计的方法-linux删除文件夹...

    本篇文章扣丁学堂Linux培训小编给读者们分享一下利用shell脚本遍历文件夹内所有的文件并作整理统计的方法,文章具有很好的参考价值,感兴趣的小伙伴就随小编来了解一下吧. 环境: Ubuntu下采用s ...

  8. 利用 shell 脚本进行android 马甲包制作

    最近公司需要进行马甲包的制作,一开始想拉分支来解决,发现这样的做法不是很好,如果是多个马甲包呢?需要拉N个分支,一旦源代码动了,马甲包代码也要跟着动,而且还会产生很多冲突,多个地方需要操作起来,费时费 ...

  9. php shell ddos,利用Shell 脚本解决DDOS攻击问题

    思路:主要利用 awk ,if结构,sort,uniq #!/bin/bash FilePath="access.log" awk '{print $1}' $FilePath | ...

  10. 利用shell脚本批量判断目标ip存活情况

    一.目的 有时候需要批量去判断目标ip是否存活,一个一个去试多麻烦所以写了个shell脚本去批量尝试,原理使用的是去ping目标ip,虽然这种方法受很多因素影响,比如网速,防火墙禁ping等,但是也是 ...

最新文章

  1. mysql右下角托盘中的图标_MFC下托盘图标的实现和托盘菜单。
  2. HeadFirst设计模式(四) - 工厂模式之1 - 简单工厂
  3. python自学平台-怎么自学python,大概要多久?
  4. Leetcode 6.Z 字形变换 (每日一题 20210630)
  5. JavaWeb学习之路——SpringBoot搭建项目框架(一)
  6. 流感传染(信息学奥赛一本通-T1191)
  7. boost学习之BOOST_PP_SEQ_FOR_EACH_R
  8. ❤️使用Mybatis对数据库进行增删改查!!!
  9. 【MTSP】基于matlab遗传算法求解多旅行商问题【含Matlab源码 1339期】
  10. Java研发方向如何准备BAT技术面试
  11. 计算机组成原理白中英考点,唐朔飞版和白中英版《计算机组成原理》考研考点精讲及复习思路...
  12. 用cat命令生成软盘镜像文件
  13. 防火墙添加ip白名单_宝塔防火墙IP白名单添加/导入知道创宇云CDN节点IP段
  14. .nav ul .mall a:hover是什么意思
  15. html在浏览器中打开就是网站,浏览器打开网页的过程
  16. idea2020版本无法使用actiBPM插件问题
  17. 基础设施即代码:一场变革即将到来
  18. WSL嵌入式开发系列教程 4 —— 安装VS code
  19. 架构三要素:职责明确的模块或者组件、关联关系、约束和指导原则
  20. BAV99W 器件的作用

热门文章

  1. Git 基础 —— 常用命令
  2. Android 那些年,处理getActivity()为null的日子
  3. android shape.xml 属性详解
  4. Maven排除项目中同名不同版本的jar
  5. WPF的WebBrowser屏蔽弹出脚本错误窗口
  6. css资源网站收集推荐
  7. 大道五目Flash英文版(Renju Problems)程序分析之禁手判断
  8. select函数_SQL高级功能:窗口函数
  9. Mybatis源码阅读(二):动态节点解析2.2 —— SqlSourceBuilder与三种SqlSource
  10. 开发应用层的需要了解 framework层吗?---不需要!!!!