NVIDIA GPU Operatorは何をしてくれるのか

NVIDIA GPU Operatorは何をしてくれるのか

2025.12.18

オンプレミスやエッジ環境のKubernetesでGPUワークロードを動かす場合、「GPUをどう管理するか」が重要な技術課題になります。

本記事では、この課題を解決するNVIDIA GPU Operatorについて解説します。

従来のGPU管理の3つの問題点

問題1: 手動インストールの運用負荷

従来、GPUを使うには各ノードに対して以下の作業が必要でした。

  1. NVIDIA GPU ドライバのインストール
  2. NVIDIA Container Toolkitのインストール
  3. コンテナランタイム(containerd/Docker)の設定変更
  4. Kubernetes Device Pluginのデプロイ

ノードが10台、20台と増えると、この作業だけで数日を要することもあります。

問題2: バージョン依存の地獄

GPUソフトウェアスタックは相互依存が複雑です。

カーネルバージョン
    └─→ ドライババージョン
           └─→ CUDAバージョン
                  └─→ cuDNN/TensorRTバージョン
                         └─→ フレームワーク(PyTorch/TensorFlow)

OSをアップデートしたらドライバが動かなくなった、という経験をした方も多いのではないでしょうか。この「Matrix of Hell(依存関係地獄)」は、運用チームの大きな負担です。

問題3: 構成ドリフト

AnsibleやChefで初期構築しても、時間が経つにつれてノード間で設定が微妙にずれていく「構成ドリフト」が発生します。

  • あるノードだけドライバのバージョンが古い
  • 特定ノードでランタイム設定が上書きされている
  • 障害復旧時に手順書と実環境が乖離

こうした状況は、障害発生時の原因特定を困難にします。

GPU Operatorが解決すること

NVIDIA GPU Operatorは、これら3つの問題をKubernetesネイティブな方法で解決します。

Operatorパターンによる宣言的管理

GPU Operatorは、KubernetesのOperatorパターンを採用しています。

Operatorパターンとは、Custom Resource(CR)とカスタムコントローラーを組み合わせて、アプリケーション固有の運用知識をコード化する手法です。人間のオペレーターが行う「監視→判断→対処」のサイクルを自動化し、宣言された「あるべき状態」と「現在の状態」を常に比較して差分を解消します。

管理者が定義: 「GPUノードにはドライバv550とDevice Pluginが必要」
     ↓
ClusterPolicy CRDとして宣言
     ↓
Operatorが現在の状態を監視
     ↓
差分があれば自動で収束(Reconcile)

これにより、「あるべき状態」を定義するだけで、Operatorが自動的にその状態を維持します。

コンテナ化されたドライバ

GPU Operatorの特徴的なアプローチが、ドライバのコンテナ化です。

従来はホストOSに直接インストールしていたドライバを、特権コンテナとしてデプロイします。

メリット:

  • ホストOSを「イミュータブル(不変)」に保てる
  • ドライバのバージョン管理がKubernetesマニフェストで完結
  • ロールバックが容易

動作の仕組み:

  1. ドライバコンテナが起動
  2. ホストのカーネルバージョンを検出
  3. 対応するカーネルモジュール(nvidia.ko)をビルドまたはロード
  4. ホストの/dev/nvidia*デバイスが利用可能に

自動検出とラベリング

Node Feature Discovery(NFD)が、GPUを搭載したノードを自動で検出します。

# NFDが付与するラベル例
feature.node.kubernetes.io/pci-10de.present=true  # NVIDIA GPU検出
nvidia.com/gpu.product=Tesla-T4                    # GPUモデル
nvidia.com/cuda.driver.major=550                   # ドライババージョン

これにより、GPU Operatorは「このノードにGPUがある」と認識し、必要なコンポーネントだけを展開します。CPUオンリーのノードには何もデプロイされません。

GPU Operatorのコンポーネント構成

GPU Operatorは複数のマイクロサービスで構成されています。

各コンポーネントはDaemonSetとしてGPUノードにデプロイされ、独立してアップグレードやトラブルシューティングが可能です。

やってみた

