こんにちは。サイオステクノロジーの塙です。
今回はKubernetes をベースとしたプラットフォームでGPUを扱っていくための手法について解説してみます。
概要
直近では特にAIや機械学習(ML)に関する話題が増え、これらの分野を活用したソリューションの実現を図る組織も多いのではないでしょうか。
これらの分野の計算リソースのためには、GPUが必要となってきます。
そして、GPUリソースを効率的に使用するために、Kubernetes と組み合わせてGPUを管理し、コストの削減と効率化が期待出来ます。
- コンテナ環境を利用することで、機械学習(ML)のための複雑な環境を何度も同じようにセットアップすることができる
- kubernets のスケジューリングにより、リソースの利用率の効率化をすることができる
では、KubernetesでGPUを扱うためにはどんな準備が必要となるのかを説明していきます。
KubernetesでのGPUの使用
Kubernetes でのGPUスケジューリング*1 を有効にするためには、デバイスプラグインを使用します。
デバイスプラグインは、特定のハードウェアのリソースを管理するためのgRPCサービスとなります。Kubelet がデバイスプラグインと連携することでGPUをコンテナに割り当てることが可能になります。
デバイスプラグインについての詳細は以下をご参考下さい。
*1 GPU スケジューリング:
複数のプロセスが同時に実行されるGPUのリソースを効率的に管理するためのプロセスです。
これは、タスクの優先順位付けや、タスクのリソース割り当てなどを行い、GPUリソースの使用率を高め全体的なパフォーマンスを向上させることに繋がります。
GPUスケジューリングは、特に並列計算が求められるAIや機械学習(ML)向けアプリケーションで重要な機能となっている。
具体的にKubernetesでGPUを使用するために以下の対応が必要です。(ここでは、NVIDIAを例にしてます)
- 対応するベンダーのGPUドライバーをノードにインストールする
- 前提として、gcc と 正しいカーネルバージョンのインストールが必要です
詳細は、NVIDIA CUDA Installation Guide for Linux を参照
- 前提として、gcc と 正しいカーネルバージョンのインストールが必要です
- Kubernetes でデバイスプラグインをインストールする
- Kubernetes からyamlファイルでデプロイします
- 詳細は、https://github.com/NVIDIA/k8s-device-plugin?tab=readme-ov-file#example-for-debian-based-systems- with-docker-and-containerd を参照
■ Kubernetes のオブジェクトからの使用方法
デバイスプラグインまでインストールを行った後、従来のCPU/メモリをリクエストするのと同様に、カスタムGPUリソースをリクエストすることで、Pod から GPUを使用することが可能になります。
apiVersion: v1
kind: Pod
metadata:
name: test-gpu-pod
spec:
restartPolicy: OnFailure
containers:
- name: test-gpu-container
image: registry.example/example/example:v10.2
resources:
limits:
nvidia.com/gpu: 1 # requesting 1 GPU
Kubernetesでのデバイスプラグインの制限について
Kubernetes の Schedule GPUs 、Device Plugins を参照すると、以下のような制限が記載されています。
- コンテナ間でGPUを共有することは出来ない
- 拡張リソースはオーバーコミットすることは出来ない
- マニフェスト定義でresources.limits を指定する形式である
- resources.request を指定する時は、resources.limits と同じにする必要がある
GPUリソースを指定する時には上記の制限に注意したいところですが、特に気になったものは コンテナ間でGPUを共有することは出来ない
という制限です。
Kubernetes上のコンテナとして扱うからには、AIや機械学習(ML)向けアプリケーションのワークロードを分割して実行したいと思います。ただし、この制限があるとその分GPUを搭載する必要が出てきてしまいます。
単体だけでもコストのかかるGPUを、コンテナ数分用意するとなると非常に高価になってしまいます。
そのため、NVIDIAや他のベンダーが、Kubernetesのコードをベースとしたソリューションを実装して、GPUリソースの共有を提供できる形にしています。
GPUへの共有アクセス
NVIDIA のデバイスプラグインを例に、GPUへの共有アクセスを提供している機能を記載します。
下記、Time-Slicing と MPS は相互に排他的となります。
■ Time-Slicing
タイムスライシングスケジューラを活用して、複数のCUDAプロセスを同時に実行します。
GPUは一定間隔でCUDAプロセスを切り替えることによって複数プロセスの共有が可能となります。
GPUのレプリカセットを定義することができ、各レプリカをPodにリソースとして提供することが出来ます。
version: v1
sharing:
timeSlicing:
resources:
- name: nvidia.com/gpu
replicas: 4 # 単一のGPUを4つのレプリカとして提供する
設定した後は、GPUリソースに.sharedが付与されるので、それをGPUリソースとして利用します。
apiVersion: v1
kind: Pod
metadata:
name: test-gpu-pod
spec:
restartPolicy: OnFailure
containers:
- name: test-gpu-container
image: registry.example/example/example:v10.2
resources:
limits:
nvidia.com/gpu.shared: 1 # requesting 1 GPU
注意点としては以下があります。
- 複数のGPUをリクエストしても、比例して計算能力が向上することが保証されない
- プロセス間の切り替え時にオーバーヘッドが発生する
- メモリ制限は考慮されていない。1つのプロセスが異常終了すると、他のプロセスも影響して終了する
- GPUを共有して使用しているため
■ MPS (Multi Process Service)
こちらも、複数のCUDAプロセスが単一のGPUを共有出来るようにする機能です。制御を行うdaemon を使用して、アクセスを管理します。
Time-Slicing のデメリットであるオーバーヘッドを排除しています。
各プロセスに独自のメモリアドレス空間を提供することにより、プロセスにメモリの制限を適用することが出来ます。
注意点としては以下があります。
- プロセスを完全分離させているわけではないため、メモリの保護の提供はされていない
- あるプロセスが異常終了した場合に、他のプロセスに影響を与える可能性があります
参考 https://docs.nvidia.com/deploy/mps/index.html
■ MIG (Multi Instance GPU)
単一の物理的なGPUを複数の独立したGPUインスタンスに分割することが出来る機能です。
利用可能なGPUとしては、Ampere, Hpper などがあります。
注意点としては以下があります。
- 各GPUのモデルによって、特定のMIGプロファイルをサポートするため、柔軟なカスタムを行うことは出来ない
参考 Supported MIG Profiles
まとめ
今回は、Kubernetes でGPUを扱っていくための手法についてまとめてみました。
今やクラウドベースでGPU搭載のインスタンスを使用してKubernetes を構築出来るようですが、その前提となっている技術等について改めて簡単に整理してみると面白いです。
次回は、実際の構築例を試してみて所感を記載していこうと思います。
本書の記載が読者のお役に立てれば幸いです。