Kubernetesノードの安定性向上のためのLinuxスワップパラメータのチューニング
swappinessやウォーターマークなどのカーネルパラメータを深く掘り下げ、OOMキルを引き起こすことなくKubernetes v1.34でスワップを安全に有効化する方法を探ります。
英語の原文から自動翻訳されました。
2025年8月のKubernetes Blogへの投稿で、GoogleのAjay Sundar Karuppasamy氏は、Kubernetesクラスタ向けにLinuxスワップをチューニングする方法について詳しく解説しました。この記事では、ノードがディスク領域を仮想メモリとして使用できるようにするNodeSwap機能がKubernetes v1.34で安定版(stable)になることを踏まえ、リソース利用率とシステム安定性のバランスを取るためにカーネルパラメータを入念に設定する必要性を取り上げています。
何が起きたか
長年にわたり、Kubernetesオペレーターに対する標準的なアドバイスは、予測可能なパフォーマンスを確保するためにスワップを完全に無効化することでした。しかし、NodeSwap機能の導入により、このパラダイムは変化し、Linuxノードがあまり頻繁に使用されないメモリページを二次ストレージへオフロードできるようになりました。この機能は、アウト・オブ・メモリー(OOM)キルの削減と全体的なリソース効率の向上を目指しています。これらの利点があるものの、スワップの有効化は単純なトグル操作ではありません。正確なチューニングを行わない場合、深刻なパフォーマンス低下を招き、Kubeletによるポッドのエビクション(退避)処理を妨げる可能性があります。
記事では、スワップ設定の誤りが、メモリ負荷時にカーネルを予測不能な挙動に導く可能性があることを強調しています。デフォルト設定でのテストでは、高いメモリ割り当て率にさらされたノードで予期しない再起動や早すぎるOOMキルが発生しました。根本的な問題は、Linuxカーネルのページ置換アルゴリズムとKubernetesのエビクションロジックとの相互作用にあります。カーネルが十分に速くメモリを回収できない場合や、誤った種類のメモリを回収した場合は、Kubeletが対応する前にノードが不安定になる可能性があります。
これらの課題に対処するため、著者はKubernetes v1.33.2を実行しているGoogle Kubernetes Engine (GKE) ノード上で一連のストレステストを実施しました。テストには、さまざまなメモリアクセスパターンや負荷をシミュレートするために設計されたカスタムのGoアプリケーションが含まれていました。特定のカーネルパラメータを調整することで、著者は急激な需要スパイク中に致命的な障害を防ぎ、メモリ管理のためのより安全な運用ウィンドウを作成する方法を示しました。
仕組み
Linuxはメモリをページ単位で管理しており、通常は各ページが4KiBです。物理RAMがいっぱいになると、カーネルはどのページをスワップ領域へ移動するかを決定する必要があります。ヒープやスタックデータなどの匿名メモリと、実行可能コードやキャッシュなどのファイルバックドメモリを区別します。匿名ページは回収するためにスワップデバイスへ書き込む必要がありますが、クリーンなファイルバックドページは単に破棄できます。カーネルはこれらの判断をガイドするために複数のパラメータを使用しており、主にvm.swappinessが匿名ページの交換とファイルキャッシュの破棄の優先度を制御します。

他の重要な2つのパラメータはvm.min_free_kbytesとvm.watermark_scale_factorです。min_free_kbytes設定は、空きメモリの安全バッファを定義します。利用可能なメモリがこの閾値を下回ると、カーネルは積極的にページを回収します。watermark_scale_factorは、低(low)、最小(min)、高(high)のメモリウォーターマーク間のギャップを決定します。ギャップが大きいほど、背景回収プロセスであるkswapdがページを徐々にスワップへ移動させるための時間が確保されます。これにより、プロセスの割り当てをブロックしOOMキルを引き起こす可能性のあるクリティカルな最小ウォーターマークにシステムが急速に到達することを防ぎます。
主要な詳細
- NodeSwap機能は、Kubernetes v1.34で安定版(stable)ステータスへ昇格する予定です。
- テストは、8GiB RAMとpd-balancedディスク上の50GBスワップを持つGKEノードで実施されました。
- デフォルト設定(
swappiness=60、min_free_kbytes=68MB)では、高負荷時にOOMキルが発生しました。 min_free_kbytesを512MiBに増加させると、より早期のメモリ回収が強制され、より大きな安全バッファが提供されます。watermark_scale_factorを2000に設定すると、スワッピングウィンドウが広がり、kswapdがより効果的に動作できるようになります。- kubeletやコンテナランタイムなどのクリティカルなシステムコンポーネントについては、cgroupsを通じてスワップを無効にする必要があります。
なぜ重要なのか
ソフトウェアエンジニアやプラットフォームチームにとって、スワップの有効化は容量とレイテンシーの間で複雑なトレードオフを生み出します。スワッピングはRAMへのアクセスよりも著しく遅いため、アプリケーションのアクティブなワーキングセットがディスクへ移動されると、I/O待ち時間の増加によりパフォーマンスが低下します。しかし、適切にチューニングされたスワップは、OOMキルによる突然のアプリケーションクラッシュを防ぐことができます。これは、一時的なレイテンシーのスパイクよりもしばしば破壊的です。これらのカーネルメカニズムを理解することは、メモリ過剰コミットメントを安全に処理できるレジリエントなシステムを構築するために不可欠です。

さらに、不適切なチューニングはメモリリークなどの根本的な問題を隠蔽する可能性があります。OOMキルによって迅速に失敗する代わりに、リークのあるアプリケーションはスワップ領域を消費してノードのパフォーマンスを徐々に低下させ、診断を困難にする場合があります。また、Kubernetesのグレースフルエビクション(Graceful Eviction)メカニズムをバイパスするリスクもあります。Kubeletがポリシーに基づいてポッドをエビクションする前にカーネルがOOMキルを発動した場合、優先度の高いワークロードが予期せず終了される可能性があります。したがって、クラスタの健全性を維持するには、カーネルの挙動をKubernetesの期待に合わせて整合させることが重要です。
実行できること
- 汎用的なワークロードの場合は
vm.swappiness=60から開始し、アプリがI/Oに敏感か、キャッシュ多用型かによって調整してください。 - 十分な安全バッファを作成するために、
vm.min_free_kbytesをノード総メモリの約2〜3%(例:8GiBノードなら500MB)に設定してください。 vm.watermark_scale_factorを2000に増やして、スワッピングウィンドウを広げてください。- クリティカルなシステムコンポーネント(kubeletなど)のスワップをcgroups経由で無効にしてください。


