Kubernetes 1.21: SIG Scheduling の変更内容

# はじめに

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

今回SIG Schedulingの変更は少なめなのですが、

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

個人的に今回の変更で特筆すべきものは下記3つかなと思います。

- Storage Capacity Tracking: `VolumeCapacityPriority`feature(alpha) で statically provisionedなvolumeのcapacityを考慮してNodeを選べるようになった
- Scheduler extenderのfilterフェーズにおいて`Unresolvable` nodeが返せるようになった
- `PreferNominatedNode`featureでpreemption時にパフォーマンスが向上した

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

# What's New (新情報)

## Storage Capacity Tracking

従来、KubernetesのSchedulerは追加のPersistentVolumeがクラスタ内のどこでも利用可能であり、容量が無制限であるという仮定に基づいています。

トポロジーの制約は前者に対応していましたが、これまでは残りのストレージ容量が新しいポッドを起動するのに十分でない可能性を考慮せずにPodのスケジューリングが行われていました。 

- :pencil: [Storage - Persistent Volumes - Node Constraint](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#node-affinity)

ストレージのキャパシティトラッキングがその問題に対応します。CSI driverへストレージキャパシティをレポートするためのAPIを追加し、PodのためのノードをSchedulerが選択する時にその情報を利用します。

- :pencil: [Storage - Storage Capacity](https://kubernetes.io/docs/concepts/storage/storage-capacity/) (FEATURE STATE: Kubernetes v1.21 [beta])

この機能は、ローカルボリュームや、より容量に制約のある他のボリュームタイプのダイナミックプロビジョニングをサポートするための足がかりとなります。

:pencil: 実際に対応された機能についてはFeaturesの節で後述します。

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

:pencil: ありません。

# Deprecation (非推奨)

- 非推奨だった`scheduling_algorithm_preemption_evaluation_seconds`,`binding_duration_seconds`というメトリクスが削除されました。代替として、`scheduler_framework_extension_point_duration_seconds`の利用を推奨します。([#96447](https://github.com/kubernetes/kubernetes/pull/96447), [@chendave](https://github.com/chendave)) [SIG Cluster Lifecycle, Instrumentation, Scheduling and Testing]
  - :pencil: `scheduler_framework_extension_point_duration_seconds`メトリクスには[`extention_point`,`status`,`profile`ラベルが付与されます](https://github.com/kubernetes/kubernetes/blob/v1.21.0/pkg/scheduler/metrics/metrics.go#L127)。

# API Change （API の変更）

- bazelによるKubernetesビルドサポートを削除。([#99561](https://github.com/kubernetes/kubernetes/pull/99561), [@BenTheElder](https://github.com/BenTheElder)) [SIG API Machinery, Apps, Architecture, Auth, Autoscaling, CLI, Cloud Provider, Cluster Lifecycle, Instrumentation, Network, Node, Release, Scalability, Scheduling, Storage, Testing and Windows]
- Scheduler extenderのfilterインターフェースにおいて、`ExtenderFilterResult`structに新しく追加された`FailedAndUnresolvableNodes`フィールドによって、スケジュール不可能かつ解決不能なノード(unresolvable failed nodes)を報告できるようになりました。このMap内のノードはpreemptionフェーズでは無視されます。([#92866](https://github.com/kubernetes/kubernetes/pull/92866), [@cofyc](https://github.com/cofyc)) [SIG Scheduling]

  - :pencil: Schedulerでは、nodeのfilter時において、filter失敗(failed)と解決不能(unresolved)を区別しており、unresolvedなnodeはpreemption時にvictim検索から除外されます
  - :pencil: これまでのscheduler extenderにおけるfilterでは、schedule不能なnodeを[`FailedNodes`というフィールドで返すことができました](https://github.com/kubernetes/kubernetes/blob/v1.21.0/staging/src/k8s.io/kube-scheduler/extender/v1/types.go#L93-L94)が、そもそもNodeがnot readyな場合等の解決不能(Unresolved)なnodeと区別することが不可能でした。
  - :pencil: この変更によって[`FailedAndUnresolvableNodes`](https://github.com/kubernetes/kubernetes/blob/v1.21.0/staging/src/k8s.io/kube-scheduler/extender/v1/types.go#L95-L98)フィールドを使って、そのようなnodeを単にスケジュール不可能なノードと区別して返答できるようになり、効率よくpreemptionが実行できるようになりました。

- PodDisruptionBudget API が`policy/v1`に昇格しました。schemaの変更はありません。唯一の機能変更は、空のセレクター(`{}`)が、該当namespaceの全podを選択するようになった事です。`policy/v1beta1`APIの振る舞いは変更はありません。 `policy/v1beta1`PodDisruptionBudget APIは非推奨になり、1.25+では提供されなくなります。([#99290](https://github.com/kubernetes/kubernetes/pull/99290), [@mortent](https://github.com/mortent)) [SIG API Machinery, Apps, Auth, Autoscaling, CLI, Cloud Provider, Cluster Lifecycle, Instrumentation, Scheduling and Testing]

# Feature （機能）

- Schedulerにおいて、複数のトポロジーに跨って静的にprovisionされたPVのうち、サイズが最もマッチするノードを優先度付けするalpha feature `VolumeCapacityPriority` を追加しました。([#96347](https://github.com/kubernetes/kubernetes/pull/96347), [@cofyc](https://github.com/cofyc)) [SIG Apps, Network, Scheduling, Storage and Testing]

  - :pencil: [KEP-1845: Prioritization on volume capacity](https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1845-prioritization-on-volume-capacity#motivation)
  - :pencil: 例えば、下記のように２つのノードにそれぞれLocal Volumeが宣言されているとします。
  - :pencil: `vol-1`: `capacity.storage=10Gi` on `node-1`(by `nodeAffinity`)
  - :pencil: `vol-2`: `capacity.storage=2Gi` on `node-2`(by `nodeAffinity`) 
  - :pencil: このとき、`requests.storage=1Gi`をもつPVCをvolumeとするPodをスケジュールする場合、従来であればどちらが選ばれるかを制御できなかったところ、このfeatureをONにすることで、`node-2`が選択されやすくなります(schedule時のnode優先度が高くなります)。これによってVolumeの利用効率が向上します。
  - :pencil: Amazon EBSのようなcloud storageでもstatic provisionedなvolumeであればnode topology(e.g. availability zone)を考慮してスコアリングされます
  
- Kube-schedulerが`--v=4`でpluginによるscoreサマリをlog出力するようになりました。([#99411](https://github.com/kubernetes/kubernetes/pull/99411), [@damemi](https://github.com/damemi)) [SIG Scheduling]
  - :pencil: 出力例→`"Top 3 plugins for pod on node" pod="default/mypodcn84p" node="kind-worker2" scores=[{Plugin:NodePreferAvoidPods Score:1000000 AverageScore:1e+06} {Plugin:PodTopologySpread Score:200 AverageScore:200} {Plugin:InterPodAffinity Score:100 AverageScore:52.333333333333336}]`
- `PreferNominatedNode` featureを有効することで、preemptionが頻繁に発生する状況でschedulingのパフォーマンスが全体的に向上します。しかし、この機能を有効にしても、最適な候補ノードにscheduleされない場合があります。([#93179](https://github.com/kubernetes/kubernetes/pull/93179), [@chendave](https://github.com/chendave)) [SIG Scheduling and Testing]

  - :pencil: [KEP-1923: Prefer Nominated Node](KEP-1923: Prefer Nominated Node)
  - :pencil: schedulerにおいて、preemptionは、2 scheduling cycleを伴います。
  - :pencil: 最初のcycleでは、victim podを停止し、victim podが動いていたnodeを `.status.nominatedNodeName`フィールドに設定する。preemptor podはscheduler内部のqueueにrequeueされる。
  - :pencil: 次のcycleは、preemptor podを通常通りスケジュールするcycleです(前のcycleでvictimを停止しているのでschedule可能なことが期待できるだけで、victimノードにスケジュールされることは保証していません)。
  - :pencil: この変更は、後者のサイクルにおける変更です。従来は、preemptorをスケジュールする際、通常どおり、nominatedNode以外のノードも含めて通常通り評価(filter→score)しスケジュール先ノードを決定していましたが、これだと大規模なクラスタでは時間がかかります。
  - :pencil: この機能を有効にすることで、`.status.nominatedNodeName`フィールドを優先してノード評価するようになります(つまりこのノードがスケジュール可能なら他のノードは見ないでここにbindする)。
  - :pencil: もしこのノードに適合しない場合、scheduling cycleは通常通りクラスタ内の残りのノードを評価します。
- `NodeAffinity`pluginが`PreFilter`拡張を実装することで `Filter`フェーズのパフォーマンスを向上しました。 (#99213, @AliceZhang2016) [SIG Scheduling]
  - :pencil: Nodeの状態はscheduling cycleに渡って変更されることが無いため、`NodeAffinity`の計算を`PreFilter`時に一度だけ計算し、`CycleState`にキャッシュすることによって効率を向上しています

# Documentation

:pencil: ありません。

# Failing Test (失敗しているテスト)

:pencil: ありません。

# Bug or Regression （バグまたはリグレッション）

- `InterPodAffinity` Pluginのスコアがより強く区別されるようになりました。([#98096](https://github.com/kubernetes/kubernetes/pull/98096), [@leileiwan](https://github.com/leileiwan)) [SIG Scheduling]
  - :pencil: これまで `InterPodAffinity` Pluginの出力するスコアの計算方法(Normalize時の値域が広くなった)が変更され、node選択により色濃く反映されるようになりました。
- `VolumeBindingArgs`で`BindTimeoutSeconds`をゼロで設定できるようになりました。ゼロを設定すると、volume binding操作のチェックをまたなくなります。([#99835](https://github.com/kubernetes/kubernetes/pull/99835), [@chendave](https://github.com/chendave)) [SIG Scheduling and Storage]

# Other (その他の修正)

- v1.17でGAになった`CSINodeInfo`feature gateが無条件にenabledになり、`--feature-gates`引数に指定できなくなりました。 ([#96561](https://github.com/kubernetes/kubernetes/pull/96561), [@ialidzhikov](https://github.com/ialidzhikov)) [SIG Apps, Auth, Scheduling, Storage and Testing]
- デフォルトの委任認可オプションでは、` healthz, readyz, and livez`への非認証アクセスを許可するようになりました。また、`system:masters` ユーザからの接続では認可チェックを行わないようになりました。 ([#98325](https://github.com/kubernetes/kubernetes/pull/98325), [@deads2k](https://github.com/deads2k)) [SIG API Machinery, Auth, Cloud Provider and Scheduling]
- RotateKubeletClientCertificate, AttachVolumeLimit, VolumePVCDataSource and EvenPodsSpread` feature gateが無条件にenabledになり、componentから指定できなくなりました。  ([#97306](https://github.com/kubernetes/kubernetes/pull/97306), [@gavinfish](https://github.com/gavinfish)) [SIG Node, Scheduling and Storage]
  - :pencil: これらのfeature gateは既に全てGAとなっています。