Kubernetes 1.29: SIG-Scheduling の変更内容

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

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

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

## :pencil: 所感

前回に引き続き、今回のリリースも Kubernetes スケジューラの内部に関する変更が主となっています。

[Queueing hint 機能](https://github.com/kubernetes/kubernetes/issues/114297) に関して、Go のインタフェースにいくつかの変更が入り、プラグインの開発がしやすくなっています。
まず、プラグインで何か想定外のことが起こった場合に備えて `QueueingHintFn` がエラーを返せるようになり、エラー時に pod を unschedulable pool に残し続けてしまうバグを埋め込みにくくなりました。
また、プラグインが返す pod のスケジュール状況に `Pending` が追加され、`QueueingHintFn` が返すヒントの値は `Queue` と `QueueSkip` のみに絞られました。
クラスタイベントが起こった際に unschedulable pool にある pod をいつ（バックオフの後なのか、すぐなのか）エンキューするかは、これまでプラグイン側で決定していましたが、明確な指標がなくプラグインの開発者によって意見が別れていました。
これを解決するために、ヒントが `Queue` と評価されたとき、プラグイン側ではなくスケジューラ本体側で、pod をいつエンキューするかを pod が `Pending` だったかどうかをもとに判断されるようになりました。
プラグイン側で判断するより自然であり、かつ明確な判断指標ができたので、プラグインの開発がしやすくなると思われます。

個人的に注目したいのは、[feat: Support score extension function in preemption. by lianghao208 · Pull Request #121867 · kubernetes/kubernetes](https://github.com/kubernetes/kubernetes/pull/121867) です。
プリエンプション処理は全体の流れが別々のプラグインでも同じになることが多いため、プラグインごとにカスタムしたい評価関数などが [`"k8s.io/kubernetes/pkg/scheduler/framework/preemption".Interface`](https://github.com/lianghao208/kubernetes/blob/79040935fa7d63c6055c4d20784546093d7ad318/pkg/scheduler/framework/preemption/preemption.go#L105) インタフェースに切り出されています。
プラグインを自作する場合はこのインタフェースを実装することで簡単にプリエンプション処理が書けるようになっています。
これまで、あるノード上のプリエンプションされる pod を選ぶ処理はカスタム可能でした。
今回、スコアが同じノードが複数あった場合にその中から一つのノードを選ぶ処理もカスタムできるようになりました。
自作プラグインでこの処理をカスタムしていた場合、よりシンプルに実装できるようになる可能性があります。

なお、[In-place Update of Pod Resources](https://github.com/kubernetes/enhancements/issues/1287) はもともと Kubernetes 1.29 でのベータへの昇格を目指していましたが、1.30 以降に持ち越しになりました。

## Urgent Upgrade Notes（必ず一読してからアップグレードしなければならない事項）

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

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

### Deprecation（非推奨）

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

### API Change（API 変更）

- `kube-scheduler` の設定ファイル (`KubeSchedulerConfiguration`) について、`kubescheduler.config.k8s.io/v1beta3` バージョンが Kubernetes 1.29 で削除されました。`kube-scheduler` の設定ファイルは `kubescheduler.config.k8s.io/v1` に移行されました。([#119994](https://github.com/kubernetes/kubernetes/pull/119994), [@SataQiu](https://github.com/SataQiu)) [sig/scheduling, sig/testing]
    - :pencil: 移行方法はこちらを参照してください：[Scheduler Configuration | Kubernetes](https://kubernetes.io/docs/reference/scheduling/config/#scheduler-configuration-migrations)
- In-Place Pod Vertical Scaling 機能について Windows サポートが追加されました。([#112599](https://github.com/kubernetes/kubernetes/pull/112599), [@fabi200123](https://github.com/fabi200123)) [SIG Autoscaling, Node, Scalability, Scheduling and Windows] [sig/scalability, sig/scheduling, sig/node, sig/autoscaling, sig/windows]
- Go API: ボリュームでの使用について、`ResourceRequirements` 構造体が `VolumeResourceRequirements` に置き換えられました。([#118653](https://github.com/kubernetes/kubernetes/pull/118653), [@pohly](https://github.com/pohly)) [sig/scheduling, sig/storage, sig/node, sig/api-machinery, sig/auth, sig/apps, sig/testing]
    - :pencil: コンテナの計算リソース要求を `ResourceRequirements` で表し、ボリュームのストレージ要求を `VolumeResourceRequirements` で表すようになりました。これまで両者とも `ResourceRequirements` で表していましたが、Dynamic Resource Allocation で使う `Claims` フィールドはコンテナにしか関係ないものなので、混同を避けるため `Claims` フィールドを持たない `VolumeResourceRequirements` を導入しました。
- `kube-scheduler` の `selectorSpread` プラグインが削除されました。代わりに `podTopologySpread` プラグインを使用してください。([#117720](https://github.com/kubernetes/kubernetes/pull/117720), [@kerthcet](https://github.com/kerthcet)) [sig/scheduling]
    - :pencil: Service, ReplicaSet, または StatefulSet で管理されている pod にデフォルトの topology spread constraint をもたせるプラグインでした。同じことが、`podTopologySpread` プラグインの `defaultConstraints` 引数で設定できます。
- `matchLabelKeys` / `mismatchLabelKeys` がハード・ソフト要件ともに `PodAffinity` / `PodAntiAffinity` に導入されました。([#116065](https://github.com/kubernetes/kubernetes/pull/116065), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling, sig/api-machinery, sig/apps, sig/testing, sig/cloud-provider]
    - :pencil: [KEP-3633: Introduce MatchLabelKeys and MismatchLabelKeys to PodAffinity and PodAntiAffinity](https://github.com/kubernetes/enhancements/tree/master/keps/sig-scheduling/3633-matchlabelkeys-to-podaffinity)
    - :pencil: Kubernetes 1.27 で Pod Topology Spread Constraint の `matchLabelKeys` フィールドがベータになりましたが、本 PR は Pod Affinity / AntiAffinity に関する同様の変更です。例えば、ReplicaSet で管理されている pod 群に `matchLabelKeys: [pod-template-hash]` という条件を追加することで、ローリングアップデートの際に同じリビジョンの pod 群だけをアフィニティの計算に入れることができます。

### Feature（機能追加）

- スケジューラプラグインが返しうるステータスに新しく `Pending` が導入され、これを利用して効率的なエンキューが実現されます。`QueueingHintFn` インタフェースは、`Pending` を導入することで簡素化され、返り値は `Queue` と `QueueSkip` のみを持つように変更されました。スケジューラは、pod がスケジュールできなかった理由によって、`Queue` を `QueueAfterBackoff` として扱うか `QueueImmediately` として扱うかどうかを決定します。([#119517](https://github.com/kubernetes/kubernetes/pull/119517), [@sanposhiho](https://github.com/sanposhiho)) [SIG Node, Scheduling and Testing] [sig/scheduling, sig/node, sig/testing]
    - :pencil: Pod をいつ（バックオフの後なのか、すぐなのか）エンキューするかを、プラグインが実装する `QueueingHintFn` が 直接決定するのではなく、pod がスケジュールできなかった理由（アフィニティを満たせなかったのか、DRA がリソースを用意するまで待たなければならないのか、など）によって決定するということです。
- カスタマイズ可能な `OrderedScoreFuncs()` 関数が導入されました。プリエンプションのためのインタフェースを使用していた out-of-tree プラグインは、この関数を実装することで、プリエンプション時のノード選択をカスタムできます。また、現在の動作を維持するために nil を返すことができます。([#121867](https://github.com/kubernetes/kubernetes/pull/121867), [@lianghao208](https://github.com/lianghao208)) [sig/scheduling]
    - :pencil: プリエンプション時、最大のスコアをとったノードが複数あった場合に、どのノードにスケジュールするか決定する評価関数をカスタムできます。デフォルトでは、PDB 違反数が最小のノード（複数あればノード内の最小のプライオリティが最高のもの、まだ複数あれば別の指標で評価したノード）を選択します。
- スケジューラに新しいメトリック `pod_scheduling_sli_duration_seconds` が追加され、`pod_scheduling_duration_seconds` の非推奨化が開始されました。([#119049](https://github.com/kubernetes/kubernetes/pull/119049), [@helayoty](https://github.com/helayoty)) [sig/scheduling, sig/instrumentation, sig/testing]
    - :pencil: 前者は pod が `PreEnqueue` プラグインによりリジェクトされていた（エンキューされていなかった）時間を含まず、後者は含みます。
- `QueueingHint` にエラーを示す返り値が追加されました。もし `QueueingHint` がエラーを返す場合、スケジューラはそれをログに記録し、イベントを `QueueAfterBackoff` として扱って pod が unschedulable pool に取り残されないようにします。([#119290](https://github.com/kubernetes/kubernetes/pull/119290), [@carlory](https://github.com/carlory)) [sig/scheduling, sig/node, sig/testing]
- `TaintManager` を `NodeLifeCycleController` から切り離しました（KEP-3902）。([#119208](https://github.com/kubernetes/kubernetes/pull/119208), [@atosatto](https://github.com/atosatto)) [sig/scheduling, sig/node, sig/api-machinery, sig/apps, sig/instrumentation, sig/testing]
    - :pencil: [KEP-3902: Decouple Taint-based Pod Eviction from Node Lifecycle Controller](https://github.com/yuanchen8911/enhancements/blob/master/keps/sig-scheduling/3902-decoupled-taint-manager/README.md)
    - :pencil: NodeLifeCycleController が unhealthy なノードに `node.kubernetes.io/unreachable=:NoExecute` などの taint を付与し、TaintManager がそれに応じてノードから pod を退去させます。
- `ReadWriteOncePod` フィーチャゲートを GA に昇格しました。([#121077](https://github.com/kubernetes/kubernetes/pull/121077), [@chrishenzie](https://github.com/chrishenzie)) [sig/scheduling, sig/storage, sig/node, sig/apps, sig/testing]
- `kube-scheduler` のメモリ使用量を改善させるために、`kube-scheduler` にとって不要な `.metadata.managedFields` フィールドを削除するようにしました。([#119556](https://github.com/kubernetes/kubernetes/pull/119556), [@linxiulei](https://github.com/linxiulei)) [sig/scheduling]
    - :pencil: Informer の `SetTransform` を使い、メモリ上で informer が格納する pod からフィールドを削除したということです。
- `Permit` プラグインについて、`WaitOnPermit` 中に pod がリジェクトされた場合、スケジューラはプラグインを記録します。スケジューラはクラスタイベントが起こった際、この記録にしたがって queueing hint を計算し、pod のスケジュールを再試行するか決定します。([#119785](https://github.com/kubernetes/kubernetes/pull/119785), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling, sig/testing]
- `nodevolumelimits` スケジューラプラグインを [contextual logging](https://k8s.io/docs/concepts/cluster-administration/system-logs/#contextual-logging) を使用するように移行しました。([#116884](https://github.com/kubernetes/kubernetes/pull/116884), [@mengjiao-liu](https://github.com/mengjiao-liu)) [sig/scheduling, sig/storage, sig/node, sig/instrumentation, sig/testing]
- `volumebinding` スケジューラプラグインを [contextual logging](https://k8s.io/docs/concepts/cluster-administration/system-logs/#contextual-logging) を使用するように移行しました。([#116803](https://github.com/kubernetes/kubernetes/pull/116803), [@mengjiao-liu](https://github.com/mengjiao-liu)) [sig/scheduling, sig/storage, sig/instrumentation]
- `volume_zone` プラグインは、スケジューリング処理中に `beta` ラベルを `GA` ラベルとして扱います。したがって、ラベルの値が同じであれば、`beta` ラベルを持つ PV も `GA` ラベルを持つノードにスケジュールできます。 ([#118923](https://github.com/kubernetes/kubernetes/pull/118923), [@AxeZhan](https://github.com/AxeZhan)) [sig/scheduling]
    - :pencil: Kubernetes 1.17 から `failure-domain.beta.kubernetes.io/{region,zone}` ラベルが非推奨になっており `topology.kubernetes.io/{region,zone}` に置き換えられていることへの対応です。
- DRA: スケジューラプラグインは、いくつかの場合において追加のスケジューリング試行を避けるために、競合後に SSA にフォールバックすることで対処します。([#120534](https://github.com/kubernetes/kubernetes/pull/120534), [@pohly](https://github.com/pohly)) [sig/scheduling, sig/node, sig/testing]
    - :pencil: PodSchedulingContext の更新操作が楽観的並行性制御のコンフリクトで失敗したときに SSA を試します。SSA は JSON のエンコーディングなどにより高コストとのことなので、失敗したときのみフォールバックします。
- `NodeUnschedulable` プラグインにスケジューリングヒントを実装しました。スケジューリングヒントにより、新しいノードが作成されたときと、ノードの `.spec.unschedulable` が false に設定されたときにのみ、`NodeSchedulable` プラグインによって以前にリジェクトされた pod のスケジューリングを再試行します。([#119396](https://github.com/kubernetes/kubernetes/pull/119396), [@wackxu](https://github.com/wackxu)) [sig/scheduling]
- `NodeAffinity` プラグインにスケジューリングヒントを実装しました。スケジューリングヒントにより、新しいノードが作成されたときと、ノードの更新が pod のノードアフィニティに一致する場合にのみ、`NodeAffinity` プラグインによって以前にリジェクトされた pod のスケジューリングを再試行します。([#119155](https://github.com/kubernetes/kubernetes/pull/119155), [@carlory](https://github.com/carlory)) [sig/scheduling]

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

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

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

- DRA (Dynamic Resource Allocation):スケジューラが pod に対してノードが不適合になった後にリソース要求を解放する必要があったとき、実際に必要なより多くのリソース割当てと解放が必要になることがありました。このバグは最初に割当てを無効にすることで修正されました。([#120428](https://github.com/kubernetes/kubernetes/pull/120428), [@pohly](https://github.com/pohly)) [sig/scheduling, sig/node]

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

- 一時的な障害（例：`kube-apiserver` の一時的な障害）によって unschedulable になった pod について、より正確に再エンキューされるようになりました。([#119105](https://github.com/kubernetes/kubernetes/pull/119105), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling, sig/testing]
    - :pencil: プラグイン起因でない理由で unschedulable になった pod が、unschedulable pool でイベントを待ち続けてしまうのではなく、backoff キューに戻されるようになりました。
- Kubernetes 1.27 でのリグレッションが修正されました。前の `PreFilter` プラグインが `Skip` を返した場合、`PostFilter` プラグインが機能しない可能性がありました。 ([#119769](https://github.com/kubernetes/kubernetes/pull/119769), [@Huang-Wei](https://github.com/Huang-Wei)) [sig/scheduling, sig/testing]
- Kubernetes 1.26 のリグレッションが修正されました。`PreFilter` プラグインが `UnschedulableAndUnresolvable` を返した場合は、プリエンプション処理がスキップされるようになりました。([#119778](https://github.com/kubernetes/kubernetes/pull/119778), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling, sig/testing]
- Kubernetes 1.28 でのリグレッションが修正されました。Pod にイベントが並列に起こった場合、pod が誤って unschedulable キューに移動され、イベントが起こらない場合、次の定期的なフラッシュまで 5 分間スケジュールされないことがありました。([#120413](https://github.com/kubernetes/kubernetes/pull/120413), [@pohly](https://github.com/pohly)) [sig/scheduling]
- `PodDisruptionConditions` フィーチャゲートが有効であるデフォルトの設定におけるリグレッションが修正されました。コントロールプレーンによる pod のガベージコレクタが、重複したキーをもつフィールド（環境変数やコンテナのポート）をもつ pod を削除できなくなっていました。([#121103](https://github.com/kubernetes/kubernetes/pull/121103), [@mimowo](https://github.com/mimowo)) [sig/scheduling, sig/node, sig/auth, sig/apps, sig/testing]
    - :pencil: このフィーチャゲートは pod に `DisruptionTarget` コンディションを付与しますが、このような pod に対して SSA での更新操作が失敗し、削除もできなくなっていました。SSA の代わりに PATCH を使うようにして回避しました。
- Kubernetes 1.27 からスケジューラフレームワークにあったリグレッションが修正されました。`skippedScorePlugins` の数が `enabledScorePlugins` よりも大きくなる可能性があり、スライスの初期時に `cap(len(skippedScorePlugins) - len(enabledScorePlugins))` が負になってしまう問題がありました。([#121632](https://github.com/kubernetes/kubernetes/pull/121632), [@kerthcet](https://github.com/kerthcet)) [sig/scheduling]
- 時折、スケジューラが pod を backoff キューではなく unschedulable pool に誤って配置してしまう状況が修正されました。これは、以前に何らかのプラグインが pod を unschedulable と判定し、後の試行で他のエラーが起こった場合に発生していました。その pod のスケジュールは、最大 5 分後の定期的なフラッシュにより active キューに戻さるまで遅れることになっていました。([#120334](https://github.com/kubernetes/kubernetes/pull/120334), [@pohly](https://github.com/pohly)) [sig/scheduling]
- `ImageLocality` プラグインでのスコアリングに影響する、あるコンテナイメージをもつノードの数の計算における不整合が修正されました。([#116938](https://github.com/kubernetes/kubernetes/pull/116938), [@olderTaoist](https://github.com/olderTaoist)) [sig/scheduling]
- Kubernetes 1.29 プレリリースにあった、contextual logging を有効にすると pod のスケジューリングが遅くなる問題が修正されました。([#121715](https://github.com/kubernetes/kubernetes/pull/121715), [@pohly](https://github.com/pohly)) [SIG Instrumentation and Scheduling] [sig/scheduling, sig/instrumentation]
- Taint manager が報告するイベントから `apiVersion` フィールドが抜けていた問題が修正されました。([#114095](https://github.com/kubernetes/kubernetes/pull/114095), [@aimuz](https://github.com/aimuz)) [sig/scheduling, sig/node, sig/apps]

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

- スケジューラの残りの部分を [contextual logging](https://k8s.io/docs/concepts/cluster-administration/system-logs/#contextual-logging) を使用するように移行しました。([#120933](https://github.com/kubernetes/kubernetes/pull/120933), [@mengjiao-liu](https://github.com/mengjiao-liu)) [SIG Instrumentation, Scheduling and Testing] [sig/scheduling, sig/instrumentation, sig/testing]
- `NodeUnschedulable` プラグインの `Filter` 拡張点を最適化して不要な計算を回避しました。 ([#119399](https://github.com/kubernetes/kubernetes/pull/119399), [@wackxu](https://github.com/wackxu)) [sig/scheduling]
- デバッグを容易にしつつ透明性を安全に確保するため、プリエンプションのイベントメッセージに、プリエンプションした pod の UID を追加しました。([#119971](https://github.com/kubernetes/kubernetes/pull/119971), [@kwakubiney](https://github.com/kwakubiney)) [SIG Scheduling] [sig/scheduling]
    - :pencil: Kubernetes 1.27 で、他のネームスペースの存在や、その中の pod 名が漏洩することを防ぐために、これらの情報がイベントメッセージから除かれていました。
- `LegacyServiceAccountTokenNoAutoGeneration` フィーチャゲートが削除されました。（この機能は GA されており、常に有効です）。([#120192](https://github.com/kubernetes/kubernetes/pull/120192), [@SataQiu](https://github.com/SataQiu)) [SIG Apps, Auth and Scheduling] [sig/scheduling, sig/auth, sig/apps]
    - :pencil: ServiceAccount の有効期限のないトークンを Secret として自動作成することをやめるフィーチャゲートです。
- `ComponentSLIs` フィーチャゲートによって制御され、`/metrics/slis` で提供される メトリクスが GA に昇格し、無条件に有効化されるようになりました。このフィーチャゲートは `v1.31` で削除されます。([#120574](https://github.com/kubernetes/kubernetes/pull/120574), [@logicalhan](https://github.com/logicalhan)) [sig/network, sig/scheduling, sig/node, sig/api-machinery, sig/instrumentation, sig/architecture, sig/cloud-provider]
- `PreEnqueue`, `PreFilter`, `Filter`, `Reserve`, `Permit` 以外のプラグインが実装する `EnqueueExtensions` は無視されるようになりました。これにより、スケジューラがサブスクライブ、処理する必要があるクラスタイベントの種類が減少します。([#121571](https://github.com/kubernetes/kubernetes/pull/121571), [@sanposhiho](https://github.com/sanposhiho)) [sig/scheduling]
    - :pencil: これらのプラグイン以外は、プラグイン起因で pod を unschedulable と判定しないためです。
- `GetPodQOS(pod *core.Pod)` 関数は、セットされている場合は `PodStatus.QOSClass` の格納値を返すようになりました。`QOSClass` の値をゼロから計算するには、`ComputePodQOS(pod*core.Pod)` を使用する必要があります。([#119665](https://github.com/kubernetes/kubernetes/pull/119665), [@vinaykul](https://github.com/vinaykul)) [sig/scheduling, sig/node, sig/api-machinery, sig/apps, sig/cli, sig/testing]
    - :pencil: QoS クラスとは Guaranteed / Burstable / BestEffort のことです。
- `ResourceClass` が存在しないために unschedulable となった pod の処理が少し効率的になり、周期的なリトライに依存しなくなりました。([#120213](https://github.com/kubernetes/kubernetes/pull/120213), [@pohly](https://github.com/pohly)) [sig/scheduling, sig/node, sig/testing]
    - :pencil: ResourceClass の作成・更新イベントを契機に pod のスケジュールをリトライするようになりました。