配置多个调度器

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-schedulermy-scheduler-config ConfigMap 存储配置。 my-scheduler Deployment 的 Pod 将 my-scheduler-config ConfigMap 挂载为卷。

在上述调度器配置中,你的调度器实现通过 KubeSchedulerProfile 表示。

另外,请注意你创建了一个专用的服务帐号 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.leaderElecttrue
  • leaderElection.resourceNamespace<lock-object-namespace>
  • leaderElection.resourceName<lock-object-name>

如果你的集群上启用了 RBAC,你必须更新 system:kube-scheduler 集群角色。 将你的调度器名称添加到应用于 endpointsleases 资源的规则的 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 清单,为集群的主调度器使用自定义调度器配置或自定义容器镜像。

上次修改时间:2023 年 12 月 14 日,太平洋标准时间上午 9:24:更新配置 API 的引用 (2fe79a7c28)