今日の記事では、スケジューリングプロセスにおいてPredicatesとPrioritiesのスケジューリング戦略が主に活躍する段階を紹介します。
Predicates
まずはPredicatesを見ていきましょう。Predicatesのスケジューリングプロセスでの役割は、フィルター(Filter)として理解できます。つまり、スケジューリングポリシーに従って、現在のクラスター内の全ノードから条件を満たす一連のノードを「フィルタリング」します。これらのノードはすべて、スケジューリング待ちのPodの潜在的なホストです。Kubernetesには、デフォルトで4つのスケジューリングポリシーがあります。
1つ目はGeneralPredicatesと呼ばれます。
その名の通り、このフィルタリングルール群は最も基本的なスケジューリングポリシーを担当します。例えば、PodFitsResourcesはホストのCPUとメモリリソースが十分かどうかを計算します。もちろん、前述したように、PodFitsResourcesはPodのrequestsフィールドのみをチェックします。注意すべき点は、KubernetesスケジューラはGPUなどのハードウェアリソースに対して特定のリソースタイプを定義せず、代わりにExtended Resourceと呼ばれるKey-Value形式で記述することです。例えば:
apiVersion: v1
kind: Pod
metadata:
name: extended-resource-demo
spec:
containers:
- name: extended-resource-demo-ctr
image: nginx
resources:
requests:
alpha.kubernetes.io/nvidia-gpu: "2"
limits:
alpha.kubernetes.io/nvidia-gpu: "2"
上記の通り、Podはalpha.kubernetes.io/nvidia-gpu=2という定義方法で2つのNVIDIA GPUを使用することを宣言しています。PodFitsResourcesでは、スケジューラはこのフィールドのKeyがGPUであることを実際には認識せず、後続のValueを直接使用して計算します。もちろん、NodeのCapacityフィールドには、このホスト上のGPUの総数(例:alpha.kubernetes.io/nvidia-gpu=4)も追加する必要があります。これらのプロセスについては、後ほどDevice Pluginの説明で詳しく紹介します。
PodFitsHostは、ホスト名がPodのspec.nodeNameと一致するかどうかをチェックします。PodFitsHostPortsは、Podが申請したホストポート(spec.nodePort)が既に使用されているポートと競合しないかどうかをチェックします。PodMatchNodeSelectorは、PodのnodeSelectorまたはnodeAffinityで指定されたノードが検査対象のノードと一致するかどうかをチェックします。このように、GeneralPredicatesのセットは、KubernetesがPodをNode上で実行できるかどうかを検査するための最も基本的なフィルタリング条件です。そのため、GeneralPredicatesは他のコンポーネント(kubeletなど)からも直接呼び出されます。
2つ目はVolume関連のフィルタリングルールです。
このルール群は、コンテナの永続ボリュームに関連するスケジューリングポリシーを担当します。その中で、NoDiskConflictは、複数のPodが宣言する永続ボリューム間に競合がないかどうかをチェックします。例えば、AWS EBSタイプのボリュームは、2つのPodが同時に使用することはできません。そのため、あるノードにAという名前のEBSボリュームが既にマウントされている場合、同じAボリュームの使用を宣言している別のPodはこのノードにスケジュールできません。MaxPDVolumeCountPredicateは、ノード上の特定タイプの永続ボリュームの数が一定数を超えていないかどうかをチェックします。超えている場合、そのタイプの永続ボリュームを使用するPodはこのノードにスケジュールできなくなります。VolumeZonePredicateは、永続ボリュームのZone(高可用性ドメイン)ラベルが検査対象ノードのZoneラベルと一致するかどうかをチェックします。さらに、VolumeBindingPredicateというルールもあります。これは、Podに対応するPVのnodeAffinityフィールドが特定のノードのラベルと一致するかどうかをチェックします。Local Persistent Volume(ローカル永続ボリューム)は、nodeAffinityを使用して特定のノードにバインドする必要があります。これは実際には、PredicatesフェーズでKubernetesがPodのVolume属性に基づいてスケジュールできなければならないことを意味します。また、PodのPVCがまだ特定のPVにバインドされていない場合、スケジューラはバインド対象のすべてのPVをチェックする責任も負います。利用可能なPVがあり、そのPVのnodeAffinityが検査対象ノードと一致する場合、このルールは「成功」を返します。例えば:
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-local-pv
spec:
capacity:
storage: 500Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
local:
path: /mnt/disks/vol1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- my-node
上記の通り、このPVに対応する永続ディレクトリは、my-nodeという名前のホスト上にのみ存在します。したがって、PVCを介してこのPVを使用するPodは、正常に機能するためにmy-nodeにスケジュールされる必要があります。VolumeBindingPredicateは、スケジューラがこの判断を行う部分です。
3つ目はホスト関連のフィルタリングルールです。
このルール群は、スケジュール対象のPodがNode自体の特定の条件を満たしているかどうかを主に検査します。例えば、PodToleratesNodeTaintsは、よく使われるNodeの「taint」メカニズムをチェックします。PodのTolerationフィールドがNodeのTaintフィールドと一致する場合にのみ、このPodはそのNodeにスケジュールできます。NodeMemoryPressurePredicateは、現在のNodeのメモリがもう十分でないかどうかをチェックします。十分でない場合、スケジュール待ちのPodはこのNodeにスケジュールできません。
4つ目はPod関連のフィルタリングルールです。
このルール群は、GeneralPredicatesの大部分と重複します。特別なのはPodAffinityPredicateです。このルールの役割は、スケジュール対象のPodとNode上の既存Podとの間のアフィニティおよびアンチアフィニティ関係をチェックすることです。例えば:
apiVersion: v1
kind: Pod
metadata:
name: with-pod-antiaffinity
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: kubernetes.io/hostname
containers:
- name: with-pod-affinity
image: docker.io/ocpqe/hello-pod
この例では、podAntiAffinityルールは、このPodがsecurity=S2ラベルを持つPodと同じNode上に存在することを望まないと指定しています。注意すべき点は、PodAffinityPredicateにはスコープがあり、上記のルールはkubernetes.io/hostnameラベルのKeyを持つNodeに対してのみ有効であることです。これがトポロジーキー(topologyKey)の役割です。
これらの4種類のPredicatesは、スケジューラがあるNodeがスケジュール対象のPodを実行できるかどうかを判断するための基本戦略を構成します。実行時、Podがスケジュールされると、Kubernetesスケジューラは同時に16個のゴルーチンを起動して、クラスター内のすべてのNodeに対してPredicatesを並行計算し、最終的にこのPodを実行できるホストのリストを返します。各Nodeに対してPredicatesを実行する際、スケジューラは固定された順序でチェックを行うことに注意してください。この順序はPredicates自体の意味に基づいて決められます。例えば、ホスト関連のPredicatesはより早くチェックされます。そうでなければ、リソースが著しく不足しているホストでPodAffinityPredicateを計算しても意味がありません。
Priorities
Predicatesフェーズでのノードの「フィルタリング」が終わると、Prioritiesフェーズの仕事はこれらのノードにスコアを付けることです。ここでのスコア範囲は0〜10点で、最も高いスコアのノードがPodが最終的にバインドされる最適なノードとなります。Prioritiesで最もよく使われるスコアリングルールはLeastRequestedPriorityです。このアルゴリズムは、実際には最も空きリソース(CPUとメモリ)が多いホストを選択します。さらに、他にも3つのPrioritiesがあります。NodeAffinityPriority、TaintTolerationPriority、InterPodAffinityPriorityです。名前が示すように、それらの意味と計算方法は前述の3つのPredicates(PodMatchNodeSelector、PodToleratesNodeTaints、PodAffinityPredicate)と似ています。ただし、Priorityとして、Nodeが上記のルールをより多く満たすほど、スコアが高くなります。
デフォルトのPrioritiesには、ImageLocalityPriorityという戦略もあります。これはKubernetes v1.12で有効になった新しいスケジューリングルールです。つまり、スケジュール対象のPodが必要とするイメージが大きく、かつ一部のNodeに既に存在する場合、これらのNodeはより高いスコアを得ます。もちろん、アルゴリズムがスケジューリングの集中を引き起こすのを避けるため、スケジューラはスコア計算時にイメージの分布に応じて最適化も行います。すなわち、大きなイメージが分布しているノードの数が非常に少ない場合、これらのノードの重みは減らされ、それによってスケジューリング集中のリスクを「相殺」します。
まとめると、これがKubernetesのスケジューラにおけるデフォルトのスケジューリングルールの主な動作原理です。実際の実行プロセスでは、スケジューラ内のクラスターとPodに関する情報はキャッシュされているため、これらのアルゴリズムの実行プロセスは比較的高速です。また、より複雑なスケジューリングアルゴリズム(PodAffinityPredicateなど)では、計算時にスケジュール対象のPodと検査対象のNodeだけでなく、クラスター全体の情報(すべてのノードをトラバースしてラベルを読み取るなど)にも注意を払う必要があります。この場合、Kubernetesスケジューラは、各スケジュール対象Podに対してスケジューリングアルゴリズムを実行する前に、アルゴリズムが必要とするクラスター情報を事前に計算し、キャッシュします。これにより、実際にアルゴリズムを実行する際、スケジューラはキャッシュされた情報を読み取って計算するだけで済み、Predicates計算時に各Nodeに対してクラスター全体の情報を繰り返し取得・計算する必要がなくなります。
まとめ
以上、本記事ではKubernetesのデフォルトスケジューラ内の主要なスケジューリングアルゴリズムについて説明しました。注意すべき点として、本記事で取り上げたルール以外にも、Kubernetesスケジューラ内にはデフォルトでは有効になっていない戦略がいくつか存在します。kube-schedulerに設定ファイルを指定したり、ConfigMapを作成して、どのルールを有効または無効にするかを設定できます。さらに、Prioritiesに重みを設定することで、スケジューラの動作を制御することも可能です。
これでKubernetesスケジューラのデフォルトのスケジューリングメカニズムの説明を終わります。スケジューラはクラスターとPod情報のキャッシュにより高速に動作しますが、より複雑なアルゴリズムの場合、スケジューラは対象のPodとNodeだけでなく、クラスター全体の状態を考慮する必要があることを言及しておきます。これには、スケジューリングアルゴリズムの実際の実行前に、必要なクラスター情報の事前計算とキャッシュが含まれ、スケジューリングプロセスの効率性と正確性を確保します。
Novita AI は、AIの野望を実現するためのオールインワンクラウドプラットフォームです。シームレスに統合されたAPI、サーバーレスコンピューティング、GPUアクセラレーションにより、AI駆動のビジネスを迅速に構築・拡張するためのコスト効率の高いツールを提供します。インフラストラクチャの悩みを解消し、無料で始めましょう - Novita AIがあなたのAIの夢を現実にします。
おすすめの記事:
