- はじめに — コンテナのGPU、VMのGPU
- 第1部 — GPU Operator: コンポーネント・設定・バージョン
- 第2部 — 一部のGPUだけにMIGを適用する
- 第3部 — MIGの手動適用: nvidia-smiで直接操作する
- 第4部 — KubeVirt: コンポーネント・設定・バージョン
- 第5部 — 二つの世界の接続: GPU Operator × KubeVirt
- おわりに
- 参考資料
はじめに — コンテナのGPU、VMのGPU
Kubernetes上のGPUインフラは二つの世界に分かれます。コンテナにGPUを差し込む世界(GPU Operator)と、Kubernetes上で仮想マシンを動かしてGPUを丸ごと渡す世界(KubeVirt)です。面白いのは、この二つが最終的に一つのスタックで出会うという点です — GPU OperatorはKubeVirt VM向けのGPUプロビジョニングまで担当します。本記事では両方の柱のコンポーネント・設定・バージョンを総整理し、よく聞かれる二つのテーマ — 一部のGPUだけへのMIG適用とMIGの手動操作 — を実践コマンドで扱います。GPU OperatorインストールとMIG基礎編を先に読んでおくと、この記事は二倍わかりやすくなります。
第1部 — GPU Operator: コンポーネント・設定・バージョン
コンポーネント (オペランド)
GPU Operatorは「GPUノードに必要なものすべて」をDaemonSetのオペランドとしてデプロイし、一つのClusterPolicyで調整するオペレーターです。
オペランド 役割
───────────────────────── ─────────────────────────────────────
driver NVIDIAドライバーをコンテナとしてロード
container-toolkit ランタイムがGPUをコンテナに公開するよう設定
device-plugin nvidia.com/gpuリソースをスケジューラーに広告
gpu-feature-discovery GPUモデル・メモリ・MIG状態をノードラベルに
dcgm-exporter 使用率・温度・電力をPrometheusメトリクスに
mig-manager ノードラベルベースのMIGパーティショニング
node-feature-discovery ハードウェア検出 (依存コンポーネント)
validator 各段階の検証ジョブ
(sandbox系) vfio-manager, vgpu-device-manager,
kubevirt-gpu-device-plugin — 第5部にて
設定 — ClusterPolicyが単一の真実
すべてのオペランドの設定は clusterpolicies.nvidia.com/cluster-policy という一つのCRに集約されます。Helmの --set は、結局このCRのフィールドを埋めるものです。実務でよく触るフィールド:
# ClusterPolicyの主要フィールド (抜粋)
spec:
driver:
enabled: true # ノードに既にドライバーがあればfalse
version: "580.65.06" # ドライバーバージョンを固定
toolkit:
enabled: true
mig:
strategy: mixed # single | mixed
migManager:
enabled: true
config:
name: custom-mig-config # カスタムMIGプロファイルのConfigMap
env:
- name: WITH_REBOOT # CSPのように再起動が必要な環境
value: "true"
devicePlugin:
config:
name: time-slicing-config # タイムスライシング設定もConfigMapで
sandboxWorkloads:
enabled: false # KubeVirt連携時はtrue (第5部)
変更はHelmアップグレードまたは kubectl patch clusterpolicies... で行い、オペレーターが変更を検知して該当するオペランドだけを再構成します。
バージョン体系
GPU Operatorは年ベースのバージョン(vYY.N.パッチ)を採用しています — 本記事執筆時点の最新系列はv26.x(例: v26.3.3)で、その前にはv25.x、v24.9、v23.9の系列があります。各リリースがサポートするドライバーバージョンのセットとKubernetesバージョンの範囲はドキュメントに明記されているため、アップグレード前の互換性マトリクスの確認は必須です。覚えておくべき原則: オペレーターのバージョンがドライバーのバージョンを管理するので、ドライバーだけを個別に上げたい場合はClusterPolicyの driver.version を使うのが定石です。
第2部 — 一部のGPUだけにMIGを適用する
GPUを8枚積んだノードで「0番GPUだけを細かく分割して推論用に、残りの7枚は丸ごと学習用に」という要件は非常によくあります。答えはmixed戦略 + カスタムMIG設定です。
apiVersion: v1
kind: ConfigMap
metadata:
name: custom-mig-config
namespace: gpu-operator
data:
config.yaml: |
version: v1
mig-configs:
# 0番GPUだけMIG、1〜7番はそのまま
partial-mig:
- devices: [0]
mig-enabled: true
mig-devices:
"1g.10gb": 4
"3g.40gb": 1
- devices: [1, 2, 3, 4, 5, 6, 7]
mig-enabled: false
# ① ClusterPolicyがこのConfigMapを参照するよう指定 (設定済みなら省略)
kubectl patch clusterpolicies.nvidia.com/cluster-policy --type='json' \
-p='[{"op":"replace","path":"/spec/migManager/config/name","value":"custom-mig-config"}]'
# ② 戦略がmixedであることを確認 — プロファイルが混在するためsingleでは表現できない
kubectl patch clusterpolicies.nvidia.com/cluster-policy --type='json' \
-p='[{"op":"replace","path":"/spec/mig/strategy","value":"mixed"}]'
# ③ ノードにプロファイルを適用
kubectl label nodes <ノード> nvidia.com/mig.config=partial-mig --overwrite
# ④ 結果: リソースは次のように広告されます
# nvidia.com/gpu: 7 ← MIGしていない7枚
# nvidia.com/mig-1g.10gb: 4 ← 0番から切り出された断片
# nvidia.com/mig-3g.40gb: 1
Podは用途に応じて nvidia.com/gpu(丸ごと)または nvidia.com/mig-1g.10gb(断片)をリクエストするだけです。核心ルールは二つ — プロファイルがGPU間で異なる場合は必ずmixed戦略でなければならないこと、そして devices リストに載っていないGPUの挙動を明示するには mig-enabled: false のエントリを必ず併記すること(暗黙の状態に任せないでください)。
第3部 — MIGの手動適用: nvidia-smiで直接操作する
Kubernetesの外のベアメタルサーバーや、mig-managerを使わない環境では、nvidia-smi mig で直接パーティショニングします。GPU Operatorが内部で行っているのはまさにこれなので、一度手を動かしてみると、オペレーターをデバッグする力も一緒に鍛えられます。
# ① MIGモードを有効化 (GPU 0番のみ) — 先に対象GPUのプロセスを空けておく必要あり
sudo nvidia-smi -i 0 -mig 1
# "Pending" と表示されたらGPUリセットまたは再起動が必要:
sudo nvidia-smi --gpu-reset -i 0
# ② 作成できるGPUインスタンス(GI)のプロファイルを確認
nvidia-smi mig -lgip
# 例: H100 80GB → 1g.10gb(ID 19), 2g.20gb(14), 3g.40gb(9), 7g.80gb(0) ...
# ③ GIを作成 — 3g.40gbを1個 + 1g.10gbを4個、-C はコンピュートインスタンス(CI)まで自動作成
sudo nvidia-smi mig -i 0 -cgi 9,19,19,19,19 -C
# ④ 確認
nvidia-smi mig -lgi # 作成されたGIの一覧
nvidia-smi -L # MIGデバイスのUUID一覧 (MIG-xxxx形式)
# ⑤ 特定のインスタンスで実行 — UUIDで指定
CUDA_VISIBLE_DEVICES=MIG-<uuid> python infer.py
# ⑥ 解除 — CI → GI の順に削除してからMIGモードを無効化
sudo nvidia-smi mig -i 0 -dci && sudo nvidia-smi mig -i 0 -dgi
sudo nvidia-smi -i 0 -mig 0
押さえておきたい概念: MIGは GI(GPU Instance — メモリ・SMのハードウェア分割) の中に CI(Compute Instance — SMの再分割) が入る2段構造です。ほとんどの場合はGIごとにCI一つ(-C オプション)で十分で、CIをさらに分割するのは、同じメモリパーティションを共有しながら演算だけを分けたい特殊なケースです。また、②のプロファイルIDはGPUモデルごとに異なるため、必ず先に -lgip で確認してください。
第4部 — KubeVirt: コンポーネント・設定・バージョン
なぜKubernetesでVMなのか
コンテナに移せないワークロードは意外と多いものです — カーネルモジュールが必要なレガシー、Windowsゲスト、強い分離が求められるマルチテナントGPU環境。KubeVirtはVMをKubernetesの一級市民(CRD)にすることで、PodとVMを同じクラスター・同じネットワーク・同じkubectlで扱えるようにします。
4大コンポーネント
コンポーネント 形態 役割
────────────── ─────────── ─────────────────────────────────────
virt-operator Deployment KubeVirt自体のインストール・アップグレード管理
virt-controller Deployment クラスターレベルのVMライフサイクル (VMI作成など)
virt-handler DaemonSet ノードレベルのデーモン — VMIスペックとlibvirtドメインを同期
virt-launcher Pod(VMごと1) VMを包むPod — 内部のlibvirtdがQEMU/KVMを起動
流れは次のとおりです: ユーザーが VirtualMachine CRを作成すると → virt-controllerが VirtualMachineInstance(VMI)とvirt-launcher Podを作成し → 該当ノードのvirt-handlerがVMIスペックをlibvirtドメインに翻訳し → virt-launcher内のlibvirtdがQEMU/KVMプロセスを起動します。VMはまさにPodの中のプロセスなので、Kubernetesのネットワーキング・スケジューリングがそのまま適用されます。ディスクイメージの取り込みは、別プロジェクトの CDI(Containerized Data Importer) がDataVolume CRDで担当します。
設定 — KubeVirt CRとfeatureGates
KubeVirtのグローバル設定も一つのCR(kubevirt.io/v1 の KubeVirt)に集約されます。GPUパススルーに必要な核心設定:
apiVersion: kubevirt.io/v1
kind: KubeVirt
metadata:
name: kubevirt
namespace: kubevirt
spec:
configuration:
developerConfiguration:
featureGates:
- GPU # VMへのGPU割り当てを許可
- HostDevices
permittedHostDevices: # どのホストデバイスをVMに渡せるか
pciHostDevices:
- pciVendorSelector: "10de:2331" # NVIDIA H100 (vendor:device)
resourceName: "nvidia.com/GH100_H100_PCIE"
externalResourceProvider: true # GPU Operatorのプラグインが広告
バージョンの特徴
KubeVirtは2023年にv1.0でプロダクション対応を宣言し、以降は四半期ごとのマイナーリリース(v1.1、v1.2、…)でv1.x系を継続しています。CNCFのインキュベーティングプロジェクトであり、リリースごとにサポートするKubernetesバージョンの範囲が明記されます(おおむね最新のK8s 3バージョン)。体感できる変化の軸は、instancetype/preference APIの成熟(VMサイズをTシャツサイズのように宣言)、メモリホットプラグ・CPUホットプラグといったライブリソース調整、そしてライブマイグレーションの堅牢化です。GPUをパススルーしたVMは、デバイスがノードに物理的に固定されるためライブマイグレーションができないという制約があります — これはバージョンとは無関係な物理法則として覚えておいてください。
第5部 — 二つの世界の接続: GPU Operator × KubeVirt
GPU Operatorを sandboxWorkloads.enabled=true でインストールすると、VM向けのGPUプロビジョニングまで担当するようになります。
helm install --wait gpu-operator \
-n gpu-operator --create-namespace \
nvidia/gpu-operator --version=v26.3.3 \
--set sandboxWorkloads.enabled=true
このとき、ノードラベル nvidia.com/gpu.workload.config がスイッチになります:
値 ノードの用途 デプロイされるオペランド
────────────── ──────────────────── ─────────────────────────────
container 通常のGPUコンテナ driver, device-plugin, ... (第1部の構成)
vm-passthrough VMにGPUを丸ごと vfio-manager (vfio-pciバインド),
kubevirt-gpu-device-plugin
vm-vgpu VMにvGPUの断片 vgpu-manager, vgpu-device-manager
パススルーノードでは、vfio-managerが(ホストドライバーの代わりに)GPUを vfio-pci ドライバーにバインドし、kubevirt-gpu-device-pluginがそのデバイスを nvidia.com/GH100_H100_PCIE のようなリソースとして広告します。VMスペックでは次のようにリクエストします:
# VirtualMachineスペック抜粋
spec:
template:
spec:
domain:
devices:
gpus:
- deviceName: nvidia.com/GH100_H100_PCIE
name: gpu1
まとめると — 同じクラスターでラベルを変えるだけで、あるノードはコンテナGPU、あるノードはVMパススルー、あるノードはvGPUとして運用できます。強い分離(セキュリティ・ドライバーの自由度)が必要ならVMパススルー、密度が必要ならコンテナ + MIG、その中間がvGPU、という感覚で選ぶとよいでしょう。
おわりに
GPU Operatorは一つのClusterPolicyでオペランドの艦隊を指揮し、KubeVirtは4つのコンポーネントでVMをPodの世界に編入し、両者はsandboxWorkloadsとworkload.configラベルで出会います。部分MIGはmixed戦略 + devicesリストで、手動MIGは nvidia-smi mig -cgi/-dgi で — オペレーターが自動化してくれている仕事の正体を知れば、障害が起きたときにどこを見ればよいかも見えてきます。Kubernetesの基礎感覚はKubernetesプレイグラウンドとKubestronautクイズで鍛えられます。
参考資料
현재 단락 (1/127)
Kubernetes上のGPUインフラは二つの世界に分かれます。コンテナにGPUを差し込む世界(GPU Operator)と、Kubernetes上で**仮想マシン**を動かしてGPUを丸ごと渡す世界...