なぜGPU Operatorが生まれたのか
一言でいうと
GPU OperatorはGPUを速くしてくれる製品ではありません。ノードごとに手作業で行っていた5、6種類のインストールを、クラスターオブジェクト1枚に移したものであり、その便利さの代償として、ノードのコンテナランタイムの設定をオペレーターが代わりに書き換えることになります。
なぜ必要なのか
GPUノード1台を「使える状態」にする手順は、以前はこうでした。
- カーネルヘッダーを合わせてインストールし、ドライバーをビルドして読み込みます。失敗したら、カーネルのバージョンから見直します。
nvidia-container-toolkitをインストールします。- containerdの設定に、
nvidiaランタイムハンドラーを登録します。 - containerdを再起動します。
nvidia-device-pluginを起動して、GPUをリソースとしてアドバタイズさせます。dcgm-exporterを起動して、使用率を収集します。
ノード1台に30分かかり、7台なら1日が終わります。問題は時間ではなく、ドリフトです。3月に作ったノードはドライバー535、8月に追加したノードは550です。カーネルの自動更新が走ると、そのノードだけドライバーが壊れます。人が繰り返す手順は必ずばらつき、ばらついたクラスターは「なぜあのノードだけ動かないのか」という質問を毎週生みます。
GPU Operatorは、この手順を丸ごと望ましい状態の宣言に置き換えます。ClusterPolicyというカスタムリソースを1枚書くと、オペレーターが必要なDaemonSetを立ち上げ、ノードが新しく入ってくれば、自動で同じ手順を実行します。ノードを作り直しても結果が同じになること。それがこのオペレーターが売る唯一の商品です。
どう動くのか
ClusterPolicy1つの下に、複数のDaemonSetが立ち上がります。それぞれが、上の手順の1段階を受け持ちます。
| DaemonSet | 役割 | ない場合に起きる症状 |
|---|---|---|
nvidia-driver-daemonset |
ドライバーをコンテナ内でビルドして読み込みます | nvidia-smi自体がありません |
nvidia-container-toolkit-daemonset |
ノードのcontainerdの設定に、ランタイムハンドラーを登録します | PodがRuntimeHandlerエラーで作成に失敗します |
nvidia-device-plugin-daemonset |
ノードのstatusにnvidia.com/gpuをアドバタイズします |
PodがいつまでもPendingになります |
gpu-feature-discovery |
GPUのモデルとメモリをノードのラベルにします | スケジューリング条件をラベルで書けません |
nvidia-dcgm-exporter |
使用率・温度・ECCのメトリクスを公開します | 誰がGPUを使っているのかわかりません |
ここには、順序の依存があります。ドライバーの準備ができる前にtoolkitが起動しても意味がなく、toolkitがランタイムを登録する前にdevice pluginがGPUをアドバタイズすると、スケジューラーはPodを送ってくるのに、ノードはそのPodを作れません。そのためオペレーターは、ノードのラベル(nvidia.com/gpu.deploy.*)で各段階をゲーティングします。人が順序を覚えていなくてもよいようにした仕組みです。
そしてここで、必ず押さえておくべき事実が1つあります。2つ目のDaemonSetは、ノードの/etc/containerd/を直接書き換えます。クラスター内のオブジェクトを作るのではなく、ホストのファイルシステムに書き込みます。このコースの残り半分は、すべてこの一文から出てきた話です。
現場での姿
第一に、ドライバーはたいていノードに事前にインストールします。driver.enabled=falseにして、OSイメージにドライバーを焼き込んでおく組織が多くあります。コンテナ内でドライバーをビルドする方式は、カーネルが更新されるたびに、ノードが数分間GPUなしで動く区間を作りますし、エアギャップ環境ではヘッダーパッケージの取得から行き詰まります。そうなると、GPU Operatorが行う作業は、実質的に「toolkit + device plugin + メトリクス」の3つに減ります。
第二に、バージョンマトリクスが本当の制約です。ドライバー・CUDA・toolkit・オペレーター・Kubernetesが、それぞれ互いのサポート範囲を持っています。オペレーターを更新することは、その5つを一度に動かすことなので、他のアップグレードと同じ作業ウィンドウに入れると、原因を切り分けられません。
第三に、監査の観点では、このオペレーターは特権ソフトウェアです。ノードのファイルシステムに書き込み、ホストのPIDネームスペースを見て、カーネルモジュールを読み込みます。「Kubernetesの上で動くPodだから分離されている」という直感は、ここでは通用しません。インストールを承認するときにこの事実を文書に残しておかないと、あとで必ず問題になります。
続く記事で見ること
すぐ次の記事では、ClusterPolicyの下のDaemonSetが、RuntimeClassとnvidia.com/gpuリソースにどうつながるのかを見ます。この2つの流れはまったく別のゲートであり、両者を取り違えると、「PodがPendingなのに原因が見つからない」状態にそのまま陥ります。