今回は EC2インスタンス上にKubernetesの軽量ディストリビューションであるk3sのクラスターを作成(シングルノード構成)し、その上にCUDAのサンプルアプリケーションをデプロイしてみます。

NVIDIA GPU Operatorの価値を理解するために、使わない場合の手順・使う場合の手順を併記します。

まずは最初の数ステップ、これらはNVIDIA GPU Operatorを使う・使わない共通の手順です。

EC2インスタンスセットアップ

g5.xlargeインスタンスタイプのインスタンスを1台作成します。AMIは以下のCanonical社公式の Ubuntu 24.04のAMI(ami-0027415c74e0cd0ec)を使用します。

AMI.png

この後の手順は SSM Session Managerを使用して行います。そのためSession Managerを利用可能にするため、インスタンスに以下の設定を行ないます。

また、デフォルトの8GBでは後々エラーになるので、ルートEBSボリュームを30GBに増やします。

クラスターセットアップ

Session Managerでインスタンスに接続し、https://k3s.io/ 右上のインストールスクリプトを実行します。

curl -sfL https://get.k3s.io | sh - 

インストール成功を確認します。

% sudo k3s kubectl get node
NAME              STATUS   ROLES                  AGE   VERSION
ip-172-20-1-199   Ready    control-plane,master   5s    v1.33.6+k3s1

下記の通り Kubernetes のバージョンは 1.33です。

$ sudo kubectl version
Client Version: v1.33.6+k3s1
Kustomize Version: v5.6.0
Server Version: v1.33.6+k3s1

サンプルアプリケーションをデプロイして失敗することを確認

$ tee -a ~/gpu-test.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: gpu-test
spec:
  restartPolicy: OnFailure
  runtimeClassName: nvidia
  containers:
  - name: vectoradd
    image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0
    resources:
      limits:
        nvidia.com/gpu: 1
EOF

$ sudo kubectl apply -f ~/gpu-test.yaml
pod/gpu-test created
$ sudo kubectl get pod
NAME       READY   STATUS    RESTARTS   AGE
gpu-test   0/1     Pending   0          2m25s
$ sudo kubectl get event
LAST SEEN   TYPE      REASON                           OBJECT                 MESSAGE
89s         Warning   FailedScheduling                 pod/gpu-test           0/1 nodes are available: 1 Insufficient nvidia.com/gpu. preemption: 0/1 nodes are available: 1 No preemption victims found for incoming pod.

Podが立ち上がらないことが確認できました。

GPU Operatorを使わない場合の手順

GPU Operatorの価値を理解するために、使わない場合に必要な手順を見てみましょう。各GPUノードに対して以下の作業を手動で行う必要があります。

ハードウェア検出確認

NitroハイパーバイザーがPCIデバイスを正しく接続していることを確認します。

# PCIユーティリティの更新
$ sudo apt-get update && sudo apt-get install -y pciutils

# PCIバス上のNVIDIAデバイスを検査
$ lspci | grep -i nvidia
00:1e.0 3D controller: NVIDIA Corporation GA102GL [A10G] (rev a1)

カーネルヘッダーの同期

DKMSコンパイルを成功させるための唯一にして最も重要なステップは、カーネルヘッダーが実行中のカーネルと正確に一致することを確認することです。AWSでは、カーネルはしばしば最適化されています(linux-aws)。

# 特定のAWSカーネルバージョン用のヘッダーをインストール
$ sudo apt-get install -y linux-headers-$(uname -r) build-essential pkg-config libglvnd-dev

NVIDIA GPU ドライバのインストール

NVIDIAのリリースサイクルより遅れる可能性があるデフォルトのUbuntuアップストリームリポジトリは回避します。代わりに、公式のNVIDIA CUDAネットワークリポジトリを構成します。これにより、詳細なドライバーバージョン(例:550シリーズ)へのアクセスが可能になります。

cd ~

# 1. Ubuntu 24.04用のキーリングをダウンロード(G5向けにx86_64に焦点を当てる)
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb

# 2. キーリングをインストール
sudo dpkg -i cuda-keyring_1.1-1_all.deb

# 3. パッケージインデックスを更新
sudo apt-get update

