Kubernetes自定义调度器 — 初窥门径

Prodan Labs
• 阅读 2079

Kubernetes自定义调度器 — 初窥门径 通过上一篇文章对scheduler-framework调度框架已经有了大致了解,根据我们的实际生产的一些问题(如计算服务没有被调度到实际CPU最优的节点)和需求,来实现一个简单的基于CPU指标的自定义调度器。自定义调度器通过kubernetes资源指标服务metrics-server来获取各节点的当前的资源情况,并进行打分,然后把Pod调度到分数最高的节点

PreFilter扩展点


对Pod的信息进行预处理,检查Pod或集群是否满足前提条件。

通过pod已声明的Annotations参数 rely.on.namespaces/namerely.on.pod/labs来获取该pod依赖的pod是否就绪,如依赖的pod未就绪,则终止调度,pod处于Pending状态。

func (pl *sample) PreFilter(ctx context.Context, state *framework.CycleState, p *v1.Pod) *framework.Status {

  namespace := p.Annotations["rely.on.namespaces/name"]
  podLabs := p.Annotations["rely.on.pod/labs"]

  if namespace == "" || podLabs == "" {
    return framework.NewStatus(framework.Success, "ont rely")
  }
  if prefilter.IsExist(namespace) == false {
    return framework.NewStatus(framework.Unschedulable, "not found namespace: "+namespace)
  }

  if prefilter.IsReady(namespace, podLabs) == false {
    return framework.NewStatus(framework.Unschedulable, "rely pod not ready")
  }
  klog.Infoln("rely pod is ready :", namespace, podLabs, prefilter.IsReady(namespace, podLabs))
  return framework.NewStatus(framework.Success, "rely pod is ready")
}

调度失败结果:

Events:
  Type     Reason            Age   From              Message
  ----     ------            ----  ----              -------
  Warning  FailedScheduling  9s    sample-scheduler  0/2 nodes are available: 2 rely pod not ready.
  Warning  FailedScheduling  9s    sample-scheduler  0/2 nodes are available: 2 rely pod not ready.

如满足Pod的前置条件,则正常调度,进入下一阶段

I1025 12:26:59.435773       1 plugins.go:50] rely pod is ready : kube-system k8s-app=metrics-server true

Filter扩展点


对不满足Pod调度要求的节点进行过滤掉。


func (pl *sample) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, node *framework.NodeInfo) *framework.Status {

  if node.Node().Labels["cpu"] != "true" {
    return framework.NewStatus(framework.Unschedulable, "not found labels")
  }
  nodeUsedCPU, nodeUsedMen, nodeCPU, nodeMen, cpuRate, menRate := filter.ResourceStatus(node.Node().Name)

  for i := 0; i < len(pod.Spec.Containers); i++ {
    requestsCPUCore, _ := strconv.ParseFloat(strings.Replace(pod.Spec.Containers[i].Resources.Requests.Cpu().String(), "n", "", 1), 64)
    requestsCPU := requestsCPUCore * 1000 * (1000 * 1000)
    requestsMen := pod.Spec.Containers[i].Resources.Requests.Memory().Value() / 1024 / 1024
    limitsCPUCore, _ := strconv.ParseFloat(strings.Replace(pod.Spec.Containers[i].Resources.Limits.Cpu().String(), "n", "", 1), 64)
    limitsCPU := limitsCPUCore * 1000 * (1000 * 1000)
    limitsMen := pod.Spec.Containers[i].Resources.Limits.Memory().Value() / 1024 / 1024
    if requestsCPU > float64(nodeCPU) || requestsMen > nodeMen {
      return framework.NewStatus(framework.Unschedulable, "out of Requests resources")
    }
    if limitsCPU > float64(nodeCPU) || limitsMen > nodeMen {
      return framework.NewStatus(framework.Unschedulable, "out of Limits resources")
    }
    if requestsCPU > float64(nodeCPU)-nodeUsedCPU || requestsMen > (nodeMen-nodeUsedMen) {
      return framework.NewStatus(framework.Unschedulable, "out of Requests resources system")
    }
    if limitsCPU > float64(nodeCPU)-nodeUsedCPU || limitsMen > (nodeMen-nodeUsedMen) {
      return framework.NewStatus(framework.Unschedulable, "out of Limits resources system")
    }

  }

  klog.Infof("node:%s, CPU:%v ,  Memory: %v", node.Node().Name, cpuRate, menRate)
  cpuThreshold := filter.GetEnvFloat("CPU_THRESHOLD", 0.85)
  menThreshold := filter.GetEnvFloat("MEN_THRESHOLD", 0.85)
  if cpuRate > cpuThreshold || menRate > menThreshold {
    return framework.NewStatus(framework.Unschedulable, "out of system resources")
  }

  return framework.NewStatus(framework.Success, "Node: "+node.Node().Name)
}

过滤掉没有 cpu=true labels的节点; Pod调度资源值和限制资源值大于节点当前可用资源的节点,则过滤; 默认过滤cpu内存使用率超过 85%的节点。 CPU_THRESHOLDMEN_THRESHOLD 环境变量设置该值。 调度失败结果:

