配置多个调度器
Kubernetes 附带了一个默认调度器,其描述在此处。 如果默认调度器不符合你的需求,你可以实现自己的调度器。 此外,你甚至可以与默认调度器同时运行多个调度器,并指示 Kubernetes 为每个 Pod 使用哪个调度器。 让我们通过一个例子来学习如何在 Kubernetes 中运行多个调度器。
如何实现调度器的详细描述超出了本文档的范围。 请参考 Kubernetes 源代码目录中 pkg/scheduler 中的 kube-scheduler 实现作为规范示例。
准备工作
你必须拥有一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与你的集群通信。 建议在至少有两个不作为控制平面主机的节点的集群上运行本教程。 如果你还没有集群,你可以使用 minikube 创建一个,或者使用这些 Kubernetes 操场中的一个。
要检查版本,请输入 kubectl version
。
打包调度器
将你的调度器二进制文件打包成一个容器镜像。 对于本例,你可以使用默认调度器 (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 Container Registry (GCR)。 有关更多详细信息,请阅读 GCR 文档。 或者,你也可以使用 docker hub。 有关更多详细信息,请参阅 docker hub 文档。
docker build -t gcr.io/my-gcp-project/my-kube-scheduler:1.0 . # The image name and the repository
gcloud docker -- push gcr.io/my-gcp-project/my-kube-scheduler:1.0 # used in here is just an example
为调度器定义 Kubernetes Deployment
现在你已经将调度器放入容器镜像中,为其创建 Pod 配置并在你的 Kubernetes 集群中运行它。 但是,你无需直接在集群中创建 Pod,而是可以使用 Deployment 作为本例。 Deployment 管理一个 Replica Set,而 Replica Set 又管理 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: 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: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-scheduler-extension-apiserver-authentication-reader
namespace: kube-system
roleRef:
kind: Role
name: extension-apiserver-authentication-reader
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: my-scheduler
namespace: kube-system
---
apiVersion: v1
kind: ConfigMap
metadata:
name: my-scheduler-config
namespace: kube-system
data:
my-scheduler-config.yaml: |
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: my-scheduler
leaderElection:
leaderElect: false
---
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-config
ConfigMap 存储配置。 my-scheduler
Deployment 的 Pod 将 my-scheduler-config
ConfigMap 挂载为卷。
在上述调度器配置中,你的调度器实现通过 KubeSchedulerProfile 表示。
注意
要确定调度器是否负责调度特定的 Pod,PodTemplate 或 Pod 清单中的spec.schedulerName
字段必须与 KubeSchedulerProfile
的 schedulerName
字段匹配。 集群中运行的所有调度器都必须具有唯一的名称。另外,请注意你创建了一个专用的服务帐号 my-scheduler
,并将其绑定到 ClusterRole system:kube-scheduler
,以便它能够获得与 kube-scheduler
相同的权限。
有关其他命令行参数的详细描述,请参阅 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-scheduler Pod 之外,你应该会看到一个“运行中”的 my-scheduler Pod。
启用领导者选举
要运行启用领导者选举的多调度器,你必须执行以下操作:
更新 YAML 文件中 my-scheduler-config
ConfigMap 中 KubeSchedulerConfiguration 的以下字段:
leaderElection.leaderElect
为true
leaderElection.resourceNamespace
为<lock-object-namespace>
leaderElection.resourceName
为<lock-object-name>
注意
控制平面会为你创建锁对象,但命名空间必须已经存在。 你可以使用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 规约中指定调度器的名称。 让我们看三个例子。
未指定调度器名称的 Pod 规约
apiVersion: v1 kind: Pod metadata: name: no-annotation labels: name: multischeduler-example spec: containers: - name: pod-with-no-annotation-container image: registry.k8s.io/pause:3.8
当未提供调度器名称时,Pod 将自动使用 default-scheduler 进行调度。
将此文件保存为
pod1.yaml
并提交到 Kubernetes 集群。kubectl create -f pod1.yaml
使用
default-scheduler
的 Pod 规约apiVersion: v1 kind: Pod metadata: name: annotation-default-scheduler labels: name: multischeduler-example spec: schedulerName: default-scheduler containers: - name: pod-with-default-annotation-container image: registry.k8s.io/pause:3.8
通过将调度器名称作为
spec.schedulerName
的值来指定调度器。 在这种情况下,我们提供默认调度器的名称,即default-scheduler
。将此文件保存为
pod2.yaml
并提交到 Kubernetes 集群。kubectl create -f pod2.yaml
使用
my-scheduler
的 Pod 规约apiVersion: v1 kind: Pod metadata: name: annotation-second-scheduler labels: name: multischeduler-example spec: schedulerName: my-scheduler containers: - name: pod-with-second-annotation-container image: registry.k8s.io/pause:3.8
在这种情况下,我们指定此 Pod 应该使用我们部署的调度器
my-scheduler
进行调度。 请注意,spec.schedulerName
的值应与KubeSchedulerProfile
映射中调度器schedulerName
字段提供的名称匹配。将此文件保存为
pod3.yaml
并提交到 Kubernetes 集群。kubectl create -f pod3.yaml
验证所有三个 Pod 正在运行。
kubectl get pods
验证 Pod 是否使用所需调度器进行调度
为了更容易地完成这些示例,我们没有验证 Pod 是否确实使用所需调度器进行调度。 我们可以通过更改上述 Pod 和 Deployment 配置提交的顺序来验证这一点。 如果我们在提交调度器 Deployment 配置之前将所有 Pod 配置提交到 Kubernetes 集群,我们会看到 Pod annotation-second-scheduler
永远保持“待处理”状态,而其他两个 Pod 被调度。 一旦我们提交调度器 Deployment 配置并且我们的新调度器开始运行,annotation-second-scheduler
Pod 也会被调度。
或者,你可以查看事件日志中的“已调度”条目,以验证 Pod 是否由所需的调度器进行调度。
kubectl get events
你还可以通过修改相关控制平面节点上的静态 Pod 清单,为集群的主调度器使用自定义调度器配置或自定义容器镜像。