配置多个调度器

Kubernetes 自带了一个默认调度器,其详细描述请查阅 这里。 如果默认调度器不适合你的需求,你可以实现自己的调度器。 而且,你甚至可以和默认调度器一起同时运行多个调度器,并告诉 Kubernetes 为每个 Pod 使用哪个调度器。 让我们通过一个例子讲述如何在 Kubernetes 中运行多个调度器。

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

准备开始

你必须拥有一个 Kubernetes 的集群,同时你的 Kubernetes 集群必须带有 kubectl 命令行工具。 如果你还没有集群,你可以通过 Minikube 构建一 个你自己的集群,或者你可以使用下面任意一个 Kubernetes 工具构建:

要获知版本信息,请输入 kubectl version.

打包调度器

将调度器可执行文件打包到容器镜像中。出于示例目的,可以使用默认调度器 (kube-scheduler)作为第二个调度器。 克隆 GitHub 上 Kubernetes 源代码, 并编译构建源代码。

  1. git clone https://github.com/kubernetes/kubernetes.git
  2. cd kubernetes
  3. make

创建一个包含 kube-scheduler 二进制文件的容器镜像。用于构建镜像的 Dockerfile 内容如下:

  1. FROM busybox
  2. ADD ./_output/local/bin/linux/amd64/kube-scheduler /usr/local/bin/kube-scheduler

将文件保存为 Dockerfile,构建镜像并将其推送到镜像仓库。 此示例将镜像推送到 Google 容器镜像仓库(GCR)。 有关详细信息,请阅读 GCR 文档

  1. docker build -t gcr.io/my-gcp-project/my-kube-scheduler:1.0 .
  2. gcloud docker -- push gcr.io/my-gcp-project/my-kube-scheduler:1.0

为调度器定义 Kubernetes Deployment

现在将调度器放在容器镜像中,为它创建一个 Pod 配置,并在 Kubernetes 集群中 运行它。但是与其在集群中直接创建一个 Pod,不如使用 Deployment。 Deployment 管理一个 ReplicaSet, ReplicaSet 再管理 Pod,从而使调度器能够免受一些故障的影响。 以下是 Deployment 配置,将其保存为 my-scheduler.yaml

admin/sched/my-scheduler.yaml 配置多个调度器 - 图1

  1. apiVersion: v1
  2. kind: ServiceAccount
  3. metadata:
  4. name: my-scheduler
  5. namespace: kube-system
  6. ---
  7. apiVersion: rbac.authorization.k8s.io/v1
  8. kind: ClusterRoleBinding
  9. metadata:
  10. name: my-scheduler-as-kube-scheduler
  11. subjects:
  12. - kind: ServiceAccount
  13. name: my-scheduler
  14. namespace: kube-system
  15. roleRef:
  16. kind: ClusterRole
  17. name: system:kube-scheduler
  18. apiGroup: rbac.authorization.k8s.io
  19. ---
  20. apiVersion: rbac.authorization.k8s.io/v1
  21. kind: ClusterRoleBinding
  22. metadata:
  23. name: my-scheduler-as-volume-scheduler
  24. subjects:
  25. - kind: ServiceAccount
  26. name: my-scheduler
  27. namespace: kube-system
  28. roleRef:
  29. kind: ClusterRole
  30. name: system:volume-scheduler
  31. apiGroup: rbac.authorization.k8s.io
  32. ---
  33. apiVersion: apps/v1
  34. kind: Deployment
  35. metadata:
  36. labels:
  37. component: scheduler
  38. tier: control-plane
  39. name: my-scheduler
  40. namespace: kube-system
  41. spec:
  42. selector:
  43. matchLabels:
  44. component: scheduler
  45. tier: control-plane
  46. replicas: 1
  47. template:
  48. metadata:
  49. labels:
  50. component: scheduler
  51. tier: control-plane
  52. version: second
  53. spec:
  54. serviceAccountName: my-scheduler
  55. containers:
  56. - command:
  57. - /usr/local/bin/kube-scheduler
  58. - --address=0.0.0.0
  59. - --leader-elect=false
  60. - --scheduler-name=my-scheduler
  61. image: gcr.io/my-gcp-project/my-kube-scheduler:1.0
  62. livenessProbe:
  63. httpGet:
  64. path: /healthz
  65. port: 10251
  66. initialDelaySeconds: 15
  67. name: kube-second-scheduler
  68. readinessProbe:
  69. httpGet:
  70. path: /healthz
  71. port: 10251
  72. resources:
  73. requests:
  74. cpu: '0.1'
  75. securityContext:
  76. privileged: false
  77. volumeMounts: []
  78. hostNetwork: false
  79. hostPID: false
  80. volumes: []

