转载请注明出处即可。
所使用源码k8s源码为release-1.18

如果对K8s的Scheduler不是很了解,可以先看下Kubernetes Scheduler简介这篇文章

零、Scheduler扩展简介

Scheduler的扩展有两种方式,一种是修改Scheduler的源码,编写调度和绑定两个过程的插件。然后将插件注册。
k8s目录

还有一种是通过Extender来进行扩展, 可以通过http请求调用自己编写的extender项目来处理自定义调度。
image.png

第一种的话,需要修改源码,但可以修改的阶段比较灵活,而第二种方法,处理的阶段比较宽泛。
本文主要是通过第二种方式, 首先先构建k8s集群,然后构建一个用于模拟调度扩展的项目。

一、环境准备

需要准备一个多节点的k8s集群,如果手上没有现成的测试集群或者云服务。那么可以看kubernetes部署-基于vmware+centos7虚拟机3个节点这篇文章来搭建一个简单的集群。
需要注意的是,本文使用的k8s版本为1.18,之前那篇文章上为1.17.4,需要升级。

generic_scheduler.go

需要多节点的原因如上图,仅仅是一个节点的话,也就无需考虑到底放到哪里了^_^

二、构建项目

所使用的环境为 Go 1.14版本,并且配置了go mod。通过go mod来安装相关包。框架主要使用gin,toml, k8s client等。

# 配置到.bash_profile中或者.zshrc中
export GOPROXY="https://goproxy.cn"
export GO111MODULE=on

因为考虑到大部分开发都在用Java,所以在这里多啰嗦几句。
首先创建一个项目文件夹 scheduler-extender
然后进入到文件夹内部执行go mod init scheduler-extender创建go.mod
然后安装相关的包

go get github.com/BurntSushi/toml
go get github.com/gin-gonic/gin
go get k8s.io/kube-scheduler

如果安装成功的话 go.mod如下图所示,当然版本可能会有所不同
go.mod

然后简单封装下https://gitee.com/VincentWang/scheduler-extender,具体extender实现都在这个项目中

项目封装后,在看下需要如何接收与返回参数,然后在考虑如果编写相关逻辑。
extender.go
首先看下HTTPExtender的 send 方法, 发现使用的json格式,并且args参数会序列化成json后发送到自定义的extender服务中。

send方法有四处调用,分别对应着,

  • Filter: 在调度过程中,过滤掉不部署pod的node
  • Preempt: 在资源不足时候,抢占低优先级的pod资源,优先保证高优先级pod运行
  • Prioritize: node排序,在资源充足时,选择"最佳"的node
  • Bind: 绑定阶段

在看下具体调用send方法的地方,这里只看下Filter
v1/types.go
其实在上面的四个扩展都有对应的传参和返回值(ExtenderArgs是filter和prioritize两个阶段在共用),在scheduler-extender项目实现时,需要分别进行处理。

我这里的nodes环境如下。

iphostnode role
192.168.179.137ceph1master
192.168.179.138ceph2master
192.168.179.139ceph3master

然后我们来模拟实现一个调度,filter阶段过滤掉cehp3,prioritize阶段, cehp1的优先级高于ceph2, preempt, bind先不实现。实现后,理论上部署的pod会部署到ceph1中。
filter.go
prioritize.go

具体实现逻辑完成后,在ceph3中进行项目部署,生产环境中可以部署到k8s中。

三、Scheduler配置

首先先关注下如何进行配置,才能让Scheduler去调用scheduler-extender。
register.go
首先不稳当的api版本才会用internal

const (
	// APIVersionInternal may be used if you are registering a type that should not
	// be considered stable or serialized - it is a convention only and has no
	// special behavior in this package.
	APIVersionInternal = "__internal"
)

然后在看下v1alpha2版本的api,发现也可以使用Extenders配置。
register.go

保存以下配置到sched.yaml中, 这个配置可以参考源码中的KubeSchedulerConfiguration struct,在官网没有搜索到具体的配置项,注意不要使用json的配置,k8s的这个api解析json有些bug。
KubeSchedulerConfiguration

apiVersion: kubescheduler.config.k8s.io/v1alpha2
kind: KubeSchedulerConfiguration
extenders:
  - urlPrefix: http://192.168.179.139/scheduler-extender
    filterVerb: filter
    prioritizeVerb: prioritize
    nodeCacheCapable: true
    enableHttps: false
    weight: 100000
leaderElection:
	leaderElect: true
clientConnection:
	kubeconfig: /etc/kubernetes/scheduler.conf

并将sched.yaml 放到/etc/kubernetesf中,然后修改/etc/kubernetes/manifests下的kube-scheduler.yaml文件

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    component: kube-scheduler
    tier: control-plane
  name: kube-scheduler
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-scheduler
    - --authentication-kubeconfig=/etc/kubernetes/scheduler.conf
    - --authorization-kubeconfig=/etc/kubernetes/scheduler.conf
    - --bind-address=127.0.0.1
    - --kubeconfig=/etc/kubernetes/scheduler.conf
    - --leader-elect=true
    - --config=/etc/kubernetes/sched.yaml
    image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler:v1.18.2
    imagePullPolicy: IfNotPresent
    livenessProbe:
      failureThreshold: 8
      httpGet:
        host: 127.0.0.1
        path: /healthz
        port: 10259
        scheme: HTTPS
      initialDelaySeconds: 15
      timeoutSeconds: 15
    name: kube-scheduler
    resources:
      requests:
        cpu: 100m
    volumeMounts:
    - mountPath: /etc/kubernetes/scheduler.conf
      name: kubeconfig
      readOnly: true
    - mountPath: /etc/kubernetes/sched.yaml
      name: schedconfig
      readOnly: true
  hostNetwork: true
  priorityClassName: system-cluster-critical
  volumes:
  - hostPath:
      path: /etc/kubernetes/scheduler.conf
      type: FileOrCreate
    name: kubeconfig
  - hostPath:
      path: /etc/kubernetes/sched.yaml
      type: FileOrCreate
    name: schedconfig
status: {}

主要增加了–config配置以及通过hostPath挂载sched.yaml
可以查看下是否存在配置错误

k logs -f kube-scheduler-ceph1 -n kube-system

log
修改过kube-scheduler.yaml后,k8s会自动重启pod,但是需要将3个节点的配置都修改下才行

四、验证自定义调度是否有效

上面小节的步骤都完成后,尝试部署一个简单的pod。
在执行指令前,一定要确保scheduler-extender程序是在运行的。
scheduler-extender

kubectl run kubia --image=luksa/kubia --port=8080

在执行后, 查看po的状态

kubectl get po

kubia

这里我们也可以看到scheduler-extender也存在对应的请求
scheduler-extender请求

最后看下是否部署到了ceph1节点

kubectl descibe po kubia

descibe po

DONE,大功告成。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