Kubernetes 1.30: SIG-Scheduling の変更内容

Kubernetes 1.30 の [CHANGELOG](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md) から、SIG-Scheduling に関するところを抜粋して紹介します。
:pencil: は筆者によるコメントです。

過去 3 リリースの変更内容：

- [Kubernetes 1.29: SIG-Scheduling の変更内容](https://qiita.com/ordovicia/items/e99d8ab6ca3b540b70e1)
- [Kubernetes 1.28: SIG-Scheduling の変更内容](https://qiita.com/ordovicia/items/df66b4f3712f1783c62a)
- [Kubernetes 1.27: SIG-Scheduling の変更内容](https://qiita.com/ordovicia/items/6046be0f50f999cdb063)

## :pencil: 所感

前回に引き続き、今回のリリースも Kubernetes スケジューラ内部での最適化やバグ修正が主な内容となっています。

ユーザや運用者に関わる変更としては、二つの API が GA に昇格しました。

[Pod Scheduling Readiness](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-scheduling-readiness/) では、
Pod がスケジュール可能かどうかを制御でき、スケジュール可能でない間の無駄なスケジューリング処理を回避できます。
動的なクオータ制御、Pod どうしに依存関係をもたせる、計算リソースのプロビジョニングが完了するまで Pod のスケジューリング処理を待機させるなどの応用が考えられます。

[Pod Topology Spread Constraints](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/) の `minDomains` フィールドを使うと、
Pod を分散させるドメインの最小数を定義できます。
例えば `minDomains: 3` とすると、いま二つの Pod があり二つのドメインに一つずつスケジュールされている場合、新しく Pod を作ると（`maxSkew: 1` の場合）必ず三つ目のドメインにスケジュールしようとします。
このときもしドメインが二つしか存在しないと、Pod のスケジュールに失敗します。
ここで Cluster Autoscaler がはたらくと、ノードを作成して新しいドメインを用意し、新しい Pod はこのノードにスケジュールされるので、晴れて 3つのドメインに分散できます。

`minDomains` は Cluster Autoscaler のある環境を想定した機能なので、個人的にはあまり使う機会はなさそうなのですが、
Pod Scheduling Readiness は動的なクオータ制御などでクラスタの計算リソースの利用効率を高めるために役立てられそうだと考えています。

なお、[In-place Update of Pod Resources](https://github.com/kubernetes/enhancements/issues/1287) の開発は引き続き進んでいるようですが、ベータへの昇格は 1.31 以降に持ち越しになりました。

## Changes by Kind（種類別の変更）

### Deprecation（非推奨）

SIG-Scheduling に関するものはありません。

### API Change（API 変更）

- Dynamic Resource Allocation: DRA ドライバが「構造化パラメータ」を使い、スケジューラにリソース割り当て要求を処理させることができるようになりました。([#123516](https://github.com/kubernetes/kubernetes/pull/123516), [@pohly](https://github.com/pohly)) [sig/scheduling,sig/storage,sig/node,sig/api-machinery,sig/cluster-lifecycle,sig/auth,sig/apps,sig/cli,sig/instrumentation,sig/testing,sig/release]
    - :pencil: [KEP-4381: Structured Parameters for Dynamic Resource Allocation](https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/4381-dra-structured-parameters)
    - :pencil: これまでは DRA が扱うリソース要求のパラメータが opaque だったため、Pod スケジューリング時に kube-scheduler が DRA ドライバと通信する必要がありました。
      この変更により、Kubernetes で定義された構造化パラメータによってスケジューラがリソースの「モデル」を解釈できるようになり、DRA ドライバとの通信なしでスケジューリングできるようになります。
      Cluster Autoscaler などもリソースの使用状況を解釈してはたらくことができます。
- `volumeBinding` プラグインに `PreScore` 拡張点を実装しました。これは、`Score` 拡張点で何もおこなわない場合に `Skip` を返します。([#115768](https://github.com/kubernetes/kubernetes/pull/115768), [@AxeZhan](https://github.com/AxeZhan)) [sig/scheduling,sig/storage,sig/testing]
    - :pencil: Pod が静的なボリュームを必要としているときのみ `Score` を呼びます。
- Pod Scheduling Gate が GA に昇格しました。`PodSchedulingReadiness` フィーチャゲートはもう効果がなく、`spec.schedulingGates` フィールドは Pod および PodTemplate で常に利用可能です。([#123575](https://github.com/kubernetes/kubernetes/pull/123575), [@Huang-Wei](https://github.com/Huang-Wei)) [sig/scheduling,sig/node,sig/api-machinery,sig/apps,sig/testing]
- Pod topology spread cnstraint での `minDomains` が GA に昇格しました。`MinDomainsInPodTopologySpread` フィーチャゲートはもう効果がなく、このフィールドは Pod および PodTemplate で常に利用可能です。([#123481](https://github.com/kubernetes/kubernetes/pull/123481), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling,sig/api-machinery,sig/apps,sig/testing]
- `ResourceClaims` をもつ Pod ともたない Pod が混在するとき、`ResourceClaims` をもつ Pod のスケジューリング処理が全体のスケジューリング処理のレイテンシに与える影響が小さくなりました。([#121876](https://github.com/kubernetes/kubernetes/pull/121876), [@pohly](https://github.com/pohly)) [sig/scheduling,sig/node,sig/api-machinery,sig/testing]
- client-go でイベントを扱う際、contextual logging を有効にしたい場合は `NewEventBroadcasterAdapter` ではなく `NewEventBroadcasterAdapterWithContext` の使用が推奨されています。([#122142](https://github.com/kubernetes/kubernetes/pull/122142), [@pohly](https://github.com/pohly)) [sig/scheduling,sig/api-machinery,sig/instrumentation]

### Feature（機能追加）

- `io.Closer` を実装したスケジューラプラグインを graceful に閉じられるようになりました。([#122498](https://github.com/kubernetes/kubernetes/pull/122498), [@Gekko0114](https://github.com/Gekko0114)) [sig/scheduling]
    - :pencil: WebAssembly をロードするプラグインで mmap したメモリを解放するユースケースがあるようです。
- Pod に対してすべき処理がないとき、スケジューラは `NodeAffinity` プラグインの `Score` 拡張点をスキップします。プラグインが必要な時だけ動作するようになるので、`plugin_execution_duration_seconds` メトリックで `extension_point=score` かつ `plugin=NodeAffinity` の値が変わるかもしれません。([#117024](https://github.com/kubernetes/kubernetes/pull/117024), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling,sig/testing]
- スケジューラのいくつかのインターフェイスのシグネチャが変更されました。
  - `PluginsRunner`: `RunPreScorePlugins` と `RunScorePlugins` メソッドで `NodeInfo` を使用します。
  - `PreScorePlugin`: `PreScore` メソッドで `NodeInfo` を使用します。
  - `Extender`: `Filter` と `Prioritize` で `NodeInfo` を使用します。([#121954](https://github.com/kubernetes/kubernetes/pull/121954), [@AxeZhan](https://github.com/AxeZhan)) [sig/scheduling,sig/storage,sig/node,sig/autoscaling,sig/testing]
  - :pencil: 一貫して `Node` ではなく `NodeInfo` 構造体を使うようになりました。`NodeInfo` は `Node` に加え、ノードに割り当てられている Pod のリストや、リソース要求量の合計などの情報をもっています。
- `NodeUnschedulable` プラグインにスケジューリングヒントを実装しました。スケジューリングヒントにより、新しいノードが作成されたときと、ノードの `.spec.unschedulable` が false に設定されたときにのみ、`NodeSchedulable` プラグインによって以前にリジェクトされた Pod のスケジューリングを再試行します。([#122334](https://github.com/kubernetes/kubernetes/pull/122334), [@carlory](https://github.com/carlory)) [sig/scheduling]
    - :pencil: Kubernetes 1.29 でも同様の変更が入っていましたが、下のバグがあったためリバートされていました。今回入った変更は、このバグがないよう修正したものです。
    - :pencil: https://github.com/kubernetes/kubernetes/issues/122284
- `NodeAffinity` プラグインにスケジューリングヒントを実装しました。スケジューリングヒントにより、新しいノードが作成されたときと、ノードの更新が Pod のノードアフィニティに合うときにのみ、`NodeSchedulable` プラグインによって以前にリジェクトされた pod のスケジューリングを再試行します。([#122309](https://github.com/kubernetes/kubernetes/pull/122309), [@carlory](https://github.com/carlory)) [sig/scheduling]
- `NodeResourceFit` プラグインにスケジューリングヒントを実装しました。スケジューリングヒントにより、新しいノードが作成されたとき、ノードの更新が Pod のリソース要求に合うとき、または既存の Pod の更新または削除が Pod のリソース要求と合うときにのみ、`NodeResourceFit` プラグインによって以前にリジェクトされた Pod のスケジューリングを再試行します。([#119177](https://github.com/kubernetes/kubernetes/pull/119177), [@carlory](https://github.com/carlory)) [sig/scheduling]
- kube-scheduler は、関連する Pod が作成、削除、または更新されたとき、およびノードが指定された `topologyKey` に合うときに、以前に `PodTopologySpread` プラグインにリジェクトされた Pod のスケジューリングを再試行します。([#122195](https://github.com/kubernetes/kubernetes/pull/122195), [@nayihz](https://github.com/nayihz)) [sig/scheduling]
    - :pencil: これもスケジューリングヒント機能による最適化です。
- コンテナイメージの存在場所に基づいたノード選択を見直しました。kube-scheduler は、init コンテナと（`SidecarContainers` が有効なクラスタの場合）サイドカーコンテナについても、必要なコンテナイメージをノードがもっているか考慮します。([#123366](https://github.com/kubernetes/kubernetes/pull/123366), [@kerthcet](https://github.com/kerthcet)) [sig/scheduling]
    - :pencil: `ImageLocality` プラグインは、Pod が必要とするコンテナイメージをすでに取得済みのノードを高くスコアリングします。
      これまでは init コンテナで大きなイメージを使うことは稀だということで考慮されていませんでしたが、例えば推論サーバで重みを格納した init コンテナを使うユースケースがあるとのことで、init コンテナも考慮されるようになりました。
- スケジューラ extender の `ignorable` オプションは、Filter と Bind の両方のフェイズでエラーを扱うようになりました。([#122503](https://github.com/kubernetes/kubernetes/pull/122503), [@sunbinnnnn](https://github.com/sunbinnnnn)) [sig/scheduling]
- スケジューラは、PVC が見つからないために `NodeVolumeLimits` プラグインによって失敗した Pod を、新しい PVC が追加されたときだけ再試行します。([#121952](https://github.com/kubernetes/kubernetes/pull/121952), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling,sig/storage]
- `IterateOverWaitingPods` メソッドを使い Permit ステージで待っているすべての Pod を走査できます。つまり、任意のプロファイルからスケジューラ内のすべての `waitingPods` を取得できます。これまでは個々のプロファイルはそのプロファイル内の `waitingPods` のみを取得できました。([#122946](https://github.com/kubernetes/kubernetes/pull/122946), [@NoicFank](https://github.com/NoicFank)) [sig/scheduling]
    - :pencil: リリースノートには挙げられていますが、実際にはこの変更は [#124001](https://github.com/kubernetes/kubernetes/pull/124001) でリバートされました。
- `PreFilter` 拡張点が特定のノードを除外した場合、スケジューリングフレームワークはそれらを `UnschedulableAndUnresolvable` ケースでリジェクトされたと分類します。結果として、これらのノードはプリエンプション処理の候補から除外されます。さらに、この変更ではスケジューリングフレームワークが `PreFilter` からの `Unschedulable` ステータスをどのように処理するかが修正されています。以前は、`PreFilter` が `Unschedulable` を返した場合、プリエンプション処理の中断が予期せず発生する可能性がありました。これはデフォルトのスケジューラでは発生しませんが、カスタムプラグインがあるスケジューラでは発生する可能性があります。([#119779](https://github.com/kubernetes/kubernetes/pull/119779), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling]
    - :pencil: 一部の `PreFilter` 拡張点しか呼ばれなかった場合、他の `PreFilter` プラグインで前処理として計算されるはずだった結果が `cycleState`（一つのスケジューリングサイクル内での状態）に格納されません。
      すると、この Pod がプリエンプション処理を起こしたとき、`cycleState` にあるべき計算結果がないため処理できません。
      そこで、この変更ではプリエンプションが起こる可能性がある場合はすべての `PreFilter` 拡張点を呼ぶようになりました。

### Documentation（ドキュメント改善）

- 廃止予定のフラグ `--pod-max-in-unschedulable-pods-duration` は当初 v1.26 で削除される予定でしたが、この計画を変更しました。Pod が 5分間 unschedulable pod pool に止まってしまう [問題](https://github.com/kubernetes/kubernetes/issues/110175) を見つけ、このフラグを使用するのがこの問題を回避する唯一のワークアラウンドでした。この問題はカスタムプラグインを使用するか、またはスケジューラの設定で使用するプラグインを変更する場合にのみ発生します。([#122013](https://github.com/kubernetes/kubernetes/pull/122013), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling]

### Failing Test（失敗しているテスト）

- 「異なるスケジューラプロファイル間で `waitingPods` を共有する」ための変更をリバートしました。([#124001](https://github.com/kubernetes/kubernetes/pull/124001), [@kerthcet](https://github.com/kerthcet)) [sig/scheduling]

### Bug or Regression（バグ修正）

- 1.24 からスケジューリングフレームワークに存在していた、マルチポイントプラグイン（デフォルトのプラグインも含む）をオーバーライドするときのリグレッションを修正しました。誤ったループロジックにより、プラグインが複数回ロードされる可能性があり、結果的にすべての Pod がスケジュールされない、という予期せぬ状況を引き起こす可能性がありました。([#122068](https://github.com/kubernetes/kubernetes/pull/122068), [@caohe](https://github.com/caohe)) [sig/scheduling]
    - :pencil: マルチポイントとは、拡張点（`Score` や `Filter` など）単位ではなく、プラグインが実装している拡張点をまとめて有効化・無効化できる機能です。
- `pod_scheduling_duration_seconds` が非推奨になったバージョンの表記を修正しました。1.28 ではなく、正しくは 1.29 でこのメトリックがデフォルトで非表示になっていました。([#123038](https://github.com/kubernetes/kubernetes/pull/123038), [@alculquicondor](https://github.com/alculquicondor)) [sig/scheduling,sig/instrumentation]
    - :pencil: このメトリックは、Pod が `PreEnqueue` 拡張点でリジェクトされていた時間を含む、Pod のスケジュールにかかった時間です。1.31 で削除される予定です。代わりに、`pod_scheduling_sli_duration_seconds` を使うことが推奨されています。
- スコアリングプラグインが定義されていない場合のスケジューラのパフォーマンスを向上させました。([#122058](https://github.com/kubernetes/kubernetes/pull/122058), [@aleksandra-malinowska](https://github.com/aleksandra-malinowska)) [sig/scheduling]
- スコアリングプラグインが定義されていない場合のスケジューラのパフォーマンスを向上させました。([#122435](https://github.com/kubernetes/kubernetes/pull/122435), [@aleksandra-malinowska](https://github.com/aleksandra-malinowska)) [sig/scheduling]
- スコアリングプラグインが定義されていない場合のスケジューラのパフォーマンスを向上させました。([#123384](https://github.com/kubernetes/kubernetes/pull/123384), [@aleksandra-malinowska](https://github.com/aleksandra-malinowska)) [sig/scheduling]
    - :pencil: テストが flaky だったため何度か修正を繰り返しました。リリースノートが若干不正確ですが、正しくはスコアリングやフィルタリングする extender もプラグインもないときの最適化のようです。
- 以前は、スケジューリングキューは extender の失敗を検知せず、クラスタイベントが見逃されたり、最悪の場合、extender にリジェクトされた Pod が最大 5分間 unschedulable pod pool にとどまり続ける可能性がありました。この変更により、スケジューリングキューは extender の失敗を検知し、extender にリジェクトされた Pod を適切に再キューにします。([#122022](https://github.com/kubernetes/kubernetes/pull/122022), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling]
- Pod がスケジュール可能になるイベントが見逃される可能性のあるシナリオが見つかったため、`NodeAffinity` のキューイングヒント実装がリバートされました。([#122285](https://github.com/kubernetes/kubernetes/pull/122285), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling]
- NodeAdded イベントを持っているが UpdateNodeTaint イベントを持っていないプラグインに対して UpdateNodeTaint イベントを登録することで、NodeAdded キューイングヒントの効率を改善しました。これにより再キューの効率が向上し、Pod が unschedulable pod pool にとどまるのを防ぎます。([#122292](https://github.com/kubernetes/kubernetes/pull/122292), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling,sig/storage,sig/node,sig/testing]
    - :pencil: ノードがクラスタに追加されたがまだ ready でないとき、NodeAdded イベントはプラグインに通知されません。したがって、ノードが後に ready になった後も、Pod が再キューされない場合がありました。
      対策として NodeAdded イベントを登録しているプラグインすべてに UpdateNodeTaint イベントも追加し、ノードが ready になったイベントを捕捉できるようにしました。
- Pod がスケジュール可能になるイベントが見逃される可能性のあるシナリオが見つかったため、`NodeUnschedulable` のキューイングヒント実装がリバートされました。([#122288](https://github.com/kubernetes/kubernetes/pull/122288), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling]
- DRA: リソースの即時割当てクレームを参照する Pod がスケジュールされなかった場合、スケジューラは誤ってそのクレームの解放を試みる可能性がありました。([#122415](https://github.com/kubernetes/kubernetes/pull/122415), [@pohly](https://github.com/pohly)) [sig/scheduling,sig/node]

### Other (Cleanup or Flake)（その他）

- スケジューラでの再キュー処理において、ワイルドカードのクラスタイベントを登録しても機能していなかったバグを修正しました。([#123117](https://github.com/kubernetes/kubernetes/pull/123117), [@kerthcet](https://github.com/kerthcet)) [sig/scheduling]
    - :pencil: `ClusterEvent { Resource: "*", ActionType: All }` のようにワイルドカードのイベントを定義でき、これを登録すると任意のイベントが起こったときにキューイングヒント機能を呼び出せます。