Kubernetes 1.32: SIG Storageの変更内容

# はじめに

Kubernetes 1.32.0がリリースされました🎉

それでは、[Kubernetes 1.32.0のCHANGELOG](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.32.md#v1320)をベースにSIG Storageに関する変更について紹介します。

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

過去 3 リリースの変更内容:
- [Kubernetes 1.31: SIG Storageの変更内容](https://qiita.com/ysakashita/items/e5121b77bea1fbd170f5)
- [Kubernetes 1.30: SIG Storageの変更内容](https://qiita.com/ysakashita/items/07fab50bff17c10fa07d)
- [Kubernetes 1.29: SIG Storageの変更内容](https://qiita.com/ysakashita/items/de08b58ac87a52d02011)

# :pencil: 所感

新機能としては`SELinuxChangePolicy`フィーチャーゲートの導入が挙げられますが、それ以外はほぼBugFix, Scalability改善が主だと感じました。Scheduler系の変更も多く挙げられていますが、主に性能改善を目的としたものです。

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

v1.32リリースではUrgent Upgrade Notesはありません。

# :wastebasket: Deprecation (非推奨になったAPI)

:pencil: SIG Storage関連のものはありません

# :earth_asia: API Changes (API周りの変更)

- Access Modeが`ReadWriteOncePod`なvolumeに対しても`fsGroup` policyが適用されます([#128244](https://github.com/kubernetes/kubernetes/pull/128244), [@gnufied](https://github.com/gnufied))
  - :pencil: CSI Volumeに対する変更です。Bug扱いでも良い程度の変更と思われます。API Changesのカテゴリに含まれてしまっているのは、APIを定義するファイルのコメント修正が含まれているためです。これまでは`ReadWriteOnce` access modeのCSI volumeにしか `fsGroup` が適用されていませんでした
- Podレベルの`securityContext`内に、新しく`seLinuxChangePolicy`フィールドがalphaレベル(フィーチャーゲート: `SELinuxChangePolicy`)で実装されました。 このフィールドは、`SELinuxMount`フィーチャーゲート(現在はアルファ版で、デフォルトでは無効)が有効になっている場合に、SELinuxラベル付きのPodボリュームのマウントをオプトアウトするためのものです。 SELinuxの動作がどのように変更になるか、どのようにオプトアウトするか、については、[KEP](https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1710-selinux-relabeling#story-3-cluster-upgrade)を参照してください。 このフィールドと機能ゲートはSELinuxが有効なクラスタでのみ有効であることに注意してください。 SELinuxが有効でないクラスタでは何もする必要はありません
  - :pencil: [KEP-1710: Speed up recursive SELinux label change](https://github.com/kubernetes/enhancements/issues/1710)
    これまでの`SELinuxMount`フィーチャーゲートの機能は`-o context=<SELinux lagel>`というマウントオプションを利用してボリュームをマウントすることで高速なrelabelingが実現されていました。しかし、この方法だと、Pod内にprivilegedコンテナとunprivilegedコンテナが共存すること(正確には、コンテナ間で異なるSELinuxラベルを持つボリュームマウント)は実現できません。そのためこのフィーチャーでは、`seLinuxChangePolicy: Recursive | MonuntOptions (これまでの挙動)`を導入し、`Recursive`を指定した場合にはマウント後にRecursiveに全ファイルをrelabelすることで共存を可能にしています
- kube-schedulerから`AzureDiskLimits` ,`CinderLimits`,`EBSLimits`,`GCEPDLimits`プラグインが削除されました。それぞれに対応するCSIドライバはNodeGetInfoResponse経由でノードが処理できるボリューム数を報告することで、kubeletがこの制約をCSINodeに格納します。スケジューラはCSINodeから、そのノード上のドライバの制約を把握します。 AzureDiskLimits, CinderLimits, EBSLimits, GCEPDLimits プラグインをスケジューラー設定で明示的に有効にしている場合は削除する必要があります。([#124003](https://github.com/kubernetes/kubernetes/pull/124003), [@carlory](https://github.com/carlory))
  - :pencil: [KEP-625 In-tree storage plugin to CSI Driver Migration](https://github.com/kubernetes/enhancements/issues/625)の残作業のようです
  - :pencil: ChangeLogに記載の通り、これらのプラグインを明示的に有効にしている場合には設定からの削除が必要です。既に`NodeVolumeLimits`プラグインで同等の機能が提供されています
- `NodeRestriction`アドミッションは、kubeletが、Pod Spec Volumeに定義されるServiceAccountトークンを要求する際にaudienceの値をvalidateするようになります。 kube-apiserverの`ServiceAccountNodeAudienceRestriction`フィーチャーゲートで有効化されます(デフォルト有効です) ([#128077](https://github.com/kubernetes/kubernetes/pull/128077), [@aramase](https://github.com/naramase))
  - :pencil: [KEP-4412: Projected service account tokens for Kubelet image credential providers](https://github.com/kubernetes/enhancements/issues/4412)の一環です(KEP-4412自体はv1.33でAlphaを予定)
  - KEP-4412に記載の通り、`ServiceAccountNodeAudienceRestriction`フィーチャーゲート自体は
    - 最初からBetaレベルでの導入
    - このvalidation追加は既存の機能を壊すようなものではないはず
  - KEP-4412の概要
    - モチベ: 
      - LongLivedなImage Pull Secretをできるだけなくしていきたい
    - 変更概要:
      - Kubelet Credential Provider Configに`tokenAttributes`という新しいfieldが追加
      - このフィールドが定義されていると、Service Accountトークンが別途発行されCredential Providerに渡される
        - つまり、Service AccountトークンからImage Pull Secretを生成するような細かく権限制御されたCredential Providerが開発可能になって良さそう👍
      - 発行時にService Accountトークン発行時にAudienceがvalidateしたいので`ServiceAccountNodeAudienceRestriction`を事前にリリース
      - Credential Provider Configに定義されるaudienceはapiserverは知ることができないので`--allowed-kubelet-audiences`というFlagが追加される

# :sparkle: Features (機能追加)

- kube-controller-managerにvolumeattributesclass-protection-controllerが新しく追加されました。この新しいコントローラは`VolumeAttributesClass`オブジェクトを保護するfinalizerを管理します。([#123549](https://github.com/kubernetes/kubernetes/pull/123549), [@carlory](https://github.com/carlory))
  - :pencil: [KEP-3751 Kubernetes VolumeAttributesClass ModifyVolume](https://github.com/kubernetes/enhancements/blob/master/keps/sig-storage/3751-volume-attributes-class/README.md)のGA Graduationに向けた機能追加です
- `CSILimit`プラグインでPersistentVolumeClaim/Addイベントに対するQueueing Hintを実装しました([#124703](https://github.com/kubernetes/kubernetes/pull/124703), [@utam0k](https://github.com/utam0k))
  - :pencil: kube-schedulerの変更です
- `RecoverVolumeExpansionFailure`フィーチャーゲートがBetaに昇格しました([#128342](https://github.com/kubernetes/kubernetes/pull/128342), [@gnufied](https://github.com/gnufied))
  - :pencil: [KEP-1790 Support recovery from volume expansion failure](https://github.com/kubernetes/enhancements/issues/1790)
- `SizeMemoryBackedVolumes`がStableに昇格しました([#126981](https://github.com/kubernetes/kubernetes/pull/126981), [@kannon92](https://github.com/kannon92))
  - :pencil: [KEP-1967: Sizable memory backed volumes](https://github.com/kubernetes/enhancements/issues/1967)
  サイズ未指定の`medium: Memory`な`emptyDir`はサイズ上限がnodeのallocatableになるので注意が必要です(以前はallocatableの50%と明記されていたが実装と乖離があって[kubernetes/website#40723](https://github.com/kubernetes/website/issues/40723)で修正されました)。[Kubernetes クラスター全体を実働不可能にさせかねない不注意なmemory-backed emptyDirの利用](https://qiita.com/shu-mutow/items/292d43606ad4c658c2ae)でとても詳しく解説されていますので参照してください
- kubelet起動時に、次のvolume typeに対応するCSI driverがインストールされている場合、nodeのattachable volume limitsを削除します:
  - `awsElasticBlockStore` for `ebs.csi.aws.com`
  - `azureDisk` for `disk.csi.azure.com`
  - `gcePersistentDisk` for `pd.csi.storage.googleapis.com`
  - `cinder` for `cinder.csi.openstack.org`
  - `csi`
  ただし、これらの制約はすでに`CSINode` オブジェクトによって強制されています ([#126924](https://github.com/kubernetes/kubernetes/pull/126924), [@carlory](https://github.com/carlory))
- schedulerのVolumeBindingプラグインでCSIDriverイベントに対する`QueueingHint`を実装しました。これによってスケジューリングのスループットが改善されます([#125171](https://github.com/kubernetes/kubernetes/pull/125171), [@YamasouA](https://github.com/YamasouA))
- `SchedulerQueueingHint`が有効な場合、schedulerのin-treeプラグインは、Podをいつrequeueするかを判断するために、複数のNodeイベント(taints, tolerations, allocatableの更新)をsubscribeするようになります。これによってschedulerはCluster Eventをより速く省メモリで処理できるようになります。またIn-treeプラグインはこれらのフィールドが変更されない更新は無視するようになります([#127220](https://github.com/kubernetes/kubernetes/pull/127220), [@sanposhiho](https://github.com/sanposhiho))

# 📃 Documentation (ドキュメント)

:pencil: SIG Storage関連のものはありません

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

- Windowsでkubelet pluginが15ms未満でre-registrationを行う場合でも適切にre-registerされるようになります([#114136](https://github.com/kubernetes/kubernetes/pull/114136), [@claudiubelu](https://github.com/claudiubelu))
  - :pencil: go 1.16で入ったRegressionの影響でWindowsの`time.Now()`の解像度が15ms程度になってしまっていたバグに対する修正。ただしこのバグはgo 1.23で修正済み([golang/go#44343](https://github.com/golang/go/issues/44343))

# :bug: Bug or Regression (バグ修正)

- 1. kubeletが`image` volume source typeを参照するCRIのMountを生成する際、これまで渡されていなかった`readOnly`, `propagation`, and `recursiveReadOnly`等のattributeを渡すようになります。もし、`volumeMount`の`readOnly`フィールドが明示的にfalseにセットされている場合でも、image volume pluginはマウントがread-onlyでなければならないため、kubeletは`readOnly`をtrueとしてCRI実装に渡します
  2. `image` volume source typeボリュームが、意図せずコンテナの`/etc/hosts`にマウントできてしまうバグを修正しました([#126806](https://github.com/kubernetes/kubernetes/pull/126806), [@carlory](https://github.com/carlory))
  - :pencil: [KEP-4639 VolumeSource: OCI Artifact and/or Image](https://github.com/kubernetes/enhancements/issues/4639)
- Node名とhostnameラベルが異なる場合に、`nodeAffinity`で`hostname`を使っているPersistentVolumeが間違ったNodeにスケジュールされたり、スケジュール失敗したりするバグを修正([#125398](https://github.com/kubernetes/kubernetes/pull/125398), [@AxeZhan](https://github.com/AxeZhan))
- kubeletの再起動中にflex volume pluginのunmountエラーの原因になるrace conditionを修正しました([#127669](https://github.com/kubernetes/kubernetes/pull/127669), [@olyazavr](https://github.com/olyazavr))
- kubeletの再起動中にflex volume pluginのunmountエラーの原因になるrace conditionを修正しました([#128495](https://github.com/kubernetes/kubernetes/pull/128495), [@olyazavr](https://github.com/olyazavr))
  - :pencil: 直前のPRのfollowupです
- kubelet/volumemanagerのdata raceを修正しました ([#127919](https://github.com/kubernetes/kubernetes/pull/127919), [@carlory](https://github.com/carlory)) 
- PVC Protection Controllerで、PVCをnamespace毎にBatch-Processingし、live podのリスティングをlazyにすることで、scalabilityを改善しました([#125372](https://github.com/kubernetes/kubernetes/pull/125372), [@hungnguyen243](https://github.com/hungnguyen243))
  - :pencil: このPRは後に[kubernetes/kubernetes#126723](https://github.com/kubernetes/kubernetes/pull/126723)でRollbackされ、↓のPRで再修正されました
- PVC Protection Controllerで、PVCをnamespace毎にBatch-Processingし、live podのリスティングをlazyにすることで、scalabilityを改善しました([#126745](https://github.com/kubernetes/kubernetes/pull/126745), [@hungnguyen243](https://github.com/hungnguyen243))
  - :pencil: PVCがdeleteされた時、PVC protection controllerは、最終チェックとしてLive Podをリストして確認を行います(pod informerからの結果が空のときだけ実行されます)。この処理はPVCやPodが大量に存在する場合は大きな負荷となるため、この修正では、namespace単位でPVCをバッチ処理すると同時に、Live Pod Listを非同期に取得しメモリにキャッシュすることでスケーラビリティを改善しています。PRでは10k Pods/PVCの場合で、PVC削除にかかる時間が`>120m`→`22m`に改善しています(PRではより詳細なベンチマーク結果が掲載されています)
- Node shutdown controllerは、pod priority group毎にCSI Driverがvolumeのteardown処理を完了するのをbest effortで待つようになります([#125070](https://github.com/kubernetes/kubernetes/pull/125070), [@torredil](https://github.com/torredil)) 
  - :pencil: node shutdown managerはpod priority group事に(non-critical→critical)停止を行いますが、pod停止処理内で行われるvolume teardown処理は並行で処理されるため、CSI Driver Pod(criticalな想定)が実際のvolumeのtear downよりも前に停止されてしまい、結果としてteardownが不完全なCSI Volumeが残ってしまうバグがありました。このPRではnode shutdown managerで、次のpod priority groupの停止処理に移る前に、volumeが全てumountされていることを確認(gracePeriod付き)してから進むように変更しています。ただしこの確認はbest effortでもし確認取れない場合はerror logが出力されるにとどまります。尚、このgracePeriodはkubeletの[`shutdownGracePeriod/shutdownGracePeriodCriticalPods/shutdownGracePeriodByPodPriority`で設定できます](https://kubernetes.io/docs/concepts/cluster-administration/node-shutdown/)
- volume attachmentを待つ際のメモリ利用/アロケーションを削減([#126575](https://github.com/kubernetes/kubernetes/pull/126575), [@Lucaber](https://github.com/Lucaber)) 
- `system:controller:persistent-volume-binder`と`system:controller:expand-controller` clusterroleから不要なpermissionを削除 ([#125995](https://github.com/kubernetes/kubernetes/pull/125995), [@carlory](https://github.com/carlory))
- kubeletのCSI Volume Pluginは、volumeのattachを待っている間、VolumeAttachmentオブジェクトが見つからないか、Volumeがアタッチされていない場合、VolumeAttachmentオブジェクトをwatchしなくなりました。 以前は、パーミッション不足で失敗していました。 ([#126961](https://github.com/kubernetes/kubernetes/pull/126961), [@carlory](https://github.com/carlory))
- Usage, VolumeConditionは共にoptionalであり、CSIVolumeHealthフィーチャーゲートが有効な時は、kubeletはこれらのフィールドのどちらかがセットされているときだけメトリクスを返す必要があります([#127021](https://github.com/kubernetes/kubernetes/pull/127021), [@Madhu-1](https://github.com/Madhu-1))
  - :pencil: Volume Health Monitorの修正ですが、修正内容とChangeLogの文言に乖離があるようです。これまでVolumeConditionをSupportしているVolumeでも、`usage==nil`が許容されておらず、metricsが出力されていませんでしたが(volume healthがabnormalで、かつusageがreportされてない場合)、VolumeConditionをサポートしているvolumeについては、usageが空を許容するように変更されています
- Pod statusの`qosClass`フィールドのvalidationを強化しました。このフィールドはimmutableですが、statusサブリソースを使って更新する際に、newStatusが空の場合にはoldStatusの値をmutableします。([#127744](https://github.com/kubernetes/kubernetes/pull/127744), [@carlory](https://github.com/carlory))
  - :pencil: statusサブリソースを使って更新する際に`qosClass`がmutableにってしまっていたようです

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

:pencil: SIG Storage関連のものはありません