複数のスケジューラーを設定する

Kubernetesにはこちらで説明されているデフォルトのスケジューラーが付属します。 もしデフォルトのスケジューラーがあなたの要求を満たさない場合、独自にスケジューラーを実装できます。 さらに、デフォルトのスケジューラーと一緒に複数のスケジューラーを同時に実行し、どのPodにどのスケジューラーを使うかKubernetesに指示できます。 具体例を見ながらKubernetesで複数のスケジューラーを実行する方法を学びましょう。

スケジューラーの実装方法の詳細は本ドキュメントの範囲外です。 標準的な例としてKubernetesのソースディレクトリのpkg/schedulerにあるkube-schedulerの実装が参照できます。

始める前に

Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:

バージョンを確認するには次のコマンドを実行してください: kubectl version.

スケジューラーをパッケージ化する

スケジューラーのバイナリをコンテナイメージとしてパッケージ化します。 例として、デフォルトのスケジューラー(kube-scheduler)を2つ目のスケジューラーとして使用します。 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の設定を作成してクラスター上で動かします。 この例では、直接Podをクラスターに作成する代わりに、Deploymentを使用します。 DeploymentReplicaSetを管理し、そのReplicaSetがPodを管理することで、スケジューラーを障害に対して堅牢にします。 my-scheduler.yamlとして保存するDeploymentの設定を示します:

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/v1beta2
    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を使用してあなたのスケジューラー実装の振る舞いを変更できます。 この設定ファイルはkube-schedulerの初期化時に--configオプションから渡されます。 この設定ファイルはmy-scheduler-config ConfigMapに格納されており、my-scheduler DeploymentのPodはmy-scheduler-config ConfigMapをボリュームとしてマウントします。

前述のスケジューラー設定において、あなたのスケジューラー実装はKubeSchedulerProfileを使って表現されます。

また、専用のサービスアカウントmy-schedulerを作成してsystem:kube-scheduler ClusterRoleに紐づけを行い、スケジューラーにkube-schedulerと同じ権限を付与している点に注意します。

その他のコマンドライン引数の詳細はkube-schedulerのドキュメントから、その他の変更可能なkube-schedulerの設定はスケジューラー設定のリファレンスから確認できます。

クラスターで2つ目のスケジューラーを実行する

2つ目のスケジューラーをクラスター上で動かすには、前述のDeploymentをKubernetesクラスターに作成します:

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が「Running」になっているはずです。

リーダー選出を有効にする

リーダー選出を有効にして複数のスケジューラーを実行するには、次の対応が必要です:

YAMLファイルにあるmy-scheduler-config ConfigMap内のKubeSchedulerConfigurationの次のフィールドを更新します:

  • leaderElection.leaderElecttrueに設定します
  • leaderElection.resourceNamespace<lock-object-namespace>に設定します
  • leaderElection.resourceName<lock-object-name>に設定します

クラスターでRBACが有効になっている場合、system:kube-scheduler ClusterRoleを更新し、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にスケジューラーを指定する

2つ目のスケジューラーが動作している状態で、Podをいくつか作成し、デフォルトのスケジューラーまたは新しいスケジューラーのどちらで配置するか指定します。 あるPodを特定のスケジューラーで配置するには、Podのspecにスケジューラー名を指定します。 3つの例を確認しましょう。

  • スケジューラー名を指定しない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
    

    この場合、前述の手順でデプロイしたmy-schedulerを使用してPodを配置することを指定します。 spec.schedulerNameの値はKubeSchedulerProfileschedulerNameフィールドに設定した名前と一致する必要があります。

    このファイルをpod3.yamlとして保存し、クラスターに投入します。

    kubectl create -f pod3.yaml
    

    3つのPodがすべて実行中であることを確認します。

    kubectl get pods
    

Podが目的のスケジューラーによって配置されたことを確認する

わかりやすさのため、前述の例ではPodが実際に指定したスケジューラーによって配置されたことを確認していません。 確認したい場合はPodとDeploymentの設定の適用順序を変えてみてください。 もしPodの設定をすべて先に適用し、その後にスケジューラーのDeploymentを適用した場合、annotation-second-scheduler Podは「Pending」のままになり、他の2つのPodが先に配置されることを確認できます。 その後にスケジューラーのDeploymentを適用して新しいスケジューラーが動作すると、annotation-second-scheduler Podも配置されます。

あるいは、イベントログの「Scheduled」の項目を見ることで、どのPodがどのスケジューラーによって配置されたかを確認できます。

kubectl get events

クラスターのメインのスケジューラーについては、独自のスケジューラー設定を適用することや、関連するコントロールプレーンノードにある静的Podのマニフェストを変更し独自のコンテナイメージを使うことができます。