Events:
  Type     Reason            Age    From              Message
  ----     ------            ----   ----              -------
  Warning  FailedScheduling  9m33s  sample-scheduler  0/2 nodes are available: 1 Insufficient cpu, 1 out of Limits resources system.
  Warning  FailedScheduling  9m33s  sample-scheduler  0/2 nodes are available: 1 Insufficient cpu, 1 out of Limits resources system.

可以通过日志查看当前获取到的系统资源利用率

I1025 12:29:21.360979       1 plugins.go:87] node:k8s-test09, CPU:0.06645718025 ,  Memory: 0.33549941504789904
I1025 12:29:21.361471       1 plugins.go:87] node:k8s-test10, CPU:0.0411259705 ,  Memory: 0.15946609553600768

Score扩展点


用于对已通过过滤阶段的节点进行打分。

func (pl *sample) Score(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) (int64, *framework.Status) {

  isSamePod := score.IsSamePod(nodeName, p.Namespace, p.Labels) // max 2
  cpuLoad := score.CPURate(nodeName)                            // max 3
  menLoad := score.MemoryRate(nodeName)                         // max 3
  core := score.CpuCore(nodeName)                               // max 3

  c := isSamePod + cpuLoad + core + menLoad
  klog.Infoln(nodeName+" score is :", c)
  return c, framework.NewStatus(framework.Success, nodeName)
}

打分规则:

  • 配置高的节点权重大
  • 当前资源使用率底的节点权重大
  • 运行多组pod的情况下,运行相同pod的节点权重底
  • 如果Score插件的打分结果不是[0-100]范围内的整数,则调用NormalizeScore进行归一化。

调度结果:

I1025 12:28:35.620198       1 plugins.go:105] k8s-test10 score is : 6
I1025 12:28:35.626170       1 plugins.go:105] k8s-test09 score is : 7
I1025 12:28:35.626394       1 trace.go:205] Trace[232544630]: "Scheduling" namespace:default,name:test-scheduler-84859f9467-rgfpd (25-Oct-2020 12:28:35.488) (total time: 137ms):
Trace[232544630]: ---"Computing predicates done" 38ms (12:28:00.526)
Trace[232544630]: ---"Prioritizing done" 99ms (12:28:00.626)
Trace[232544630]: [137.453956ms] [137.453956ms] END
I1025 12:28:35.626551       1 default_binder.go:51] Attempting to bind default/test-scheduler-84859f9467-rgfpd to k8s-test09
I1025 12:28:35.632736       1 eventhandlers.go:205] delete event for unscheduled pod default/test-scheduler-84859f9467-rgfpd
I1025 12:28:35.632893       1 scheduler.go:597] "Successfully bound pod to node" pod="default/test-scheduler-84859f9467-rgfpd" node="k8s-test09" evaluatedNodes=2 feasibleNodes=2
I1025 12:28:35.633369       1 eventhandlers.go:225] add event for scheduled pod default/test-scheduler-84859f9467-rgfpd 
I1025 12:29:21.328791       1 eventhandlers.go:173] add event for unscheduled pod default/test-scheduler-84859f9467-48wlr
I1025 12:29:21.328897       1 scheduler.go:452] Attempting to schedule pod: default/test-scheduler-84859f9467-48wlr
I1025 12:29:21.351126       1 plugins.go:50] rely pod is ready : kube-system k8s-app=metrics-server true
I1025 12:29:21.360979       1 plugins.go:87] node:k8s-test09, CPU:0.06645718025 ,  Memory: 0.33549941504789904
I1025 12:29:21.361471       1 plugins.go:87] node:k8s-test10, CPU:0.0411259705 ,  Memory: 0.15946609553600768
I1025 12:29:21.419137       1 plugins.go:105] k8s-test10 score is : 6
I1025 12:29:21.419210       1 plugins.go:105] k8s-test09 score is : 5
I1025 12:29:21.419407       1 default_binder.go:51] Attempting to bind default/test-scheduler-84859f9467-48wlr to k8s-test10
I1025 12:29:21.427243       1 scheduler.go:597] "Successfully bound pod to node" pod="default/test-scheduler-84859f9467-48wlr" node="k8s-test10" evaluatedNodes=2 feasibleNodes=2
I1025 12:29:21.427441       1 eventhandlers.go:205] delete event for unscheduled pod default/test-scheduler-84859f9467-48wlr
I1025 12:29:21.427472       1 eventhandlers.go:225] add event for scheduled pod default/test-scheduler-84859f9467-48wlr 

完整的示例代码: https://github.com/prodanlabs/scheduler-framework Kubernetes自定义调度器 — 初窥门径


感兴趣的读者可以关注下微信号 Kubernetes自定义调度器 — 初窥门径

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Prodan Labs Prodan Labs
3年前
Kubernetes自定义调度器 — 初识调度框架
Kubernetes已经成为容器编排(Orchestration)平台的事实标准,它为容器化应用提供了简单且高效部署的方式、大规模可伸缩、资源调度等生命周期管理功能。kubescheduler作为kubernetes的核心组件,它负责整个集群资源的调度功能,根据特定的调度算法或调度策略,将Pod调度到最优的Node节点,使集群的资源得到合理且充分的利用。
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Android蓝牙连接汽车OBD设备
//设备连接public class BluetoothConnect implements Runnable {    private static final UUID CONNECT_UUID  UUID.fromString("0000110100001000800000805F9B34FB");
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这