Kubernetes 1.24: SIG Scheduling の変更内容

Kubernetes 1.24がリリースされましたね :tada:


今回もKubernetes v1.24の[CHANGELOG](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.24.md#v1240)をベースにSIG Schedulingに関する機能について紹介していきます。

過去の変更内容:
- [Kubernetes 1.23: SIG Scheduling の変更内容](https://qiita.com/everpeace/items/1b6ad68075d81ce315c4)
- [Kubernetes 1.22: SIG Scheduling の変更内容](https://qiita.com/everpeace/items/c7ab1c366dd777dce14a)
- [Kubernetes 1.21: SIG Scheduling の変更内容](https://qiita.com/everpeace/items/084da032a83c81bb887a)


## 1.24変更点の所感

- 多くのBeta FeatureがGAになりました: `DefaultPodTopologySpread`, `NonPreemptingPriority`, `PodOverhead`, `PreferNominatedNode`, `PodAffinityNamespaceSelector`
- 1.24での機能変更/修正は、利用が増えてきているからか、Pod Topology Spread関連が目立ちます。コミュニティからのフィードバックを受けて成長してきている印象です。
  - `nodeAffinity/nodeSeletor`の扱いの変更(Urgent Upgrade Notes)
  - `topologySpreadConstraint.minDomain`の導入(API Changes)
- それ以外は小さな修正にとどまっています。

> 下記 :pencil: がついた文章は、CHANGELOGの公式内容ではなく筆者の補足です。

# :new: What's new! (新情報)

## Storage Capacity and Volume Expansion Are Generally Available

[Kubernetes 1.24: SIG Storageの変更内容](https://qiita.com/ysakashita/items/b90daf37bc3d1f2fa437#storage-capacity-and-volume-expansion-are-generally-available)を参照ください。

## NonPreemptingPriority to Stable

[NonPreempting Priority Class](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#non-preempting-priority-class)の機能がStableになりました。　

:pencil: バッチ処理やデータサイエンスワークロードなどPreemptionされたくないワークロードがある場合に、*Preemptionする側のPriorityClass*に `preemptionPolicy: Never` を設定することでPreemptionを*行わない*PriorityClassを作成することができる機能です(default値は`PreemptLowerPriority`)。ただしscheduler内のQueueは優先度に応じて並ぶので低優先度のPodよりスケジュールされやすくなるため、バッチワークロードを低優先度に割り当てておくことで、バッチはリソースが空いているときにだけスケジュールされ、プリエンプションされない。が、実現出来ます。

<details><summary>NoPreempting Priority Classの例</summary><div>

```yaml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority-nonpreempting
value: 1000000
preemptionPolicy: Never
globalDefault: false
description: "このpriority classはpodをpreemptしない"
```

</div></details>

:pencil: Preemptされる側でPreemptされるされないを制御できる 
[Preemption Toleration Scheduler Plugin](https://qiita.com/everpeace/items/6152db29e2f609464800)というのもあります:bow: 

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

- [Pod Topology Spread](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/)でskew[^1]を計算する際にスケジュールしようとしているPodのnode affinity/selectorにマッチしないノードで稼働しているPodを除外するようになりました。この変更によって、もしtopology spread対象のlabelにマッチするpodが、node affinty/selectorにマッチしないノードで稼働している場合、これまでscheduleされていたpodがunschedulableになる可能性があります。その場合はこのシナリオが発生しないようにnode affinityもしくはpod selectorを調整してください。([#107009](https://github.com/kubernetes/kubernetes/pull/107009), [@kerthcet](https://github.com/kerthcet))

[^1]: 各topology domain(zoneやnode)にどのぐらい偏ってpodがスケジュールされているかを示す。具体的には、topology domainをzoneだとすると、各zoneにスケジュールされているpod数の最大値-最小値がskewとなります。

<details><summary>:pencil: インパクトが有るのは、topology spread constraintとnode affinity/selectorの両方を使っている場合のみですのであまりケースは多くないかもしれません。が、どういうふうに治ったのか、説明してますので、興味ある方は折りたたみを開いてください。</summary>

<br />

**おさらい**

```yaml
spec:
  topologySpreadConstraints:
    # 複数指定したらAND-ed
  - topologyKey: zone # zone単位で散らしたい(node label keyを指定できる)
    maxSkew: 1        # 各zoneに居るlabelSelectorにマッチする
    labelSelector:    # pod数の偏りは1以内にしたい
      matchLabels:
        foo: bar
    whenUnsatisfiable: DoNotSchedule # maxSkewを満たせない場合はscheduleしない
                                     # 'ScheduleAnyway'だと無視してスケジュールする
  
  # 今回はこのnodeAffinity/nodeSelectorを一緒に使っている時の挙動が変わります
  affinity:
    nodeAffinity:
    ...
  nodeSelector:
  ...
```

<br/>

**何が問題だったのか**

4ノードが2つのゾーンに存在していて、zone1に2 pod, zone2に3 pod稼働しているとします。(label selectorは話を簡単にするために、全部マッチするとします。)

| zone         | zone1    |          | zone2      |          |
| ------------ | -------- | -------- | ---------- | -------- |
| node         | worker   | worker2  | worker3    | worker4  |
| existingPods | pod1     | pod2     | pod3, pod4 | pod5     |
| vacancy      | 空き無し | 空き無し | 空き有り   | 空き有り |

ここに、zoneに対するpod topology spreadと **worker3に対するanti node-affinity(worker3にはスケジュールされない)** をもったtest podが作成されたとします。すると、

- test podはworker3にはscheduleされないはずなのに
- 各zoneのpod数はzone1=2, zone2=3となるので、新しいpodはzone 1にスケジュールされようとしますが、
- nodeに空きがないのでpendingになってしまう

という挙動が有りました。

<br/>

**どう治ったのか**

test podのskewを計算するときにnode affinityを考慮するようになりました。なので、

- 各zoneのpod数はzone1=2, zone2=1となり、
- test podはzone2にスケジュールされることになります

<br/>

**副作用**

上で説明したシナリオはこの挙動を修正することでスケジュールされやすいケースを意図的に紹介しましたが、当然逆もありえます。この変更によってこれまでscheduleされていたpodがunschedulableになることがあります。

各ゾーンに2nodeずつ、各nodeにはmatching pod(topology constraintにマッチするラベルを持つpod)が1個ずつ動いているとします。各ノードの利用状況はworker3だけ空きがないとします。

| zone         | zone1    |          | zone2    |          |
| ------------ | -------- | -------- | -------- | -------- |
| node         | worker   | worker2  | worker3  | worker4  |
| existingPods | pod1     | pod2     | pod3     | pod4     |
| vacancy      | 空き有り | 空き有り | 空き無し | 空き有り |

このとき、worker4にanti-node affinityを持つpodが作成されたとします。そうすると

- 以前の挙動: zone1=2, zone2=2なので、どちらのzoneにもスケジュール可能となり、zone1のnodeが空いているので、worker,worker2のどちらかにスケジュールされる
- 修正後の挙動: zone1=2, zone2=1となるので、zone2にのみスケジュール可能となるが、worker3はリソース足りない、worker4はanti node affinityがついている、ので、結果としてunschedulableになってしまうという副作用がおきるので注意が必要です。

<br />

**こぼれ話**

もともと、pod topology constraintとnode affinityを両方指定した時の細かい挙動は議論の余地があり、upstreamでもこれをバグとして修正すべきなのか、backportするほどの修正なのか？が議論されていました。

が、[Example: TopologySpreadConstraints with NodeAffinity](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#example-topologyspreadconstraints-with-nodeaffinity) に、TopologySpreadConstraintsはnodeSelectorをrespectする旨の言及が有り、今回修正されることになったようです。ただし、backportはされないことになりました。


参照: [kubernetes/kubernetes#106971](https://github.com/kubernetes/kubernetes/issues/106971#issuecomment-992139405)

</details>

:pencil:ちなみに1.25ではNodeInclusionPoliciesと呼ばれていた新しいAPIが追加される予定です([KEP-3094](https://github.com/kubernetes/enhancements/issues/3094),[kubernetes/kubernetes#108492](https://github.com/kubernetes/kubernetes/pull/108492))。`podTopologyConstraints[*].{nodeTaintsPolicy|nodeAffinityPolicy}`というAPIが追加され、`Ignore`,`Honor`を指定することでユーザがskewの計算に対してnode affinity, taintをそれぞれ考慮するかどうかが選べるようになります。NodeInclusionPoliciesについての詳細は下記のスライドが詳しいです。

https://speakerdeck.com/sanposhiho/pod-topology-spreadfalsechao-zui-qian-xian-mindomains-nodeinclusionpoliciesnituite


# :wastebasket: Deprecation(非推奨)

:pencil: ありません

# :earth_asia: API Changes（API変更）

- `DefaultPodTopologySpread`がGAになりました([#108278](https://github.com/kubernetes/kubernetes/pull/108278), [@kerthcet](https://github.com/kerthcet))
- `NonPreemptingPriority`がGAになりました([#107432](https://github.com/kubernetes/kubernetes/pull/107432), [@denkensk](https://github.com/denkensk))
- `PodOverhead`がGAになりました([#108441](https://github.com/kubernetes/kubernetes/pull/108441),[@pacoxu](https://github.com/pacoxu)) 
- Pod affinity namespace selectorとcross-namespace quotaがGAになりました。`PodAffinityNamespaceSelector` feature gateはlockされ1.26で削除されます。([#108136](https://github.com/kubernetes/kubernetes/pull/108136), [@ahg-g](https://github.com/ahg-g))
  - :pencil: [Inter-pod affinity and anti-affinity - Namespace selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#namespace-selector): `podAffinityTerm.namespaceSelector`をつかって他のnamespaceのpodとaffinity,anti-affinityを設定できる機能です
  - :pencil: [Cross-namespace Pod Affinity Quota](https://kubernetes.io/docs/concepts/policy/resource-quotas/#cross-namespace-pod-affinity-quota): Namespace selectorを使えるpod数をResourceQuotaで制限できる機能です
- `topologySpreadConstraints`に`minDomains`フィールドが追加され、topology domain の最小数を制限できるようになりました([#107674](https://github.com/kubernetes/kubernetes/pull/107674), [@sanposhiho](https://github.com/sanposhiho))
  - :pencil: [KEP-3022: Min domains in PodTopologySpread](https://github.com/kubernetes/enhancements/issues/3022)
  - :pencil: feature gate: `MinDomainsInPodTopologySpread`, status: `alpha`
  - :pencil: topology spread constraintにおいて、どのくらいのdomain(zoneとかnode等)に分散させたいか？を調整できるパラメータです。例えば、`minDomains:3`と指定すると、最低3 domainに散らばるようにpodが配置されるようになります。
  - :pencil: これまではspreadするdomain数を制御するパラメータが有りませんでした。

<details><summary>:pencil: `minDomains`の挙動の具体例</summary>

<br />

**おさらい**

- schedulerは将来にわたってtopology domainが何種類あるか？はわからないので、
- 存在しているnode群からtopology domainを把握し、
- 存在しているdomain間でskewを計算し、
- maxSkewの範囲内でspreadされるようにスケジュールされます。

<br />

**シナリオ**

- 現在zone1, zone2が存在しており、zone3はcluster autoscaler等によって自動的に発生するとします。どのnodeもリソースは潤沢にあるとします。
- pod1, pod2, pod3という3つのpodを、`topology domain=zone, maxSkew=1, whenUnstatifiable=DoNotSchedule`のconstraintでscheduleすることを考えます。
- *かつ、少なくとも3 domainにspreadしたいと想定します*

| zone      | zone1 | zone2 | *(zone3)* |
| --------- | ----- | ----- | --------- |
| node name | nodeA | nodeK | *(nodeX)* |


<br />

**minDomainが無いと何が困るか?**

| step | zone1 | zone2     | *(zone3)* | skew |
| ---- | ----- | --------- | --------- | ---- |
| 1    | pod1  |           |           | 1    |
| 2    | pod1  | pod2      |           | 0    |
| 3    | pod1  | pod2,pod3 |           | 1    |

- 1: pod1がzone1にスケジュールされたとする。
- 2: pod2はskewを小さくしたいのでzone2にスケジュールされる。
- 3: pod3は、zone3は存在しないので、zone1, zone2のどちらにスケジュールしてもskewは1でmaxSkewに反しないのでどちらかにスケジュールされる。
- *リソースが潤沢にある場合、どれだけpod作ってもリソースがなくなるまで新しいdomainは出現しない。つまり3 domainにspreadされない*

<br />

**minDomainがあるとどうなるか？**

`minDomain: 3`をつけると、spreadしているtopology domainの個数がそれに満たない場合は各domainのpod数の最大値をskewとします(skewは最大-最小なので、最小を0とするとも言えます)。こうすることでこのシナリオは下記のように変わります。

| step | zone1 | zone2     | zone3 | skew | comment     |
| ---- | ----- | --------- | ----- | ---- | ----------- |
| 1    | pod1  |           |       | 1    |             |
| 2    | pod1  | pod2      |       | 0    |             |
| 3'   | pod1  | pod2,pod3 |       | 2    | maxSkew違反 |
| 3    | pod1  | pod2      | pod3  | 0    |             |

- 1: pod1がzone1にスケジュールされたとする
- 2: pod2はskewを小さくしたいのでzone2にスケジュールされる。
- 3': pod3を作ると、spreadしているdomain数がまだ2なので、zone1, zone2どこにscheduleした仮定としてもと、skewは2になってしまう→つまりmaxSkew制約を満たせない→pod3はpendingになる。
- 3: するとCluster Autoscalerによってzone3が出現する。すると、skew=0となるスケジュールが可能となり、pod3はzone3にスケジュールされる
- *既存のdomainがminDomain未満だと各domainのpodがmaxSkew個になると制約を満たせなくなる。つまりdomainが足りない状態になる。*

</details>

# :sparkle: FEATURE（機能追加）

- <a id="podMaxUnschedulableQDuration" />unschedulable queueからactive queueもしくはbackoff queueに強制的にflushする間隔を指定するdeprecatedなコマンドラインflagを追加しました([#108017](https://github.com/kubernetes/kubernetes/pull/108017), [@denkensk](https://github.com/denkensk))
  - :pencil: もともとは[Reevaluate flushing unschedulable pods into activeQ kubernetes/kubernetes#87850](https://github.com/kubernetes/kubernetes/issues/87850)で議論されているissueを一部カバーする機能です。
  - :pencil: kubernetesはその分散システムとしての特性上、一度unschedulable判断されたPodが一定期間経過すると強制的にschedule可能かを再評価する仕組みがあります(単純に考えると一旦unschedulableになったpodはクラスタのステートが変化するまで再評価しなくても良い気がしますが、分散システムでは何があるかわからないため)。
  - :pencil: ただ、この期間は現在までハードコードされ変更出来ない値でした。これが変更出来ない場合、一定期間ごとにactiveQにpodが戻ってくるため、高優先度のpodが大量にある場合、低優先度のpodがscheduling cycleに入れない状態が発生してしまう([kubernetes/kubernetes#86373](https://github.com/kubernetes/kubernetes/issues/86373))ため、設定可能にする修正です。
  - :pencil: [kubernetes/kubernetes#87850](https://github.com/kubernetes/kubernetes/issues/87850)ではまだ具体的な解決策は出来ていないですが、この単純なしくみよりもより良い解決策を議論しており、はじめからdeprecatedで将来削除予定のflagとして追加されました。
  - :pencil: scheduler内部の3つのQueue(active, unschedulable, backoff)については[自作して学ぶKubernetes Scheduler](https://engineering.mercari.com/blog/entry/20211220-create-your-kube-scheduler/#:~:text=kube%2Dscheduler%E3%81%AEScheduling%20Queue%E3%81%8C%E3%82%82%E3%81%A43%E3%81%A4%E3%81%AEQueue%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B)が詳しいです。
- `CycleState`が`write once and read many times`なユースケースに対して最適化されました. ([#108724](https://github.com/kubernetes/kubernetes/pull/108724), [@sanposhiho](https://github.com/sanposhiho)) 
  - :pencil: `CycleState`はscheduler pluginが使えるScheduling Cycleをライフサイクルとするcontextのようなものです。もともと `sync.RWMutex`排他制御される`map[StateKey]StateData`でしたが、この修正で`syncMap`に変更になりました。`sync.Map`は`write once and read many times`に最適化されたデータですが、もともと`CycleState`のユースケースはそれに限定されていなかったのですが、これまでで、主なユースケースは`PreFilter`フェーズで事前計算を行って後続ではそれを参照するのみ、というケースが大半であることから変更されました。
- `PreferNominatedNode`がGAになりました。([#106619](https://github.com/kubernetes/kubernetes/pull/106619), [@chendave](https://github.com/chendave))
  - <a id="preemption" />:pencil: Schedulerのpreemptionは2 scheduling cyle掛けて行われます。
    - scheduling cycle `C1`: Preemptor Pod `P`がnode `N`上のVictim Pod `V`をpreemptします。このcycleで`P.status.nominatedNode: N`がセットされます。
    - scheduling cycle `C2`: Preemptor Pod `P`が実際にスケジュールされる、という挙動をします。
  - :pencil: cycle `C2`において、`nominatedNode`をまずチェックしてスケジュール可能であればそこにスケジュールするという機能です。通常のFilter→Scoreという処理を行いません。つまり、Node Score的により良いノードがいるかも知れない状況ですが、cycle`C1`でpreemption下nodeを優先的に選ぶという機能です。
- Scheduler Frameworkにおいて`PreFilter`拡張点の返り値が`Status`から`PreFilterResult`に変更になりました([#108648](https://github.com/kubernetes/kubernetes/pull/108648), [@ahg-g](https://github.com/ahg-g))
  - :pencil: Scheduling Frameworkのメソッドの多くは[framework.Status](https://github.com/kubernetes/kubernetes/blob/v1.24.0/pkg/scheduler/framework/interface.go#L134-L146)というデータを返すようになっています。
  - :pencil: 現在のSchedulerのFilterフェーズ(スケジュール可能なノードを探すフェーズ)は、Podのスケジューリングのスループットを上げるために[`PercentageOfNodesToScore`](https://github.com/kubernetes/kubernetes/blob/v1.24.0/pkg/scheduler/apis/config/types.go#L70-L78)で指定した割合のnode数を見つけたらFilterフェーズを早期リターンする用になっているのですが、[大規模なクラスタでまだスループットが足りないことが報告](https://github.com/kubernetes/kubernetes/issues/108606)されていました。
  - :pencil: なぜかというと、schedule不可能なPodは、Filterフェーズで全ノードがschanされてしまい、ここでスループットが落ちてしまうとのこと。
  - :pencil: そこで[PreFilterフェーズでFilterフェーズでscanするnodelistを返せるように変更したらどうか？](https://github.com/kubernetes/kubernetes/issues/108606#issuecomment-1064479942)という提案がなされてそれが、PrefilterResultという形で実現されました。
  - :pencil: 最初のユースケースとしてはNodAffinity Pluginが先にnodeAffinityをチェックしてnode対象のNodeの集合をPrefilterすることが想定されている模様。
  - :pencil: Filterフェーズでは複数のPluginが実行されるので、各nodeを事前にスキップできると不必要なPlugin実行が軽減できスループットの向上が期待されます。
- kube-schedulerのインセキュアなコマンドラインフラグ(`--port`)が削除されました。代わりに`--bind-address`, `--secure-port`を使ってください。([#106865](https://github.com/kubernetes/kubernetes/pull/106865), [@jonyhy96](https://github.com/jonyhy96))
- `PodMaxUnschedulableQDuration`(のデフォルト値)が5分にセットされました。([#108761](https://github.com/kubernetes/kubernetes/pull/108761), [@denkensk](https://github.com/denkensk))
  - :pencil: [上](#podMaxUnschedulableQDuration)で導入された値のデフォルトが5分になりました。[バグ修正のセクション](#clusterEventRegistration)でも触れられているように現在は、unschedulablePodをactiveQ/backoffQに戻るタイミングをPluginが細かく制御できるため、デフォルト間隔が延長になりました。
- Extenderがエラーを返したときに、ログを出力するようになりました。(`--v>5`) ([#107974](https://github.com/kubernetes/kubernetes/pull/107974), [@sanposhiho](https://github.com/sanposhiho))

# :bug: バグ修正

- <a id="clusterEventRegistration" />Scheduller pluginのevent registrationを修正し、unschedulable podがre-queueされる間隔が長くなってしまう問題を修正しました。([#109442](https://github.com/kubernetes/kubernetes/pull/109442), [@ahg-g](https://github.com/ahg-g))
  - :pencil: 各Scheduler PluginはunschedulableなpodをactiveQもしくはbackoffQに戻す必要のあるクラスタイベント(Nodeの追加や更新等)を登録できますが、この登録が正しく行われていませんでした。
  - :pencil: :back:この修正はv1.21以降のすべてのバージョンにbacckportされています。
- Podの`.status.nominatedNodeName`が適切にクリアされずリソースが確保されいる状態になっていた問題を修正しました。([#106816](https://github.com/kubernetes/kubernetes/pull/106816), [@Huang-Wei](https://github.com/Huang-Wei))
  - :pencil: [上](#preemption)で説明したように、preemptionは2 scheduling cycleかけて行われますが、一般に`C1`(低優先度podをpreemptionするcycle)と`C2`(preeptorをscheduleするcycle)は連続していません。
  - :pencil: この時、`C1`と`C2`の間のcycleで`P`が`N`にscheduleできなくなる事象が起きた際に適切に`status.nominatedNode`が削除されず、scheduler上で`P`分のリソース利用が予約され続けてしまうバグがありました。
  - :pencil: 例えば、 `C1`と`C2`の間のcycleでより高い優先度のPod `Q`が`N`にスケジュールされてしまって`P`が入る空きがなくなってしまった場合等です。
  - :pencil::back:変更量が多いため1.23にのみbackportされています
- `v1beta3` configを使った場合、out-of-tree scheduler pluginの想定外の順序で配置されていた問題を修正しました。([#108613](https://github.com/kubernetes/kubernetes/pull/108613), [@Huang-Wei](https://github.com/Huang-Wei))
  - :pencil: default scheduler pluginよりも前にout-of-tree pluginが配置されてしまっていたようです。
  - :pencil::back:1.23にbackportされています(`v1beta3`は1.23から導入されました)
- Pod数が少ない場合のPodToplogySpread score計算時の丸め誤差を改善し、より正確にscoreを考慮するようになりました。([#107384](https://github.com/kubernetes/kubernetes/pull/107384), [@sanposhiho](https://github.com/sanposhiho)) 
  - :pencil: `int(someFloat64Value)`ではなく`math.Round`を使うようになりました。
- 実際にscheduleされているnodeへのnomiationを行わないようにしました。([#109245](https://github.com/kubernetes/kubernetes/pull/109245), [@alculquicondor](https://github.com/alculquicondor))
  - :pencil: ある[特定のシナリオ](https://github.com/kubernetes/kubernetes/issues/109236#issuecomment-1086246634)で、scheduler内のcahceでpodが実際にスケジュールされているにも関わらずnominated podにもなってしまっており、リソースを余分に確保している状態になってしまっていた。
- Scheduler ExtenderのPreemptを呼んだ際に、後続の`pickOneNodeForPreemption`というfilter stepで必要な、Nodeの`NumPDBVioloations`を復元するように修正しました。([#105853](https://github.com/kubernetes/kubernetes/pull/105853), [@caden2016](https://github.com/caden2016))
  - :pencil: Scheduler ExtenderのPreemptは、kube-schedulerが選出した各victim候補ノードのvictim Pod群とPDB違反Pod数を入力として、それをfilter(victim候補から外して)して、新たなvictim候補と新たなPDB違反Pod数を返すことが出来ます。
  - :pencil: SchedulerがExtenerのPreemptメソッドを呼んだ際、PDB違反POD数がリセットされてしまっていました。この値は最終的にvictim候補ノードを1個に絞る`pickOneNodeForPreemption`という処理で使われます。
  - :pencil: 影響が大きそうな修正ですが、どのバージョンにもbackportはされていないようです。Scheduler ExtenderのしかもPreemptを使っている事例は殆どないのかもしれません。

# :microscope: Other (その他の修正)

- `PriorityClass`を`kubectl describe`する際に`PreemptionPolicy`が表示されるようになりました。([#108701](https://github.com/kubernetes/kubernetes/pull/108701), [@denkensk](https://github.com/denkensk))
- preemptionの詳細がscheduling失敗eventに追加されました。([#107775](https://github.com/kubernetes/kubernetes/pull/107775), [@denkensk](https://github.com/denkensk)) 
  - :pencil: `FailedScheduling` eventの`Message`に↓のような詳細結果が記載されるようになりました。
  - :pencil: `preemption: not eligible due to preemptionPolicy=Never`
  - :pencil: `preemption: 0/4 nodes are available: 1 Insufficient cpu, 3 Preemption is not helpful for scheduling.`
- `unschedulableQ`は`unschedulablePods`にrenameされました([#108919](https://github.com/kubernetes/kubernetes/pull/108919), [@denkensk](https://github.com/denkensk))
  - :pencil: `Q`と名前がついていても実際にはFIFOやLIFOのような構造を持っておらず単なるmapだったので実際に即したrenameです。
- Scheduler frameworkの`runAllFilters`オプションが削除されました。([#108829](https://github.com/kubernetes/kubernetes/pull/108829), [@kerthcet](https://github.com/kerthcet))
  - :pencil: もう使われていなかったオプションの削除です。