Edit This Page

配置多个调度器

Kubernetes 自带了一个默认调度器,其详细描述请查阅这里

如果默认调度器不适合您的需求,您可以实现自己的调度器。

不仅如此,您甚至可以伴随着默认调度器同时运行多个调度器,并告诉 Kubernetes 为每个 pod 使用什么调度器。 让我们通过一个例子讲述如何在 Kubernetes 中运行多个调度器。

关于实现调度器的具体细节描述超出了本文范围。 请参考 kube-scheduler 的实现,规范示例代码位于 pkg/scheduler

准备开始

你必须拥有一个 Kubernetes 的集群,同时你的 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/dockerized/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

为调度器定义 Kubernetes Deployment

现在我们将调度器放在容器镜像中,我们可以为它创建一个 pod 配置,并在我们的 Kubernetes 集群中运行它。 但是与其在集群中直接创建一个 pod,不如使用 DeploymentDeployment 管理一个 Replica Set,Replica Set 再管理 pod,从而使调度器能够适应故障。 以下是 Deployment 配置,被保存为 my-scheduler.yaml

admin/sched/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: 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
        - --address=0.0.0.0
        - --leader-elect=false
        - --scheduler-name=my-scheduler
        image: gcr.io/my-gcp-project/my-kube-scheduler:1.0
        livenessProbe:
          httpGet:
            path: /healthz
            port: 10251
          initialDelaySeconds: 15
        name: kube-second-scheduler
        readinessProbe:
          httpGet:
            path: /healthz
            port: 10251
        resources:
          requests:
            cpu: '0.1'
        securityContext:
          privileged: false
        volumeMounts: []
      hostNetwork: false
      hostPID: false
      volumes: []

这里需要注意的是,在该部署文件中 Container 的 spec 配置的调度器启动命令参数(--scheduler-name)指定的调度器名称应该是惟一的。 这个名称应该与 pods 上的可选参数 spec.schedulerName 的值相匹配,也就是说调度器名称的匹配关系决定了 pods 的调度任务由哪个调度器负责。

还要注意,我们创建了一个专用服务帐户 my-scheduler 并将集群角色 system: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 之外,您应该还能看到处于 “Running” 状态的 my-scheduler pod。

要在启用了 leader 选举的情况下运行多调度器,您必须执行以下操作:

首先,更新上述 Deployment YAML(my-scheduler.yaml)文件中的以下字段:

  • --leader-elect=true
  • --lock-object-namespace=lock-object-namespace
  • --lock-object-name=lock-object-name

如果在集群上启用了 RBAC,则必须更新 system:kube-scheduler 集群角色。将调度器名称添加到应用于端点资源的规则的 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:
    - ""
    resourceNames:
    - kube-scheduler
    - my-scheduler
    resources:
    - endpoints
    verbs:
    - delete
    - get
    - patch
    - update

指定 pod 的调度器

现在我们的第二个调度器正在运行,让我们创建一些 pod,并指定它们由默认调度器或我们刚部署的调度器进行调度。 为了使用特定的调度器调度给定的 pod,我们在那个 pod 的 spec 中指定调度器的名称。让我们看看三个例子。

  • Pod spec 没有任何调度器名称
admin/sched/pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: no-annotation
  labels:
    name: multischeduler-example
spec:
  containers:
  - name: pod-with-no-annotation-container
    image: k8s.gcr.io/pause:2.0

如果未提供调度器名称,则会使用 default-scheduler 自动调度 pod。

将此文件另存为 pod1.yaml,并将其提交给 Kubernetes 集群。

kubectl create -f pod1.yaml
  • Pod spec 设置为 default-scheduler
admin/sched/pod2.yaml
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: k8s.gcr.io/pause:2.0

通过将调度器名称作为 spec.schedulerName 参数的值来指定调度器。在这种情况下,我们提供默认调度器的名称,即 default-scheduler

将此文件另存为 pod2.yaml,并将其提交给 Kubernetes 集群。

kubectl create -f pod2.yaml
  • Pod spec 设置为 my-scheduler
admin/sched/pod3.yaml
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: k8s.gcr.io/pause:2.0

在这种情况下,我们指定此 pod 使用我们部署的 my-scheduler 来调度。 请注意,spec.schedulerName 参数的值应该与 Deployment 中配置的提供给 scheduler 命令的参数名称匹配。

将此文件另存为 pod3.yaml,并将其提交给 Kubernetes 集群。

kubectl create -f pod3.yaml

确认所有三个 pod 都在运行。

kubectl get pods

验证是否使用所需的调度器调度了 pod

为了更容易地完成这些示例,我们没有验证 pod 实际上是使用所需的调度程序调度的。 我们可以通过更改 pod 的顺序和上面的部署配置提交来验证这一点。 如果我们在提交调度器部署配置之前将所有 pod 配置提交给 Kubernetes 集群,我们将看到注解了 annotation-second-scheduler 的 pod 始终处于 “Pending” 状态,而其他两个 pod 被调度。 一旦我们提交调度器部署配置并且我们的新调度器开始运行,注解了 annotation-second-scheduler 的 pod 就能被调度。

或者,可以查看事件日志中的 “Scheduled” 条目,以验证是否由所需的调度器调度了 pod。

kubectl get events