转载请注明出处即可。
所使用源码k8s源码为release-1.18
如果对K8s的Scheduler不是很了解,可以先看下Kubernetes Scheduler简介这篇文章
零、Scheduler扩展简介
Scheduler的扩展有两种方式,一种是修改Scheduler的源码,编写调度和绑定两个过程的插件。然后将插件注册。
还有一种是通过Extender来进行扩展, 可以通过http请求调用自己编写的extender项目来处理自定义调度。
第一种的话,需要修改源码,但可以修改的阶段比较灵活,而第二种方法,处理的阶段比较宽泛。
本文主要是通过第二种方式, 首先先构建k8s集群,然后构建一个用于模拟调度扩展的项目。
一、环境准备
需要准备一个多节点的k8s集群,如果手上没有现成的测试集群或者云服务。那么可以看kubernetes部署-基于vmware+centos7虚拟机3个节点这篇文章来搭建一个简单的集群。
需要注意的是,本文使用的k8s版本为1.18,之前那篇文章上为1.17.4,需要升级。
需要多节点的原因如上图,仅仅是一个节点的话,也就无需考虑到底放到哪里了^_^
。
二、构建项目
所使用的环境为 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如下图所示,当然版本可能会有所不同
然后简单封装下https://gitee.com/VincentWang/scheduler-extender,具体extender实现都在这个项目中
项目封装后,在看下需要如何接收与返回参数,然后在考虑如果编写相关逻辑。
首先看下HTTPExtender的 send 方法, 发现使用的json格式,并且args参数会序列化成json后发送到自定义的extender服务中。
send方法有四处调用,分别对应着,
- Filter: 在调度过程中,过滤掉不部署pod的node
- Preempt: 在资源不足时候,抢占低优先级的pod资源,优先保证高优先级pod运行
- Prioritize: node排序,在资源充足时,选择"最佳"的node
- Bind: 绑定阶段
在看下具体调用send方法的地方,这里只看下Filter
其实在上面的四个扩展都有对应的传参和返回值(ExtenderArgs是filter和prioritize两个阶段在共用),在scheduler-extender项目实现时,需要分别进行处理。
我这里的nodes环境如下。
ip | host | node role |
---|---|---|
192.168.179.137 | ceph1 | master |
192.168.179.138 | ceph2 | master |
192.168.179.139 | ceph3 | master |
然后我们来模拟实现一个调度,filter阶段过滤掉cehp3,prioritize阶段, cehp1的优先级高于ceph2, preempt, bind先不实现。实现后,理论上部署的pod会部署到ceph1中。
具体实现逻辑完成后,在ceph3中进行项目部署,生产环境中可以部署到k8s中。
三、Scheduler配置
首先先关注下如何进行配置,才能让Scheduler去调用scheduler-extender。
首先不稳当的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配置。
保存以下配置到sched.yaml中, 这个配置可以参考源码中的KubeSchedulerConfiguration struct,在官网没有搜索到具体的配置项,注意不要使用json的配置,k8s的这个api解析json有些bug。
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
修改过kube-scheduler.yaml后,k8s会自动重启pod,但是
需要将3个节点的配置都修改下才行
。
四、验证自定义调度是否有效
上面小节的步骤都完成后,尝试部署一个简单的pod。
在执行指令前,一定要确保scheduler-extender程序是在运行的。
kubectl run kubia --image=luksa/kubia --port=8080
在执行后, 查看po的状态
kubectl get po
这里我们也可以看到scheduler-extender也存在对应的请求
最后看下是否部署到了ceph1节点
kubectl descibe po kubia
DONE,大功告成。