配置多个调度器
Kubernetes自带了一个默认调度器。如果默认调度器不适合你的需求,你可以实现自己的调度器。而且,你甚至可以和默认调度器一起同时运行多个调度器,并告诉Kubernetes为每个Pod使用哪个调度器。让我们通过一个例子讲述如何在Kubernetes中运行多个调度器。
关于实现调度器的具体细节描述超出了本文范围。请参考kube-scheduler的实现,规范示例代码位于pkg/scheduler。
在开始之前
你必须拥有一个Kubernetes的集群,同时你的Kubernetes集群必须带有kubectl命令行工具。建议在至少有两个节点的集群上运行本教程,且这些节点不作为控制平面主机。如果你还没有集群,你可以通过Minikube构建一个你自己的集群,或者你可以使用下面任意一个Kubernetes工具构建:
要获知版本信息,请输入kubectlversion。
打包调度器
将调度器可执行文件打包到容器镜像中。出于示例目的,可以使用默认调度器(kube-scheduler)作为第二个调度器。克隆GitHub上Kubernetes源代码,并编译构建源代码。
git clone https://github.com/kubernetes/kubernetes.git
cd kubernetes
make
创建一个包含kube-scheduler二进制文件的容器镜像。用于构建镜像的Dockerfile内容如下:
FROM busybox
ADD ./_output/local/bin/linux/amd64/kube-scheduler /usr/local/bin/kube-scheduler
将文件保存为Dockerfile,构建镜像并将其推送到镜像仓库。此示例将镜像推送到Google容器镜像仓库(GCR)。有关详细信息,请阅读GCR文档。
docker build -t gcr.io/my-gcp-project/my-kube-scheduler:1.0 .
gcloud docker -- push gcr.io/my-gcp-project/my-kube-scheduler:1.0
为调度器定义KubernetesDeployment
现在将调度器放在容器镜像中,为它创建一个Pod配置,并在Kubernetes集群中运行它。但是与其在集群中直接创建一个Pod,不如使用Deployment。Deployment管理一个ReplicaSet,ReplicaSet再管理Pod,从而使调度器能够免受一些故障的影响。以下是Deployment配置,将其保存为my-scheduler.yaml:
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-scheduler
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: my-scheduler-as-kube-scheduler
subjects:
- kind: ServiceAccount
name: my-scheduler
namespace: kube-system
roleRef:
kind: ClusterRole
name: system:kube-scheduler
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: ConfigMap
metadata:
name: my-scheduler-config
namespace: kube-system
data:
my-scheduler-config.yaml: |
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: my-scheduler
leaderElection:
leaderElect: false
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: my-scheduler-as-volume-scheduler
subjects:
- kind: ServiceAccount
name: my-scheduler
namespace: kube-system
roleRef:
kind: ClusterRole
name: system:volume-scheduler
apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
component: scheduler
tier: control-plane
name: my-scheduler
namespace: kube-system
spec:
selector:
matchLabels:
component: scheduler
tier: control-plane
replicas: 1
template:
metadata:
labels:
component: scheduler
tier: control-plane
version: second
spec:
serviceAccountName: my-scheduler
containers:
- command:
- /usr/local/bin/kube-scheduler
- --config=/etc/kubernetes/my-scheduler/my-scheduler-config.yaml
image: gcr.io/my-gcp-project/my-kube-scheduler:1.0
livenessProbe:
httpGet:
path: /healthz
port: 10259
scheme: HTTPS
initialDelaySeconds: 15
name: kube-second-scheduler
readinessProbe:
httpGet:
path: /healthz
port: 10259
scheme: HTTPS
resources:
requests:
cpu: '0.1'
securityContext:
privileged: false
volumeMounts:
- name: config-volume
mountPath: /etc/kubernetes/my-scheduler
hostNetwork: false
hostPID: false
volumes:
- name: config-volume
configMap:
name: my-scheduler-config
在以上的清单中,你使用KubeSchedulerConfiguration来自定义调度器实现的行为。当使用--config选项进行初始化时,该配置被传递到kube-scheduler。my-scheduler-configConfigMap存储配置数据。my-schedulerDeployment的Pod将my-scheduler-configConfigMap挂载为一个卷。
在前面提到的调度器配置中,你的调度器通过KubeSchedulerProfile进行实现。
说明:要确定一个调度器是否可以调度特定的Pod,PodTemplate或Pod清单中的spec.schedulerName字段必须匹配KubeSchedulerProfile中的schedulerName字段。所有运行在集群中的调度器必须拥有唯一的名称。
还要注意,我们创建了一个专用服务账号my-scheduler并将集群角色system:kube-scheduler绑定到它,以便它可以获得与kube-scheduler相同的权限。
在集群中运行第二个调度器
为了在Kubernetes集群中运行我们的第二个调度器,在Kubernetes集群中创建上面配置中指定的Deployment:
kubectl create -f my-scheduler.yaml
验证调度器Pod正在运行:
kubectl get pods --namespace=kube-system
输出类似于:
NAME READY STATUS RESTARTS AGE
....
my-scheduler-lnf4s-4744f 1/1 Running 0 2m
...
此列表中,除了默认的kube-schedulerPod之外,你应该还能看到处于“Running”状态的my-schedulerPod。
启用领导者选举
要在启用了leader选举的情况下运行多调度器,你必须执行以下操作:
更新你的YAML文件中的my-scheduler-configConfigMap里的KubeSchedulerConfiguration相关字段如下:
说明:
控制平面会为你创建锁对象,但是命名空间必须已经存在。你可以使用
kube-system命名空间。
如果在集群上启用了RBAC,则必须更新system:kube-scheduler集群角色。将调度器名称添加到应用了endpoints和leases资源的规则的resourceNames中,如以下示例所示:
kubectl edit clusterrole system:kube-scheduler
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:kube-scheduler
rules:
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- apiGroups:
- coordination.k8s.io
resourceNames:
- kube-scheduler
- my-scheduler
resources:
- leases
verbs:
- get
- update
- apiGroups:
- ""
resourceNames:
- kube-scheduler
- my-scheduler
resources:
- endpoints
verbs:
- delete
- get
- patch
- update
为Pod指定调度器
现在第二个调度器正在运行,创建一些Pod,并指定它们由默认调度器或部署的调度器进行调度。为了使用特定的调度器调度给定的Pod,在那个Pod的spec中指定调度器的名称。让我们看看三个例子。
确认所有三个pod都在运行。
kubectl get pods
验证是否使用所需的调度器调度了pod
为了更容易地完成这些示例,我们没有验证Pod实际上是使用所需的调度程序调度的。我们可以通过更改Pod的顺序和上面的部署配置提交来验证这一点。如果我们在提交调度器部署配置之前将所有Pod配置提交给Kubernetes集群,我们将看到注解了annotation-second-scheduler的Pod始终处于“Pending”状态,而其他两个Pod被调度。一旦我们提交调度器部署配置并且我们的新调度器开始运行,注解了annotation-second-scheduler的pod就能被调度。
或者,可以查看事件日志中的“Scheduled”条目,以验证是否由所需的调度器调度了Pod。
kubectl get events
你也可以使用自定义调度器配置或自定义容器镜像,用于集群的主调度器,方法是在相关控制平面节点上修改其静态pod清单。