Kubernetes 1.32、APIストリーミングを導入しリストリクエストによるメモリスパイクを解消
Kubernetes 1.32ではwatch list機能がベータ版に昇格し、クライアントは大量のリソースコレクションをストリーム配信できるようになり、APIサーバーのメモリ不足(OOM)クラッシュを防ぐことができます。
英語の原文から自動翻訳されました。
2024年12月のKubernetes Blogの投稿で、Upbound、Google、Red Hatのエンジニアが、Kubernetes APIサーバーにおける重要なメモリ効率改善について詳細を説明しました。このアップデートは、大規模クラスターでのバルクデータ取得時の挙動に対処し、高負荷時に急激なメモリ枯渇を引き起こさないためのストリーミングメカニズムを導入しています。
何が起きたか
大規模なKubernetesクラスターの管理では、コンポーネントが list リクエストを発行する際に、顕著なメモリオーバーヘッドが発生することがよくあります。従来の実装では、kube-apiserverはクライアントにデータを送信する前に、レスポンス全体をメモリ上で組み立てる必要がありました。レスポンスボディが数百メガバイトに及ぶ場合や、ネットワーク障害後に複数のリクエストが同時に到着した場合には、この処理により利用可能なRAMが急速に消費されることがあります。既存のAPI Priority and FairnessメカニズムはCPU過負荷に対する保護を提供しますが、これらの無制限なメモリスパイクに対しては限定的な保護しか提供できません。
調査の結果、このメモリ割り当ては、サーバーがデータベースからデータを取得し、それをデシリアライズして、最終的なレスポンス形式を一度に構築するために発生することが判明しました。このシーケンスは巨大な一時的なメモリフットプリントを生み出し、Goのガベージコレクションも設定されたメモリ制限も、急激なスパイク時には効果的に管理できません。高可用性環境では、これによりカスケード障害が発生する可能性があります。あるAPIサーバーがメモリ不足(OOM)状態によりクラッシュすると、同じ重いリクエストが他のノードに転送され、それらも失敗するという状況です。
これを解決するため、Kubernetesチームはバージョン1.32で watch list 機能をベータ版に昇格させました。これにより、クライアントは標準的な list リクエストから特殊な形式の watch リクエストへ切り替えることで、リストのストリーミングを利用するためのオプトインが可能になります。これらのリクエストを watch cache から提供することで、サーバーはコレクション全体をバッファリングするのではなく、個々のアイテムを個別にストリーム配信します。この変更により、メモリオーバーヘッドは一定に保たれ、単一のオブジェクトの最大サイズとわずかな割り当てのみによって制限されるため、多くの大きなオブジェクトを持つクラスターの安定性が劇的に向上します。
仕組み
コアとなるメカニズムは、バッチ処理からストリーミングへの移行に基づいています。従来の list リクエストでは、サーバーはシリアライゼーション中にデータセット全体をRAM上に保持する必要があります。対照的に、新しい watch list アプローチは、読み取り操作のスケーリング用に設計されたインメモリキャッシュである既存のwatch cacheを活用します。クライアントがこの方法を使用する場合、APIサーバーはキャッシュから取得されたオブジェクトを一つずつ送信し、完全なレスポンスボディのために一度にメモリを割り当てる必要を回避します。

このアーキテクチャの変更により、メモリ使用量はコレクション内のオブジェクトの総数から切り離されます。リストのサイズに応じてメモリ消費量が線形に増加する代わりに、返されるアイテムの数に関係なくフラットな状態を保ちます。これにより、APIサーバーは substantial なペイロードを持つSecretsなど、数千もの大きなリソースを処理する場合でも耐性を持ち、OOMキルのリスクを負うことなく運用できます。
主要な詳細
- watch list 機能はKubernetes 1.32でベータステータスに到達しました。
- クライアントは、ストリーミングリストを使用するためにclient-goで
WatchListClientフィーチャーゲートを明示的に有効にする必要があります。 - 合成テストでは、ストリーミングを有効にした場合のメモリ使用量は2 GBで安定しましたが、無効にした場合は20 GBに達しました。
- この機能にはetcdバージョン3.4.31以上または3.5.13以上が必要です。
- Kubernetes 1.33では、クライアント側の変更なしでサーバー側のストリーミングを実現するための新しいフィーチャーゲート
StreamingCollectionEncodingToJSONとStreamingCollectionEncodingToProtobufが導入されました。 WatchListフィーチャーゲートはKubernetes 1.33ではデフォルトで無効ですが、1.32ではkube-controller-managerに対してデフォルトで有効でした。
なぜ重要なのか
大規模クラスターを管理するプラットフォームエンジニアやSREにとって、このアップデートはコントロールプレーンの安定性における脆弱な点を対処します。APIサーバーでのメモリ枯渇は診断と回復が困難であり、しばしばコントロールプレーン全体の停止につながります。ストリーミングリストを採用することで、チームはより複雑なリソースを含む大規模なクラスターを実行でき、定常的なレコンシリエーションループや障害後の同期が管理層をクラッシュさせることを恐れる必要がなくなります。
この変更は、将来のバージョンでのAPIコスト計算にも影響を与えます。現在、API Priority and Fairnessは一般的なユースケースでの並列性を維持するために、list リクエストに低いコストを割り当てています。エコシステムが watch lists へと移行するにつれて、システムは従来の list リクエストのコスト見積もりを安全に増やすことができます。これにより、高額なバルクリクエストを発行し続けるレガシークライアントや誤設定されたツールに対するより良い保護が提供され、クラスター全体でのリソース配分がより公平になります。
できること
- ベータ版の watch list 機能にアクセスするために、クラスターをKubernetes 1.32以降にアップグレードしてください。
- 互換性を確保するために、etcdのバージョンが少なくとも3.4.31または3.5.13であることを確認してください。
- Golangベースのクライアントを更新し、client-goで
WatchListClientフィーチャーゲートを有効にしてください。 - ピーク負荷時にAPIサーバーのメモリ使用量を監視し、大きな list リクエストがまだスパイクを引き起こしているかどうかを特定してください。
- ベータ段階において、環境内のサードパーティ製コントローラーやオペレーターがストリーミングAPIを採用することを推奨してください。
- クライアントコードの変更を必要としないサーバー側のストリーミングエンコーディング機能を活用するために、Kubernetes 1.33への将来のアップグレードを計画してください。