这里需要注意的是,在容器规约中配置的调度器启动命令参数(—scheduler-name)所指定的 调度器名称应该是唯一的。 这个名称应该与 Pod 上的可选参数 spec.schedulerName 的值相匹配,也就是说调度器名称的匹配 关系决定了 Pods 的调度任务由哪个调度器负责。

还要注意,我们创建了一个专用服务账号 my-scheduler 并将集群角色 system:kube-scheduler 绑定到它,以便它可以获得与 kube-scheduler 相同的权限。

请参阅 kube-scheduler 文档 以获取其他命令行参数的详细说明。

在集群中运行第二个调度器

为了在 Kubernetes 集群中运行我们的第二个调度器,在 Kubernetes 集群中创建上面配置中指定的 Deployment:

  1. kubectl create -f my-scheduler.yaml

验证调度器 Pod 正在运行:

  1. kubectl get pods --namespace=kube-system

输出类似于:

  1. NAME READY STATUS RESTARTS AGE
  2. ....
  3. my-scheduler-lnf4s-4744f 1/1 Running 0 2m
  4. ...

此列表中,除了默认的 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>

说明:

控制平面会为你创建锁对象,但是命名空间必须已经存在。 你可以使用 kube-system 命名空间。

如果在集群上启用了 RBAC,则必须更新 system:kube-scheduler 集群角色。 将调度器名称添加到应用了 endpointsleases 资源的规则的 resourceNames 中,如以下示例所示:

  1. kubectl edit clusterrole system:kube-scheduler

admin/sched/clusterrole.yaml 配置多个调度器 - 图2

  1. apiVersion: rbac.authorization.k8s.io/v1
  2. kind: ClusterRole
  3. metadata:
  4. annotations:
  5. rbac.authorization.kubernetes.io/autoupdate: "true"
  6. labels:
  7. kubernetes.io/bootstrapping: rbac-defaults
  8. name: system:kube-scheduler
  9. rules:
  10. - apiGroups:
  11. - coordination.k8s.io
  12. resources:
  13. - leases
  14. verbs:
  15. - create
  16. - apiGroups:
  17. - coordination.k8s.io
  18. resourceNames:
  19. - kube-scheduler
  20. - my-scheduler
  21. resources:
  22. - leases
  23. verbs:
  24. - get
  25. - update
  26. - apiGroups:
  27. - ""
  28. resourceNames:
  29. - kube-scheduler
  30. - my-scheduler
  31. resources:
  32. - endpoints
  33. verbs:
  34. - delete
  35. - get
  36. - patch
  37. - update

为 Pod 指定调度器

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

  • Pod spec 没有任何调度器名称

    admin/sched/pod1.yaml 配置多个调度器 - 图3

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: no-annotation
    5. labels:
    6. name: multischeduler-example
    7. spec:
    8. containers:
    9. - name: pod-with-no-annotation-container
    10. image: k8s.gcr.io/pause:2.0

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

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

    1. kubectl create -f pod1.yaml
  • Pod spec 设置为 default-scheduler

    admin/sched/pod2.yaml 配置多个调度器 - 图4

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: annotation-default-scheduler
    5. labels:
    6. name: multischeduler-example
    7. spec:
    8. schedulerName: default-scheduler
    9. containers:
    10. - name: pod-with-default-annotation-container
    11. image: k8s.gcr.io/pause:2.0

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

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

    1. kubectl create -f pod2.yaml
  • Pod spec 设置为 my-scheduler

    admin/sched/pod3.yaml 配置多个调度器 - 图5

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: annotation-second-scheduler
    5. labels:
    6. name: multischeduler-example
    7. spec:
    8. schedulerName: my-scheduler
    9. containers:
    10. - name: pod-with-second-annotation-container
    11. image: k8s.gcr.io/pause:2.0

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

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

    1. kubectl create -f pod3.yaml

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

  1. kubectl get pods

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

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

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

  1. kubectl get events

你也可以使用自定义调度器配置 或自定义容器镜像,用于集群的主调度器,方法是在相关控制平面节点上修改其静态 pod 清单。