550シリーズドライバーは、2025年初頭時点でのUbuntu 24.04推奨LTSブランチです。CUDA 12.4以降をサポートし、A10Gとの堅牢な互換性を提供します。

# ヘッドレスサーバー用ドライバーとユーティリティをインストール
sudo apt-get install -y nvidia-driver-550-server nvidia-utils-550-server

一時的なモジュールをアンロードし、新しいプロプライエタリモジュールをクリーンにロードするために、再起動します。

sudo reboot

再起動後、GPUが正しく認識されているか確認します。

$ nvidia-smi
Thu Dec 18 08:52:40 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 570.195.03             Driver Version: 570.195.03     CUDA Version: 12.8     |
|-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA A10G                    Off |   00000000:00:1E.0 Off |                    0 |
|  0%   31C    P0             61W /  300W |       0MiB /  23028MiB |     18%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|  No running processes found                                                             |
+-----------------------------------------------------------------------------------------+

Driver Versionが意図していたもの(550.xx.xx)と異なっているのが若干気がかりですが、このまま進めます!

NVIDIA Container Toolkitのインストール

ホスト上でドライバーがアクティブになったら、次の課題はホストのGPU機能と隔離されたコンテナ環境との間のギャップを埋めることです。これは、NVIDIA Container Toolkitおよび**コンテナランタイムインターフェース(CRI)**の領域です。まずはNVIDIA Container Toolkitです。

ツールキットは、libnvidia-container(ドライバーとの対話方法を知っているライブラリ)と nvidia-container-toolkit(ランタイムを構成するCLI)で構成されています。

# リポジトリのセットアップ
cd ~
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg

curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | sed 's#$(ARCH)#amd64#g' | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

sudo apt-get update

# インストール
sudo apt-get install -y nvidia-container-toolkit

# コンテナデバイスインターフェース(CDI)の構成
sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml

containerdの設定変更

次に、k3s内の組み込みcontainerdの構成について扱います。k3sが最終的な構成を生成するために使用するGoテンプレートファイルを作成する必要があります。

$ sudo tee -a /var/lib/rancher/k3s/agent/etc/containerd/config-v3.toml.tmpl <<EOF
{{ template "base" . }}

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes."nvidia"]
  runtime_type = "io.containerd.runc.v2"

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes."nvidia".options]
  BinaryName = "/usr/bin/nvidia-container-runtime"
  SystemdCgroup = true
EOF

再起動して構成の再生成を強制します。

% sudo systemctl restart k3s

crictl がランタイムを認識していることを検証します。

$ sudo crictl info | grep -A 5 "runtimes"

出力には有効なランタイムとして nvidia がリストされている必要があります。

RuntimeClassの定義

この段階で、ホストとコンテナランタイムはGPUを認識しています。しかし、Kubernetesスケジューラはまだ認識していません。RuntimeClassとDevice Pluginを使用して、CRIとスケジューラ間のギャップを埋める必要があります。

RuntimeClassリソースは、作成した nvidia ランタイム構成をエンドユーザーに公開するためのKubernetes APIオブジェクトです。

$ tee -a ~/nvidia-runtime.yaml <<EOF
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: nvidia
handler: nvidia
EOF

# 適用
$ sudo kubectl apply -f ~/nvidia-runtime.yaml

NVIDIA Device Pluginのデプロイ

NVIDIA Device Pluginは、すべてのノードで実行されるDaemonSetです。その役割は以下の通りです。

  1. ノード上のGPUデバイスを検出する。
  2. これらのデバイスを拡張リソース(nvidia.com/gpu)としてKubeletにアドバタイズする。
  3. スケジューリング時にデバイスをPodに割り当てる。
# Device PluginのDaemonSetのデプロイ
$ sudo kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.18.0/deployments/static/nvidia-device-plugin.yml

Device PluginのPodのStatusが Error ⇔ CrashLoopBackOffを行き来する状態になります。

Podのログを確認すると Incompatible strategy detected autoというエラーメッセージが出ています。
DaemonSetの設定を変更(環境変数追加)します。

$ sudo kubectl set env  daemonset/nvidia-device-plugin-daemonset -n kube-system DEVICE_DISCOVERY_STRATEGY=nvml

