コンテンツに移動
Containers & Kubernetes

Google Kubernetes Engine の高パフォーマンス ストレージ向けローカル SSD

2023年3月2日
Google Cloud Japan Team

※この投稿は米国時間 2023 年 2 月 18 日に、Google Cloud blog に投稿されたものの抄訳です。

Google Kubernetes Engine(GKE)のユーザーは、AI / ML、分析、バッチ処理、メモリ内キャッシュなど、データを迅速にダウンロードして処理する必要があるアプリケーション用にローカル SSD を使用しています。これらのアプリケーションは、Google Cloud Storage(GCS)などのオブジェクト ストレージからローカル SSD にデータをダウンロードし、GKE の Pod として実行されているアプリケーションでこのデータを処理します。処理中のデータはローカル ストレージと RAM の間を移動するため、1 秒あたりの入出力オペレーション(IOPS)のパフォーマンスが重要になります。以前は、GKE でローカル SSD を使用する場合、古い SCSI ベースのテクノロジーまたはベータ版(およびアルファ版)の API が利用されていました。現在では一般提供されている API を使用して、すべて NVMe ベースのエフェメラルまたは raw ブロック ストレージ ボリュームを作成可能で、SCSI に比べてパフォーマンスを最大 1.7 倍向上させることができます。

ローカル SSD は、物理ホストに直接アタッチされた高パフォーマンス SSD へのエフェメラル アクセス(一時的なアクセス)を許可する Compute Engine プロダクトです。ローカル SSD は PD SSDFilestore よりも高いパフォーマンスを発揮しますが、耐久性がやや弱く、Compute Engine インスタンスが停止した場合やさまざまなエラー条件が重なった場合にデータが失われます。ワークロードの IOPS の増加とレイテンシの改善が耐久性よりも必要である場合は、妥当なトレードオフであると言えます。

GKE は最近、組み込みのローカル SSD サポートの提供を開始しました。このローカル SSD は、馴染みのある Kubernetes API でプロビジョニング可能なエフェメラルおよび raw ブロック ストレージをアプリケーションに提供する初のマネージド Kubernetes プラットフォームとして利用できます。これは、エフェメラル ボリュームに分離を追加し、ローカル SSD を高パフォーマンスのローカル ストレージ用に構成できるように Google Cloud API の一般提供を開始するというアップストリーム Kubernetes コミュニティの取り組みの成果です。

GKE を介してローカル SSD を使用する場合の 2 つのオプション: 

1)エフェメラル ストレージのローカル SSD オプションは、Pod のライフサイクルに結びつけられたローカル SSD を基盤とするフルマネージドのローカル エフェメラル ストレージが必要なユーザー向けです。Pod がエフェメラル ストレージを要求すると、ローカル SSD がアタッチされているノードに自動的にスケジュールされます。クラスタの自動スケーリングが有効になっている場合、クラスタでエフェメラル ストレージ領域が足りなくなると、ノードが自動スケーリングされます。

2)ローカル SSD ブロック オプションは、基盤となるストレージの制御を強化したいユーザーや、Pod に独自のノードレベルのキャッシュを構築してアプリケーションのパフォーマンスを改善したいユーザー向けです。このオプションはカスタマイズすることも可能で、その場合は必要に応じて DaemonSet を実行し、ディスクを RAID 構成にしてフォーマットして、ローカル SSD にファイル システムをインストールします。

Google Cloud では、より高いパフォーマンスを実現できるよう、以前の(一般提供)ローカル SSD Count API新たに一般提供となった API に移行することを推奨しています。
https://storage.googleapis.com/gweb-cloudblog-publish/images/Table_1._GKE_Local_SSD_APIs_GA.max-1300x1300.jpg
表 1. GKE のローカル SSD API(一般提供)

新しい API の使用例をいくつか見ていきましょう。

例 1: emptyDir でエフェメラル ストレージのローカル SSD API を使用する

Kubernetes で管理する AI / ML アプリケーションがあり、データはローカル ストレージにダウンロードされて処理されるとしましょう。すべての Pod が同じ ML モデルを実行しており、各 Pod はデータの一部のトレーニングを担当しています。Pod 間でデータが共有されることはないため、emptyDir ボリュームをスクラッチ領域として使用し、ローカル SSD を基盤とするローカル エフェメラル ストレージでノードプールをプロビジョニングして、IOPS のパフォーマンスを最適化します。

このようなノードプールを作成するには、gcloud CLI で --ephemeral-storage-local-ssd count=<N> オプションを使用します。

読み込んでいます...

このコマンドは次のことを行います。

  • デフォルトのノードプールの各ノードに n 個のローカル SSD がアタッチされたクラスタを作成する。ディスクの最大数はマシンタイプとリージョンによって異なる

  • ラベル cloud.google.com/gke-ephemeral-storage-local-ssd=true を作成して各ノードに追加する。

  • すべてのローカル SSD をアレイ /dev/md/0 で RAID0 構成にして、ext-4 ファイル システムにフォーマットし、パス /mnt/stateful_partition/kube-ephemeral-ssd にマウントする。

  • コンテナ ランタイム ルート ディレクトリ、kubelet ルート ディレクトリ、Pod ログ ルート ディレクトリから構成されるエフェメラル ストレージを、ローカル SSD マウント ポイント /mnt/stateful_partition/kube-ephemeral-ssd にバインド マウントする。

--ephemeral-storage-local-ssd オプションは変更できません。ノードプールの作成後に、各ノードにアタッチされたローカル SSD の数は変更できません。このオプションが指定されていない場合、GKE はデフォルトでノードのローカル エフェメラル ストレージを永続ディスクのブートディスク(pd-standard、pd-ssd、pd-balanced のいずれか)で初期化します。N 個のローカル SSD がノードにアタッチされている場合、Pod で利用可能なローカル エフェメラル ストレージは次のようになります。

