CDIスペックを書く
目標
CDI(Container Device Interface)のスペックを自分で作成し、文法と配置を検証して、podman run --deviceの引数の形式を正確に書きます。
なぜ重要なのか
CDIは、「このデバイスをコンテナに入れるには、どんなデバイスノード・ライブラリ・環境変数が必要か」を記述する、ベンダー中立の標準です。以前のランタイムフック方式よりも透明で、移植性が高く、podman・containerd・CRI-Oのすべてがサポートしています。実務では、nvidia-ctk cdi generateが自動的に作成してくれますが、ドライバーの更新後にGPUが認識されない事故の原因は、ほとんどがスペックの再生成漏れなので、その内容を読めるようになっておく必要があります。
この環境には、実際のGPUがありません。そのため、スペックの文法・構造・配置と、--device引数の形式を採点します。現場でミスが出る場所が、まさにそこです。
ステップ
/etc/cdiディレクトリを作成してください。そして、/root/cdi作業ディレクトリも作成してください。/etc/cdi/nvidia.yamlを作成してください。最上位にcdiVersion: "0.6.0"とkind: nvidia.com/gpuがある必要があり、devices配列にname: "0"の項目が1つある必要があります。その項目のcontainerEdits.deviceNodesには、/dev/nvidia0、/dev/nvidiactl、/dev/nvidia-uvmの3つのパスが入る必要があります。- そのファイルをYAMLとしてパースして、最上位のキーの一覧を
/root/cdi/parsed.txtに保存してください。cdiVersion、kind、devicesの3つのキーがすべて見える必要があります。 devices配列に、name: "all"の2つ目の項目を追加してください。その項目のdeviceNodesにも、最低2つのパスがある必要があります。name: "0"の項目のcontainerEditsに、mountsを追加してください。hostPathとcontainerPathが両方とも/usr/lib/x86_64-linux-gnu/libnvidia-ml.so.550.90.07で、optionsにはro、nosuid、nodev、bindの4つの値が入る必要があります。name: "0"の項目のcontainerEditsに、hooksを追加してください。hookNameはcreateContainer、pathは/usr/bin/nvidia-ctk、argsは["nvidia-ctk", "hook", "update-ldcache"]です。/root/cdi/run.shを作成してください。podman runでnvidia.com/gpu=allデバイスをリクエストするコマンドが入っている必要があります。--device引数の値の形式が、正確である必要があります。/root/cdi/report.txtを、次の5行で作成してください。値は、作成したスペックをパースして得る必要があります。CDI_VERSION=0.6.0/KIND=nvidia.com/gpu/DEVICES=<devices 배열 길이>/NODES_DEV0=<name 이 "0" 인 장치의 deviceNodes 개수>/SPEC_PATH=/etc/cdi/nvidia.yaml(プレースホルダーは、順に、devices配列の長さ、nameが"0"のデバイスのdeviceNodesの数です)
参考
- YAMLのパースは、
python3 -c "import yaml,sys;d=yaml.safe_load(open('/etc/cdi/nvidia.yaml'));print(list(d))"の形で行います。 --deviceの値の形式は、<kind>=<장치이름>です(プレースホルダーはデバイス名です)。- 実際の環境では、
nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yamlが、このファイルを作成してくれます。 - よくある間違い1:
kindをnvidia/gpuのように書くこと。ベンダーの部分は、ドメイン形式(nvidia.com)である必要があります。 - よくある間違い2: デバイス名
"0"を、引用符なしで書いて、YAMLが数値としてパースしてしまうこと。文字列である必要があります。
CDIディレクトリを準備する
/etc/cdiディレクトリを作成してください。そして、/root/cdi作業ディレクトリも作成してください。
標準のパスは2か所です。永続的なスペックが置かれるほうを使ってください。
最小限のスペックを作成する
/etc/cdi/nvidia.yamlを作成してください。最上位にcdiVersion: "0.6.0"とkind: nvidia.com/gpuがある必要があり、devices配列にname: "0"の項目が1つある必要があります。その項目のcontainerEdits.deviceNodesには、/dev/nvidia0、/dev/nvidiactl、/dev/nvidia-uvmの3つのパスが入る必要があります。
最上位に、2つのキーとdevices配列が必要です。kindは、ドメイン形式のベンダーとクラスを、スラッシュでつなぎます。
YAMLの文法を検証する
そのファイルをYAMLとしてパースして、最上位のキーの一覧を/root/cdi/parsed.txtに保存してください。cdiVersion、kind、devicesの3つのキーがすべて見える必要があります。
python3のyamlモジュールで読んでみれば、文法エラーがすぐに表面化します。パース結果を要約して保存してください。
2つ目のデバイスを追加する
devices配列に、name: "all"の2つ目の項目を追加してください。その項目のdeviceNodesにも、最低2つのパスがある必要があります。
allは、慣例的にすべてのデバイスを意味する名前です。devices配列に、項目をもう1つ入れてください。
ライブラリのマウントを追加する
name: "0"の項目のcontainerEditsに、mountsを追加してください。hostPathとcontainerPathが両方とも/usr/lib/x86_64-linux-gnu/libnvidia-ml.so.550.90.07で、optionsにはro、nosuid、nodev、bindの4つの値が入る必要があります。
mountsの項目は、hostPath、containerPath、optionsの3つのキーを持ちます。optionsは、文字列の配列です。
フックを追加する
name: "0"の項目のcontainerEditsに、hooksを追加してください。hookNameはcreateContainer、pathは/usr/bin/nvidia-ctk、argsは["nvidia-ctk", "hook", "update-ldcache"]です。
hooksの項目には、hookName、path、argsが入ります。コンテナ作成時点のフック名を書いてください。
実行コマンドを作成する
/root/cdi/run.shを作成してください。podman runでnvidia.com/gpu=allデバイスをリクエストするコマンドが入っている必要があります。--device引数の値の形式が、正確である必要があります。
--deviceの値は、kindとデバイス名を等号でつないだ形式です。スクリプトとして残してください。
スペックの検証レポートを作成する
/root/cdi/report.txtを、次の5行で作成してください。値は、作成したスペックをパースして得る必要があります。
CDI_VERSION=0.6.0 / KIND=nvidia.com/gpu / DEVICES=<devices 배열 길이> / NODES_DEV0=<name 이 "0" 인 장치의 deviceNodes 개수> / SPEC_PATH=/etc/cdi/nvidia.yaml(プレースホルダーは、順に、devices配列の長さ、nameが"0"のデバイスのdeviceNodesの数です)
値は、実際に作成したスペックをパースして得る必要があります。個数は、配列の長さです。