上記を適用すると、今度はエラーメッセージ Failed to initialize NVML: ERROR_LIBRARY_NOT_FOUNDが出力されます。Device Plugin のコンテナが、ホストOS上にあるNVIDIAドライバーのライブラリ(libnvidia-ml.so)を見つけられないことを意味しています。

これは、Device Plugin の Pod が標準のランタイム(runc) で起動してしまっていることが原因です。標準の runc は、ホストのドライバーファイルをコンテナ内に持ち込む(マウントする)機能を持っていません。

Device Plugin 自身にも、レポートの手順「4.1」で作成した RuntimeClass: nvidia を適用する必要があります。これにより、コンテナ起動時に NVIDIA Container Toolkit が介入し、必要なライブラリを注入してくれるようになります。

$ sudo kubectl patch daemonset nvidia-device-plugin-daemonset -n kube-system -p '{"spec":{"template":{"spec":{"runtimeClassName":"nvidia"}}}}'

動作確認

GPUリソースがノードに登録されているか確認します。

$ sudo kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.allocatable.nvidia\.com/gpu}{"\n"}{end}'
ip-172-20-1-50  1 # GPUコア数=1

サンプルアプリケーションの動作確認

NVIDIA Device PluginのPodのデプロイが成功したタイミングから、ずっと PendingだったサンプルアプリケーションのPodのステータスが、Pending → ContainerCreating → Running → Completedステータスに遷移します。

Podのログを確認し、以下のような出力になっていれば成功です。

$ sudo kubectl logs gpu-test
[Vector addition of 50000 elements]
Copy input data from the host memory to the CUDA device
CUDA kernel launch with 196 blocks of 256 threads
Copy output data from the CUDA device to the host memory
Test PASSED
Done

この手順の問題点

上記の手順には以下の問題があります。

  • ノードごとに実行が必要: 10台のノードがあれば10回実行
  • OSアップデート時の再作業: カーネル更新でドライバが動かなくなることがある
  • バージョン整合性の管理: コンテナが必要とするCUDAバージョンを満たすよう、ホスト側のドライバを常に最新に保つ運用負荷がかかる
  • 障害時の復旧: 手動で再インストールが必要

NVIDIA GPU Operatorを使えば、これらすべてがhelm installで完了します。

NVIDIA GPU Operatorを使用する場合

Helmコマンドのインストール

$ cd ~/
$ curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-4
$ chmod 700 get_helm.sh
$ ./get_helm.sh
[WARNING] Could not find git. It is required for plugin installation.
Downloading https://get.helm.sh/helm-v4.0.4-linux-amd64.tar.gz
Verifying checksum... Done.
Preparing to install helm into /usr/local/bin
helm installed into /usr/local/bin/helm

バージョン確認します。

$ helm version
version.BuildInfo{Version:"v4.0.4", GitCommit:"8650e1dad9e6ae38b41f60b712af9218a0d8cc11", GitTreeState:"clean", GoVersion:"go1.25.5", KubeClientVersion:"v1.34"}

Helmでのインストール

# NVIDIAのHelmリポジトリを追加
sudo helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
sudo helm repo update

# valuesファイルを作成
$ tee -a ~/gpu-operator-values.yaml <<EOF
toolkit:
  env:
    - name: CONTAINERD_CONFIG
      value: /var/lib/rancher/k3s/agent/etc/containerd/config.toml
    - name: CONTAINERD_SOCKET
      value: /run/k3s/containerd/containerd.sock
    - name: CONTAINERD_RUNTIME_CLASS
      value: nvidia
    - name: CONTAINERD_SET_AS_DEFAULT
      value: "true"
EOF

# gpu-operatorネームスペースにインストール
sudo KUBECONFIG=/etc/rancher/k3s/k3s.yaml \
helm install --wait gpu-operator \
    -n gpu-operator --create-namespace \
    nvidia/gpu-operator \
    -f ~/gpu-operator-values.yaml

--waitオプションにより、すべてのPodが起動するまでコマンドが待機します。

NVIDIA GPU Operatorの動作確認

