Kubernetes 1.27: SIG-Scheduling の変更内容

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

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

- [Kubernetes 1.26: SIG-Scheduling の変更内容](https://qiita.com/everpeace/items/8ffce0195f7d8371c54f)
- [Kubernetes 1.25: SIG-Scheduling の変更内容](https://qiita.com/everpeace/items/b2bb8a0b02a8b30c9299)
- [Kubernetes 1.24: SIG-Scheduling の変更内容](https://qiita.com/everpeace/items/3cf879bfe1464947572b)

## :pencil: 所感

今回は SIG-Scheduling に関わる変更が多いリリースです。そのうちでも、以下の二つがとくに大きい変更でしょう。

- [KEP-1287: In-place Update of Pod Resources](https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/1287-in-place-update-pod-resources)
- [KEP-3063: Dynamic resource allocation](https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/3063-dynamic-resource-allocation)

### KEP-1287: In-place Update of Pod Resources

これまで、pod に割り当てる計算リソース量、つまり Pod リソースの `.spec.containers[].resources` フィールドの値は変更不可能でした。
そのため、割り当てる計算リソース量を変えたいときは、新しい値を指定して pod を作り直す必要がありました。

In-place Update of Pod Resources では、pod を再作成することなく、そのコンテナに割り当てる計算リソース量を変更することができるようになります。
つまり、pod の in-place な垂直方向のスケーリングが可能になります。
この機能を使うと、データベースや実行時間の長いバッチジョブなど、再作成のコストが高い pod について、割り当てる計算リソース量が調整しやすくなるでしょう。

この機能は 2018 年ころから提案されており、CRI の変更も必要になるなど非常に影響範囲の大きい機能でしたが、Kubernetes 1.27 でアルファとして取り込まれました。
Kubernetes 1.29 でのベータへの昇格を目指しているようです。
ベータでは、Pod リソースに `/resize` というサブリソースが追加され、これを通して計算リソース量の変更をリクエストするようになる予定です。

### KEP-3063: Dynamic resource allocation

Dynamic resource allocation は、GPU や FPGA など拡張計算リソースの割り当てを管理する機能です。
現在のデバイスプラグインと比べ、ノードに紐付かない計算リソースを扱えるなど、柔軟性が増しています。

Kubernetes 1.26 でアルファとして入った機能ですが、Kubernetes 1.27 でも開発が進んでいます。

この機能は SIG-Node がメインに扱っているので、詳しい説明は SIG-Node の記事に譲ります。
また、Kubernetes 公式ドキュメントにも記載があります：[Dynamic Resource Allocation | Kubernetes](https://kubernetes.io/docs/concepts/scheduling-eviction/dynamic-resource-allocation)

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

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

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

### :wastebasket: Deprecation（非推奨）

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

### :earth_asia: API Change（API 変更）

- Pod のコンディションの `DisruptionTarget` type について、`PreemptionByKubeScheduler` という reason が `PreemptionByScheduler` に変更されました。([#114623](https://github.com/kubernetes/kubernetes/pull/114623), [@Huang-Wei](https://github.com/Huang-Wei))
  - :pencil: `DisruptionTarget` は Kubernetes 1.25 から導入された type です ([Disruptions | Kubernetes](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/#pod-disruption-conditions))。Kubernetes 1.27 からは、このコンディションの reason が `PreemptedByScheduler` であることで、その pod がプリエンプションされたことを判定するようになりました。
- `resource.k8s.io/v1alpha1.PodScheduling` は `resource.k8s.io/v1alpha2.PodSchedulingContext` に改名されました。([#116556](https://github.com/kubernetes/kubernetes/pull/116556), [@pohly](https://github.com/pohly))
  - :pencil: Dynaic Resource Allocation の API で、pod のスケジューリングに関わる情報をコントロールプレーンとリソースのドライバとのあいだで調整するために使われます。
- `InterPodAffinity` スケジューラプラグインに、いまスケジュール処理中の pod が preferred inter-pod affinity をもっていない場合、クラスタ上にすでにある pod の inter-pod affinity を無視するオプションを追加しました。このオプションを有効にすると、スケジューリングのスループットを向上させられる可能性があります（代わりに、クラスタ上の pod がもつ inter-pod affinity に対して最適でないスケジューリング結果になる、あるいは違反する可能性があります）。このオプションを有効にするには、`InterPodAffinity` プラグインのオプションで `ignorePreferredTermsOfExistingPods: true` と設定します。([#114393](https://github.com/kubernetes/kubernetes/pull/114393), [@danielvegamyhre](https://github.com/danielvegamyhre))
  - :pencil: Inter-pod affinity は、2 つの pod 群のあいだで双方向に設定されることが多いです。つまり、いまスケジュール処理中の pod が preferred inter-pod affinity をもたない場合、クラスタ上の pod はスケジュール処理中の pod に対する inter-pod affinity をもたない可能性が高いです。このとき、クラスタ上の pod をすべて参照して inter-pod affinity をチェックすることは無駄な処理になります。本オプションを有効にすることで、クラスタ上の pod 数に比例する計算を削減することができます。
- Pod の `topologySpreadConstraints` フィールドにおいて、`labelSelector` が設定されていないとき、`matchLabelKeys` の指定を禁止するようになりました。([#116535](https://github.com/kubernetes/kubernetes/pull/116535), [@denkensk](https://github.com/denkensk))
  - :pencil: `matchLabelKeys` による pod の選択は `labelSelector` による選択と AND で組み合わされ、`labelSelector` が未指定 (null) のときはどの pod も選択しないので、`matchLabelKeys` だけを指定することには意味がありません。
- `resource.k8s.io` API の `AllocationResult` struct に破壊的変更が入りました。この変更により、Dynamic resource allocation をおこなう kubelet プラグインで、複数のリソースのドライバからリソースを割り当てることができるようになります。([#116332](https://github.com/kubernetes/kubernetes/pull/116332), [@klueska](https://github.com/klueska))
- リーダー選出をおこなう Kubernetes のコンポーネントが、 Leases API を使う方法のみをサポートするようになりました。([#114055](https://github.com/kubernetes/kubernetes/pull/114055), [@aimuz](https://github.com/aimuz))
  - :pencil: kube-scheduler に加え、kube-controller-manager にもこの変更が入っています。
- Pod Scheduling Readiness で gate されている pod について、node selector と node affinity が可変になりました（追加のみが可能で、削除と既存の設定の更新はできません）。([#116161](https://github.com/kubernetes/kubernetes/pull/116161), [@danielvegamyhre](https://github.com/danielvegamyhre))
  - :pencil: ユースケースの例として、ワークロードをキューイングし、ワークロードを実行するタイミングと場所を動的に制御するコントローラを構築するケースなどが考えられています。
- `DynamicResourceManagement` の kubeletplugin API について、`v1alpha1` バージョンのサポートが削除されました。すべてのプラグインは `v1alpha2` バージョンを使うよう更新する必要があります。([#116558](https://github.com/kubernetes/kubernetes/pull/116558), [@klueska](https://github.com/klueska))
- `/metrics/slis` がコントロールプレーンのコンポーネントで使用可能になり、ヘルスチェックのためのメトリクスをスクレイプできるようになりました。([#114997](https://github.com/kubernetes/kubernetes/pull/114997), [@Richabanker](https://github.com/Richabanker))
  - :pencil: メトリクスの定義など詳細はこちらを参照してください：[Kubernetes Component SLI Metrics | Kubernetes](https://kubernetes.io/docs/reference/instrumentation/slis/)
- `NodeResourceFit` と `NodeResourcesBalancedAllocation` スケジューラプラグインが、`PreScore` 拡張点を使いより効率よく pod の要求リソース量の計算をおこなうようになりました。([#115655](https://github.com/kubernetes/kubernetes/pull/115655), [@tangwz](https://github.com/tangwz))
  - :pencil: Pod に含まれるコンテナの要求リソース量を合計する計算について、pod ごとに一度のみおこなうようになりました。これまでは、同じ計算を `Score` 拡張点でノード数だけおこなっていました。
- `PodSchedulingReadiness` がベータに昇格しました。([#115815](https://github.com/kubernetes/kubernetes/pull/115815), [@Huang-Wei](https://github.com/Huang-Wei))
  - :pencil: Pod Scheduling Readiness についてはこちらを参照してください：[Pod Scheduling Readiness | Kubernetes](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-scheduling-readiness/)
- `PodSpec.Container.Resources` フィールドが、CPU とメモリについて可変になりました。
  - `PodSpec.Container.ResizePolicy` フィールドが追加され、コンテナのリサイズ（割り当てるリソース量の変更）をどうおこなうか制御できるようになりました。
  - `PodStatus.Resize` フィールドが追加され、pod のリサイズの状態が記述されるようになりました。
  - `PodStatus.ResourcesAllocated` フィールドが追加され、pod に割り当てられているノードのリソースが記述されるようになりました。
    - :pencil: リリースノートには `PodStatus.ResourcesAllocated` とありますが、おそらく `PodStatus.ContainerStatuses.AllocatedResources` のことだと思われます。
  - `PodStatus.Resources` フィールドが追加され、CRI が実行中のコンテナに適用したノードのリソースが記述されるようになりました。
    - :pencil: リリースノートには `PodStatus.Resources` とありますが、おそらく `PodStatus.ContainerStatuses.Resources` のことだと思われます。
  - `UpdateContainerResources` CRI API が Linux と Windows の両方をサポートするようになりました。([#102884](https://github.com/kubernetes/kubernetes/pull/102884), [@vinaykul](https://github.com/vinaykul))
  - :pencil: 以上、前述の In-place Update of Pod Resources に関わる Pod API の変更です。
- `resource.k8s.io/v1alpha1` が `resource.k8s.io/v1alpha2` に置き換えられました。クラスタをアップグレードする前に、すべての `resource.k8s.io/v1alpha1` バージョンのリソース (ResourceClaim, ResourceClaimTemplate, ResourceClass, PodScheduling) は削除する必要があります。この変更は内部的なものであるため、`apiVersion` を更新する以外に、pod や resource claim を作る YAML の変更は必要ありません。([#116299](https://github.com/kubernetes/kubernetes/pull/116299), [@pohly](https://github.com/pohly))

### :sparkle: Feature（機能追加）

- アクセスモードが `ReadWriteOncePod` な PVC を使う pod のプリエンプションがサポートされました。([#114051](https://github.com/kubernetes/kubernetes/pull/114051), [@chrishenzie](https://github.com/chrishenzie))
- Pod Topology Spread Constraints の `matchLabelKeys` フィールドがベータに昇格しました。([#116291](https://github.com/kubernetes/kubernetes/pull/116291), [@denkensk](https://github.com/denkensk))
  - `matchLabelKeys` フィールドを使うと、pod 群をローリングアップグレードする際も topology spread constraints がうまく機能するようになります。詳しくはこちらを参照してください：[KEP-3243: Respect PodTopologySpread after rolling upgrades](https://github.com/denkensk/enhancements/blob/master/keps/sig-scheduling/3243-respect-pod-topology-spread-after-rolling-upgrades/README.md)
- `defaultbinder` スケジューラプラグイン が [contextual logging](https://k8s.io/docs/concepts/cluster-administration/system-logs/#contextual-logging) を使うようになりました。([#116571](https://github.com/kubernetes/kubernetes/pull/116571), [@mengjiao-liu](https://github.com/mengjiao-liu))
- スケジューラに `plugin_evaluation_total` メトリックが追加されました。このメトリックは、各プラグインがスケジューリング結果に影響を及ぼした回数をカウントします。プラグインがスケジュール処理中の pod に対しておこなう処理が何もなかった場合は加算されません。([#115082](https://github.com/kubernetes/kubernetes/pull/115082), [@sanposhiho](https://github.com/sanposhiho))
  - :pencil: 現時点で `PreFilter` および `Filter` 拡張点がサポートされているようです。
- スケジューラプラグインの `PreFilter` メソッドが `Skip` ステータスを返した場合、スケジューラはそのプラグインの `Filter` メソッドを呼ばないようになりました。つまり、`PreFilter` / `Filter` 拡張点を実装するプラグインは、`Filter` でおこなう処理が何もないとき、`PreFilter` で `Skip` ステータスを返すことができます。この機能追加に基づき、`NodeAffinity` プラグインが `Filter` でおこなう処理が何もないとき、スケジューラは `NodeAffinity` プラグインの `Filter` を呼ばないようになりました。この変更は、`NodeAffinity` プラグインの `Filter` に関するメトリクスに影響する可能性があります。([#114125](https://github.com/kubernetes/kubernetes/pull/114125), [@sanposhiho](https://github.com/sanposhiho))
  - また、`InterPodAffinity` プラグインが `Filter` でおこなう処理が何もないとき、スケジューラは `InterPodAffinity` プラグインの `Filter` を呼ばないようになりました。この変更は、`InterPodAffinity` プラグインの `Filter` に関するメトリクスに影響する可能性があります。([#114889](https://github.com/kubernetes/kubernetes/pull/114889), [@sanposhiho](https://github.com/sanposhiho))
  - :pencil: 今後、他のプラグインについても（適切な場合）`PreFilter` で `Skip` ステータスを返すようにしていくようです。
- `VolumeBinding` スケジューラプラグインで、pod がノードローカルな PV への claim をもっているとき、`PreFilterResult` を使いその PV が利用可能なノードだけをフィルタ結果として返すようにしました。([#109877](https://github.com/kubernetes/kubernetes/pull/109877), [@yibozhuang](https://github.com/yibozhuang))
- スケジューラプラグインが `PostFilter` メソッドで `unschedulableAndUnresolvable` を返したとき、スケジューラはその pod のスケジューリング処理を即時終了するようになりました。([#114699](https://github.com/kubernetes/kubernetes/pull/114699), [@kerthcet](https://github.com/kerthcet))
- Pod の `.spec.schedulingGates[*].name` フィールドは qualified name（例：`example.com/mygate`）でなければならなくなりました。`.spec.readinessGates[*].name` フィールドと同じルールが適用されます。Pod Scheduling Readiness（Kubernetes 1.27 より前ではアルファ）のユーザは、1.27 へのアップグレードをする前に違反している名前を修正または削除する必要があります。([#115821](https://github.com/kubernetes/kubernetes/pull/115821), [@lianghao208](https://github.com/lianghao208))
- スケジューラプラグインの `PreScore` メソッドが `Skip` ステータスを返した場合、スケジューラはそのプラグインの `Score` メソッドを呼ばないようになりました。つまり、`PreScore` / `Score` 拡張点を実装するプラグインは、`Score` でおこなう処理が何もないとき、`PreScore` で `Skip` ステータスを返すことができます。([#115652](https://github.com/kubernetes/kubernetes/pull/115652), [@AxeZhan](https://github.com/AxeZhan))
- `JobMutableNodeSchedulingDirectives` 機能が GA に昇格しました。([#116116](https://github.com/kubernetes/kubernetes/pull/116116), [@ahg-g](https://github.com/ahg-g))
  - :pencil: サスペンドされ、まだ開始もしていない job の scheduling directive（pod template のノードアフィニティやノードセレクタなど）を可変にする機能です。詳しくはこちらを参照してください：[KEP-2926: Allow updating scheduling directives of jobs](https://github.com/kubernetes/enhancements/tree/master/keps/sig-scheduling/2926-job-mutable-scheduling-directives)
- `ReadWriteOncePod` 機能がベータに昇格しました。([#114494](https://github.com/kubernetes/kubernetes/pull/114494), [@chrishenzie](https://github.com/chrishenzie))
  - :pencil: `ReadWriteOncePod` は、PV へのアクセスをある一つのノード上のある一つの pod からに限定するアクセスモードです。詳しくはこちらを参照してください：[KEP-2485: ReadWriteOncePod PersistentVolume AccessMode](https://github.com/kubernetes/enhancements/blob/master/keps/sig-storage/2485-read-write-once-pod-pv-access-mode/README.md)
- スケジューラの `plugin_execution_duration_seconds` メトリックが、`PreEnqueue` 拡張点のプラグインの実行にかかった時間を記録するようになりました。([#116201](https://github.com/kubernetes/kubernetes/pull/116201), [@sanposhiho](https://github.com/sanposhiho))
  - :pencil: `PreEnqueue` 拡張点は、Kubernetes 1.26 で追加されました。
- `MinDomainsInPodTopologySpread` 機能がベータに昇格し、デフォルトで有効になりました。([#114445](https://github.com/kubernetes/kubernetes/pull/114445), [@mengjiao-liu](https://github.com/mengjiao-liu))
  - :pencil: `MinDomainsInPodTopologySpread` は、その名の通り、Pod Topology Spread Constraints で許容する最小のドメイン数を設定できるようにする機能です。詳しくはこちらを参照してください：[KEP-3022: min domains in Pod Topology Spread](https://github.com/kubernetes/enhancements/tree/master/keps/sig-scheduling/3022-min-domains-in-pod-topology-spread)
- Pod topology spread constraints において、`labelSelector` が null のときの計算が最適化されました。([#116607](https://github.com/kubernetes/kubernetes/pull/116607), [@alculquicondor](https://github.com/alculquicondor))

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

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

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

- Pod がプリエンプションされたときのイベントのメッセージから、プリエンプター pod のメタデータを除きました。([#114923](https://github.com/kubernetes/kubernetes/pull/114923), [@mimowo](https://github.com/mimowo))
  - :pencil: 他のネームスペースの存在や、その中の pod 名が漏洩することを防ぐためです。
- スケジューラで、ボリュームのバインドが完了したことを誤って意味していたログを修正しました。([#116018](https://github.com/kubernetes/kubernetes/pull/116018), [@TommyStarK](https://github.com/TommyStarK))
- スケジューラが `Filter` プラグインを常にすべて実行していたバグを修正しました。([#114518](https://github.com/kubernetes/kubernetes/pull/114518), [@Huang-Wei](https://github.com/Huang-Wei))
  - :pencil: 本来は、ある `Filter` プラグインが失敗したらそこで処理を止めなければなりません。
- スケジューラで、プリエンプション処理と pod の更新処理とのあいだにあった競合状態を修正しました。([#116395](https://github.com/kubernetes/kubernetes/pull/116395), [@alculquicondor](https://github.com/alculquicondor))
- `NodeVolumeLimits` CSI のロギングにあった nil ポインタの参照を修正しました。([#115179](https://github.com/kubernetes/kubernetes/pull/115179), [@sunnylovestiramisu](https://github.com/sunnylovestiramisu))
- メトリックの探索をクリティカルパスで頻繁におこなっていたことによる性能劣化を修正しました。([#116428](https://github.com/kubernetes/kubernetes/pull/116428), [@mborsz](https://github.com/mborsz))
- `DisruptionTarget` type のコンディションのメッセージから、プリエンプター pod のメタデータを除きました。([#114914](https://github.com/kubernetes/kubernetes/pull/114914), [@mimowo](https://github.com/mimowo))
  - :pencil: イベントのメッセージと同様の修正です。
- プリエンプションのイベントのメッセージから、スケジューラの名前を除きました。([#114980](https://github.com/kubernetes/kubernetes/pull/114980), [@mimowo](https://github.com/mimowo))
  - :pencil: プリエンプター pod のスケジュール処理をおこなったスケジューラの名前を除くようになりました。スケジューラの名前も漏洩することを防ぐためのようです。
- `schedulingGates` が空でない場合、`nodeName` を指定することを禁止するようになりました。([#115569](https://github.com/kubernetes/kubernetes/pull/115569), [@Huang-Wei](https://github.com/Huang-Wei))
  - :pencil: この変更は、Pod Scheduling Readiness が有効化されているかどうかによらず適用されます。

### :microscope: Other (Cleanup or Flake)（その他の修正）

- `--contention-profiling` フラグのドキュメントを修正し、このフラグが block profiling をおこなうことを反映しました。([#114490](https://github.com/kubernetes/kubernetes/pull/114490), [@MadhavJivrajani](https://github.com/MadhavJivrajani))
  - :pencil: 文面を "lock contention" から "block profiling" に書き換えた変更です。なお、このフラグは非推奨です。
- Pod のリソースの request / limit 量のメトリクスが stable に昇格しました。([#115454](https://github.com/kubernetes/kubernetes/pull/115454), [@dgrisonnet](https://github.com/dgrisonnet))
- In-tree の Azure disk ストレージ用のプラグインを削除しました。([#116301](https://github.com/kubernetes/kubernetes/pull/116301), [@andyzhangx](https://github.com/andyzhangx))
- `scheduler_e2e_scheduling_duration_seconds` メトリックが削除され、`scheduler_scheduling_attempt_duration_seconds` メトリックで置き換えられました。([#115209](https://github.com/kubernetes/kubernetes/pull/115209), [@dgrisonnet](https://github.com/dgrisonnet))
  - :pencil: 削除されたのは Kubernetes 1.23.0 から非推奨だったメトリックです。