問題の概要:Dockerコンテナ内でGPUが認識されない
AI開発や機械学習の環境構築において、Dockerコンテナ内でNVIDIA GPUを利用しようとすると、以下のようなエラーに遭遇することがあります。特に、NVIDIA Container Toolkit(旧称:nvidia-docker2)のインストール後や、Dockerコンテナの起動時に発生します。
# 代表的なエラーメッセージ例
docker: Error response from daemon: could not select device driver "" with capabilities: [[gpu]].
# コンテナ内で`nvidia-smi`を実行した場合のエラー
nvidia-container-cli: initialization error: driver error: failed to process request
# システムログ(`journalctl -xe`や`dmesg`)で確認できるカーネル関連のエラー
Could not load UVM kernel module. Failed to initialize NVML: Unknown Error
これらのエラーが発生すると、コンテナ内からGPUリソースを利用した計算(例:TensorFlow, PyTorchでの学習や推論)が実行できず、AI開発ワークフローが停止してしまいます。本記事では、この問題の原因と、NVIDIA Container Toolkitを正しくインストール・設定してDockerコンテナにGPUをパススルーする方法をステップバイステップで解説します。
原因の解説
DockerコンテナがホストマシンのGPUを認識できない主な原因は、以下の3つに大別されます。
1. NVIDIA Container Toolkitが未インストールまたは設定不備
標準のDockerエンジンは、GPUのような特殊なハードウェアリソースをコンテナに直接割り当てる機能を備えていません。NVIDIA Container Toolkitは、DockerランタイムとNVIDIA GPUドライバーを連携させるためのブリッジ役となるソフトウェア群です。これが正しくインストール・設定されていないと、GPUパススルーは機能しません。
2. ホスト側のNVIDIAドライバーまたはカーネルモジュールの問題
「Could not load UVM kernel module」というエラーは、ホストOS側のNVIDIAドライバーカーネルモジュール(特にUVM – Unified Video Memoryモジュール)が正しくロードされていないことを示しています。ドライバーのバージョン不整合、インストールの失敗、またはカーネルの更新後にモジュールが再ビルドされていない場合に発生します。
3. Dockerデーモンの再起動不足またはランタイム設定の不備
NVIDIA Container Toolkitをインストールした後、Dockerデーモンを再起動しないと、新しい設定が読み込まれません。また、Dockerのデフォルトランタイムが`nvidia`に正しく設定されていないことも原因となります。
解決方法:完全なインストールと設定手順
以下に、Ubuntu 20.04/22.04 LTSを例に、問題を解決するための完全な手順を示します。他のディストリビューションでも概念は同様です。
ステップ1: 前提条件の確認
まず、ホストマシンにNVIDIA GPUドライバーが正しくインストールされていることを確認します。
# NVIDIAドライバーとCUDAツールキットのバージョン確認
nvidia-smi
正常に表示されればOKです。表示されない場合は、まずホストOS向けのNVIDIAドライバーをインストールしてください。
ステップ2: NVIDIA Container Toolkitのインストール
公式リポジトリを追加し、必要なパッケージをインストールします。
# ディストリビューションとアーキテクチャを設定
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
echo "Distribution: $distribution"
# NVIDIA Container Toolkitのリポジトリを追加
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/$distribution/libnvidia-container.list |
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' |
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
# パッケージリストを更新し、ツールキットをインストール
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
ステップ3: Dockerランタイムの設定
インストール後、`nvidia-container-runtime`をDockerの利用可能なランタイムとして設定します。
# nvidia-container-runtimeをDockerの設定に登録
sudo nvidia-ctk runtime configure --runtime=docker
# 設定ファイルの内容を確認(オプション)
sudo cat /etc/docker/daemon.json
このコマンドは、`/etc/docker/daemon.json` ファイルを編集または作成し、以下のような`runtimes`セクションを追加します。
{
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}
ステップ4: Dockerデーモンの再起動と設定の適用
設定を有効化するために、Dockerサービスを再起動します。
sudo systemctl restart docker
ステップ5: GPUパススルーの動作確認
最も簡単なテストは、NVIDIAが提供するCUDAコンテナを実行し、`nvidia-smi`がコンテナ内で動作するか確認することです。
# テスト用コンテナの実行
sudo docker run --rm --runtime=nvidia --gpus all nvidia/cuda:12.1.1-base-ubuntu22.04 nvidia-smi
あるいは、より新しいDockerバージョン(19.03以降)では`–gpus`オプションが利用できます。
sudo docker run --rm --gpus all nvidia/cuda:12.1.1-base-ubuntu22.04 nvidia-smi
ホストで実行した場合と同様のGPU情報がコンテナ内から表示されれば、設定は成功です。
ステップ6: 「Could not load UVM kernel module」エラーへの対処
上記手順後もこのエラーが発生する場合は、ホスト側のNVIDIAカーネルモジュールに問題がある可能性が高いです。以下の手順でトラブルシューティングします。
# 1. ホスト側でNVIDIAモジュールがロードされているか確認
lsmod | grep nvidia
# nvidia_uvm, nvidia_drm, nvidia_modeset, nvidia などのモジュールが表示されるはず
# 2. 表示されない場合、手動でロードを試みる
sudo modprobe nvidia-uvm
# 3. 永続化のために、モジュールを/etc/modulesに追加
echo "nvidia-uvm" | sudo tee -a /etc/modules
# 4. カーネルを更新した直後の場合、NVIDIAドライバーカーネルモジュールを再ビルド
sudo apt-get install --reinstall linux-headers-$(uname -r)
sudo apt-get install --reinstall nvidia-kernel-$(uname -r | sed 's/-/ /g' | awk '{print $1}') # ディストリビューションにより異なる
# または、NVIDIAドライバーインストーラーを再実行する
コード例・コマンド例:実践的なAI開発環境の構築
設定が完了したら、実際のAIフレームワークが動作するコンテナを起動してみましょう。
# PyTorch公式イメージを使用したインタラクティブな環境の起動
docker run -it --rm --gpus all -p 8888:8888
-v $(pwd)/workspace:/workspace
pytorch/pytorch:2.0.1-cuda11.7-cudnn8-runtime
bash
# コンテナ内でPythonを起動し、GPUが認識されているか確認
python3 -c "import torch; print(f'PyTorch version: {torch.__version__}'); print(f'CUDA available: {torch.cuda.is_available()}'); print(f'GPU device count: {torch.cuda.device_count()}')"
# TensorFlow公式イメージを使用したJupyter Notebook環境の起動
docker run -it --rm --gpus all -p 8888:8888
-v $(pwd)/notebooks:/tf/notebooks
tensorflow/tensorflow:latest-gpu-jupyter
# 起動後、ブラウザで http://localhost:8888 にアクセス
まとめ・補足情報
NVIDIA Container Toolkitを用いたDockerコンテナへのGPUパススルー設定は、現代のAI開発における必須のスキルです。本記事で解説した手順に従うことで、ほとんどの環境で問題を解決できるはずです。設定の要点を以下にまとめます。
- 依存関係の管理: ホストのNVIDIAドライバー、Dockerエンジン、NVIDIA Container Toolkitのバージョン互換性に注意してください。特にCUDAバージョンとフレームワークの要求バージョンを一致させることが重要です。
- 「–runtime=nvidia」と「–gpus all」の違い: 古いガイドでは`–runtime=nvidia`オプションが使われていますが、Docker 19.03以降ではより直感的な`–gpus all`(または`–gpus 2`のように特定のGPU数を指定)の使用が推奨されます。内部的には同じ機能を呼び出します。
- マルチGPU環境: 複数GPUを搭載するサーバーでは、`–gpus all`ですべてのGPUがコンテナに渡されます。特定のGPUのみを割り当たい場合は、`–gpus ‘”device=0,2″‘`のようにデバイスIDを指定できます。
- 永続的な問題が解決しない場合: NVIDIA Container ToolkitのGitHub IssuesやNVIDIA Developer Forumを検索することをお勧めします。特定のディストリビューションやカーネルバージョンに固有の問題が報告されていることがあります。
この設定が完了すれば、再現性が高く、依存関係に悩まされない、ポータブルなGPU機械学習開発環境を手に入れたことになります。プロジェクトごとに異なるCUDAバージョンやライブラリバージョンが必要な場合も、Dockerイメージを切り替えるだけで対応可能となり、開発効率が大幅に向上します。