OpenShift 4.6までの古い内容です。OpenShift 4.7からはSelectorSpreadではなくPodTopologySpreadとなります。
Red HatでOpenShiftのサポートをしているid:nekopです。OpenShift 全部俺 Advent Calendar 2018 - Qiitaの2日目のエントリです。投稿日は12/3ですが細かいことは気にしないでゆるゆるやっていくポリシーです。
OpenShiftのデフォルトのスケジュール設定は/etc/origin/master/scheduler.json
にあり、プライオリティは以下の定義となっています。ファイル形式はjsonですがjsonだと行数かさむのでyaml形式に変換して転記しています。
priorities: - name: SelectorSpreadPriority weight: 1 - name: InterPodAffinityPriority weight: 1 - name: LeastRequestedPriority weight: 1 - name: BalancedResourceAllocation weight: 1 - name: NodePreferAvoidPodsPriority weight: 10000 - name: NodeAffinityPriority weight: 1 - name: TaintTolerationPriority weight: 1 - argument: serviceAntiAffinity: label: zone name: Zone weight: 2
SelectorSpreadPriority
によってノード障害耐性を高めるために同種Podは同一ノードにスケジュールされない、というところが基本にはなるのですが、LeastRequestedPriority
などリソースの都合によってはこの「同種Podは同一ノードにスケジュールされない」というプライオリティが常に動作しない状況になったりしないか?という疑問が残ります。
裏をとるためSelectorSpreadPriority
のソースコードを見てみましょう。k8s 1.11です。
計算式を自然言語で記述すると以下のようになります。
10 * (既にスケジュールされている対象Pod数 - このノード上の対象Pod) / 既にスケジュールされている対象Pod数
nodeA, nodeBがあり、1 podが既にnodeAにスケジュールされているときの2 pod目のスケジュールを考えてみます。nodeAのプライオリティスコアは10 * (1 - 1) / 1 = 0
となるので0になります。一方nodeBは10 * (1 - 0) / 1 = 10
となるので、満点の10が返却されます。
比較対象として、ノードのリソースを考慮するLeastRequestedPriority
などを見てみます。
CPUとメモリについて以下の計算を行って平均しているので、例えば80%使用中のノードに10%利用するリクエストのPodをスケジュールする場合は(20 - 10) * 10 / 20 = 5
となります。残キャパシティが50%であれば8ですね。相当埋まっていてもそこそこのプライオリティスコアが返却されるようです。
(残キャパシティ - 対象Podのリクエスト) * 10 / 残キャパシティ
というわけで、SelectorSpreadPriority
のキモは2 pod目のスケジュールです。2 pod目のスケジューリング時に少なくとも既にスケジュールされているノードとそうでないノードとのプライオリティスコアが10という大差がつくので、2 pod目で2ノードにきちんと分散される、ということがわかります。もちろん他のプライオリティで10以上の差が出るようなスコアが算出されない限り、という条件はつきますが、他のプライオリティはここまで極端な差はでないので問題なさそうです。3 pod目以降のケースでは、リソース利用がかたよっている場合にプライオリティスコアが逆転するので偏ったスケジュール結果になることもありそうですし、実際やってみたら偏りました。これを防止するにはプライオリティのweightを調整すればできそうです。