# Podの状態を確認
$ sudo kubectl get pod -n gpu-operator
NAME                                                         READY   STATUS      RESTARTS      AGE
gpu-feature-discovery-8nm2n                                  1/1     Running     0             4m18s
gpu-operator-6b7854bc77-ddr9f                                1/1     Running     1 (96s ago)   4m46s
gpu-operator-node-feature-discovery-gc-74dd579c7f-vsf8v      1/1     Running     0             4m46s
gpu-operator-node-feature-discovery-master-948c8bb7c-lt2rq   1/1     Running     1 (97s ago)   4m46s
gpu-operator-node-feature-discovery-worker-q495w             1/1     Running     1 (98s ago)   4m46s
nvidia-container-toolkit-daemonset-xkzwd                     1/1     Running     0             4m18s
nvidia-cuda-validator-j7pnf                                  0/1     Completed   0             90s
nvidia-dcgm-exporter-qsxmt                                   1/1     Running     0             4m18s
nvidia-device-plugin-daemonset-5jlv4                         1/1     Running     0             4m18s
nvidia-driver-daemonset-th9jx                                1/1     Running     0             4m24s
nvidia-operator-validator-dgts2                              1/1     Running     0             4m18s

GPUリソースがノードに登録されているか確認します。

$ sudo kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.allocatable.nvidia\.com/gpu}{"\n"}{end}'
ip-172-20-1-199 1 # GPUコア数=1

サンプルアプリケーションの動作確認

NVIDIA GPU Operatorインストール前はずっとPendingだったサンプルアプリケーションのPodのステータスが、Pending → ContainerCreating → Running → Completedステータスに遷移します。

Podのログを確認し、以下のような出力になっていれば成功です。

$ sudo kubectl logs gpu-test
[Vector addition of 50000 elements]
Copy input data from the host memory to the CUDA device
CUDA kernel launch with 196 blocks of 256 threads
Copy output data from the CUDA device to the host memory
Test PASSED
Done

いかがでしょうか。NVIDIA GPU Operatorによって設定作業が大幅に簡略化されたこと、伝わりましたでしょうか。

まとめ

NVIDIA GPU Operatorは以下の価値を提供します。

  1. 運用の自動化: 手動作業からの解放
  2. 一貫性の確保: 構成ドリフトの防止
  3. 可観測性の向上: 標準化されたメトリクス収集

GPUを使ったAIワークロードをKubernetesで運用するなら、GPU Operatorは「あると便利」ではなく「必須のインフラ」と言えるでしょう。

最後に

実はこのブログは下記の「クラスメソッド発製造業アドベントカレンダー」の18日目のエントリーです。

https://adventar.org/calendars/11760

ここまで製造業との関連について何もお伝えしていませんが、製造業においてもAIを活用するシナリオは増え続けています。

ユースケース 処理内容 GPU要件
外観検査 製品画像の良品/不良品分類 推論用GPU(リアルタイム性重視)
異常検知 センサーデータの時系列分析 中程度の演算能力
予知保全 設備故障の予兆検知 バッチ処理可能ならCPUでも可
生成AI活用 マニュアル検索、作業支援 大規模GPU(LLM推論)

しかし、本格的な導入を検討する際、以下のような要件が壁となるケースが少なくありません。

  • セキュリティ: 工場内の秘匿データを外部クラウドへ送信できない
  • 低遅延(レイテンシ): 生産ラインを止めないためのリアルタイム性が必須
  • コスト最適化: クラウドの従量課金によるランニングコスト増大を避けたい

これらの要件を満たすには、クラウド上のAPIを利用するだけでなく、工場内ネットワーク(オンプレミス/エッジ)にGPUサーバーを設置し、自社でモデルを運用するアプローチが必要です。

ここで課題となるのが、貴重なGPUリソースの管理です。リソース効率の観点からは、Kubernetesクラスタ上でコンテナとしてAIモデルを運用手法が推奨されますが、インフラ構築の難易度は高くなりがちです。そこで役立つのが 「NVIDIA GPU Operator」 です。GPUインフラの管理を「自動化・抽象化・標準化」することで、運用の複雑さを解消し、現場へのAI導入を強力に支援します。

参考資料

この記事をシェアする

FacebookHatena blogX

関連記事