ノード割り当て可能 = 375 GiB x N - (kube-reserved + system-reserved + eviction-threshold)
https://storage.googleapis.com/gweb-cloudblog-publish/images/Diagram1-ephemeral-storage.max-2200x2200.jpg
図 1: NVMe を介した N 個のローカル SSD を基盤とするローカル エフェメラル ストレージがある GKE ノード

これでノードプールを作成できたので、次は emptyDir ボリュームをスクラッチ領域として使用してワークロードを作成します。Kubernetes の Pod は、emptyDir ボリューム、ログ、コンテナの書き込み可能レイヤを介して一時データへのアクセスやデータの書き込みを行います。ここで書き込まれるデータは一時的なものであり、コンテナまたは Pod が削除されると削除されます。先ほど作成したノードプールでは、これらのディレクトリはローカル SSD を使用しています。バージョン 1.25 以上の Kubernetes では、ローカルのストレージ容量の分離機能が一般提供されています。この機能では、Pod 間の共有ストレージの容量分離が可能で、Pod による共有リソースの消費量が上限を超えた場合に Pod を削除して消費量を制限します。また、リソース予約のためのエフェメラル ストレージのリクエストの設定も可能です。共有 ephemeral-storage の制限とリクエストは、メモリおよび CPU 消費量の制限とリクエストに似ています。この機能が導入される前は、ローカル ストレージを占める他の Pod が原因で Pod が削除されることがありました。これは、ローカル ストレージがベスト エフォートのリソースであるためです。

https://storage.googleapis.com/gweb-cloudblog-publish/images/Diagram2-emptyDir.max-2200x2200.jpg
図 2: kubelet が emptyDir ボリュームをコンテナにマウント

次に、ローカル SSD を基盤とする emptyDir ボリュームを使用する Pod の例を示します。ローカル ストレージ容量のリクエストと制限が構成されています。

読み込んでいます...

  • cloud.google.com/gke-ephemeral-storage-local-ssd: "true": Pod は、ローカル SSD を基盤とするローカル エフェメラル ストレージがあるノードにスケジュールされます。ノードラベルはクラスタの作成時に生成されます。

  • spec.containers[].resources.requests.ephemeral-storage:"200Gi": 使用可能なローカル エフェメラル ストレージ(割り当て可能リソース)に 200 GiB 以上の容量がある場合のみ、Pod をノードに割り当てることができます。

  • spec.containers[].resources.limits.ephemeral-storage:"300Gi": kubelet の Eviction Manager がすべてのコンテナ使用量と emptyDir の使用量の合計に占めるディスク使用量を測定し、ストレージの使用量が 300 GiB という制限を超えている場合に Pod を削除します。

  • spec.volumes[].emptyDir.sizeLimit:50Gi: Pod の emptyDir が 50 GiB 以上のローカル エフェメラル ストレージを使用していた場合、Pod がノードから削除されます。

例 2: ローカルの PersistentVolume でローカル NVMe SSD ブロック API を使用する

ここでも AI / ML アプリケーションの例を使用しますが、今回の Pod では同じデータセットに対して異なる ML モデルを実行します。データをローカル ストレージにダウンロードし、複数の Pod で同じデータにアクセスする必要があるとします。このシナリオでは、ローカル SSD がアタッチされた raw ブロックがあるノードプールをプロビジョニングし、DaemonSet を使用してディスクを RAID 構成にします。そして、ローカルの静的プロビジョナーを使用して、ノードレベルのキャッシュとして使用できるローカルの PersistentVolume をプロビジョニングします。

まず、ローカル SSD がアタッチされた raw ブロックがあるノードプールを作成します。このノードプールの作成には、gcloud CLI で --local-nvme-ssd-block count=<N> オプションを使用します。


読み込んでいます...

このコマンドは次のことを行います。

  • デフォルトのノードプールの各ノードに N 個のローカル SSD がアタッチされたクラスタを作成する。

  • ラベル cloud.google.com/gke-local-nvme-ssd=true を作成して各ノードに追加する。

  • ノードの初期化時に、ホスト OS が、順序パスにあるディスクにアクセスするシンボリック リンク(symlink)と Universally Unique Identifier(UUID)による symlink を作成する。この順序パスは、NVMe などの基盤となるストレージ インターフェースを公開しません。これを使用できるのは、アプリケーションがノードの修復またはアップグレード時のデータ削除を容認できる場合です。UUID symlink は、アプリケーションにデータの削除時に実行する必要がある特殊な復元機能がある場合に適しています。この例では前者を想定します。

https://storage.googleapis.com/gweb-cloudblog-publish/images/Diagram3-raw-block.max-2200x2200.jpg
図 3: NVMe を介してローカル SSD がアタッチされた N 個の raw ブロックがある GKE ノード

次に、DaemonSet を実行してローカル SSD を RAID 構成にします。こちらのを参照してください。この DaemonSet はすべてのローカル SSD に RAID0 アレイを設定し、デバイスを ext-4 ファイル システムにフォーマットします。ディスクを RAID 構成にした後で、こちらのサンプル yaml ファイルを使用して、ローカルの静的プロビジョナー DaemonSet を生成できます。この静的プロビジョナーは、RAID0 アレイ向けのローカル PersistentVolumes と対応する StorageClass を作成します。すべての処理を終えたら、PVCPod を作成してローカル PersistentVolumes を使用できます。コマンドについてはこちらを参照してください。

関連情報

GKE のローカル SSD の使い方について詳しくは、以下を参照してください。

- ソフトウェア エンジニア Danna Wang
- ソフトウェア エンジニア Jing Xu

投稿先