OpenGLやGLXなどを使って画面表示を行うアプリケーションを、画面のないheadlessサーバー上で、しかもDocker内で動かす方法
具体的には、Carlaの環境の構築を目的にしている。
ホストの要件
Nvidia GPUカード1枚が認識できるDockerサーバー
ヘッドレスでの使用を想定しており、例えば、GPU付きノートPCでの使用は、今のところできない。
GPU付きノートでdocker container上でGPUを使い画面描画をしようとすると、ノート上の画面表示に使用してるGPUと重複してしまうため、画面がフリーズしてしまう。 フリーズは画面のみなので、ssh経由では入れるが、使い物にならなくなる。 もし、ノートPCで動かしたい場合には、carla0910を使うとよい。 Docker上で動かす場合には、元のcuda-toolkitのバージョンを合わせる必要があるので注意。
下記のマシンでは、Cuda toolkitのバージョンは、リビジョンが違っても動作しないみたいなので、合わせる必要がある。
Dockerfileでは、11.2.2のドライバーをインストールしている。
novnc経由で研究室内で使えるのは、
192.168.100.201:6080
192.168.100.211:6080
192.168.100.221:6080
の3台のみ。
Buildするには:
./build.sh
Runするには:
./run.sh
研究室サーバーは、すべて2枚グラフィックカードの構成
研究室サーバは、基本、ミニマムインストール+KVMのインストール GPU passthrough機能を使い、KVMクライアント上で、GPUを使えるようにする。 KVMクライアントの設定でGPUを使えるようにする。(KVMクライアントは、どのバージョン、OSでもインストール可能)
なお、nvidia-smiで表示されるバージョンと、Dockerfileに書かれているスクリプトのバージョンは、合わせる必要がある。
バージョンが上がった場合には、cuda-install-kitのインストールの仕方に合わせDockerfile、build.shを修正する。
KVMクライアントへGPUのドライバとnvidia-docker2をインストールする。
sshログインしてnvidia-smi
を実行して、GPUが検出されることと、入っているドライババージョンを確認
X11サーバーとアプリケーションの入ったdocker containerをビルド、立ち上げる。
run.shがdocker内で実行される。
ホストマシンに一度ログインして、nvidia-xconfig --query-gpu-info
を実行し、BUSIDを控えておく。
(startup.sh内で処理済み)
2つの要素が組み合わさってできている。
xorg xvfb x11vnc
などで仮想ディスプレイ環境を作れるが、GPUを使いたい場合はNVIDIAドライバの機能を使う必要がある。DISPLAY
/tmp/.X11-unix
を共有する方法ではなく、Xorgをコンテナ内で動かす方法。順番に解説する。
これに関しては解説がいろいろある。
大まかな手順としては
nvidia-xconfig
を使うと、headless環境で仮想displayを使うためのXorg向けの設定を出力できる。しかしコマンド自体のオプションのマニュアルが不足しているので、release noteを読んで確認する必要がある。
X11 GUIアプリケーションをdocker内で動かしたい時、いくつか選択肢がある。
-e DISPLAY=$DISPLAY
とか-v /tmp/.X11-unix:/tmp/.X11-unix
とかを指定するのはこちらのアプローチ。やり方については検索すると出てくるので割愛。 x11 clientだけをcontainer内で動かし、host上で動いているx11 serverに接続して描画してもらう。dockerからは描画命令だけが来るので、例えばGPUを使って実際に描画するのはx11 server側、つまりcontainer外になる。それ以前に、デスクトップ環境を作っていないサーバー上で動かす場合、そのhost上でまずX11サーバーをセットアップする必要がある。 この方法でも、「ローカルのデスクトップ環境上で動かすが、ホストの環境を汚さないためにdocker内でGUIアプリを使いたい」場合や、「サーバーだけど直にX11をセットアップするのを厭わない」場合は十分。普通のXアプリなら上の手順で良いが、OpenGLなどグラフィック用途でGPUを使うアプリケーションの場合、
docker内でNVIDIA GPUを扱いたいときは、nvidia-docker2を使うのが普通。これはホストのGPUのデバイスファイルとそのドライバをコンテナと共有し、GPUをコンテナ内側でも使えるようにする技術だが、公式にはCUDA系やOpenGLの一部のみをサポートしていて、グラフィック系のGLX・Xorgからのレンダリング・vulkan等に対応していない( https://github.com/NVIDIA/nvidia-docker/issues/631 )ため、XorgがNVIDIA-GPUを使うためのドライバやGLXのextensionはコンテナと共有されない。
なので、nvidia-docker2の機能でGPUのデバイスファイルを使えるようにし、ドライバはコンテナ内部で1からインストールすることでGLXをコンテナ内で使えるようにできた。
コンテナ内部でドライバをインストールするDockerfileとして、公式の nvidia/driver - Docker Hub とその解説wiki Driver containers (Beta) · NVIDIA/nvidia-docker Wiki) がある。これはNVIDIAのドライバを公式からダウンロードして、インストールスクリプトを実行しているDockerfileだが、前述のようにX系のドライバをインストールを省略している。 https://gitlab.com/nvidia/driver/blob/master/ubuntu16.04/Dockerfile#L43 を見ると
--x-prefix=/tmp/null \ --x-module-path=/tmp/null \ --x-library-path=/tmp/null \ --x-sysconfig-path=/tmp/null \
そこでXorgをインストールした後、ドライバインストール時にこのオプションをきちんと設定して、X用のグラフィックドライバをインストールさせる。これが終われば、ホストのGPUサーバー上でXorgを動かすのと全く同様に、dockerコンテナ内でXorgを(GPU込みで)動かすことができるようになる。
あとは(A)と同じで、(A)のコマンドで作ったxorg.confをコンテナ内に設置して、Xorg &
でサーバーを走らせれば動く。
X11サーバーの1つの実装。
Xorg :0
とするとサーバーが立ち上がる。
例えばx11-apps
を入れてDISPLAY=:0 xeyes
とすると目玉のテストアプリケーションが立ち上がる。
UbuntuでNVIDIAのディスプレイドライバが動作しない場合のチェック項目 - Qiita が参考になる。
lspci | grep NVIDIA
起動しているx11 serverの画面をそのままvncで飛ばすソフトウェア。実際のdisplayが繋がっている場合はその画面が、仮想displayの場合はその中身が転送される。
ずっと起動しておく -forever
ポート変更 x11vnc -rfbport 5566
実際にアプリケーションを表示したいXサーバーのアドレスを:0
、GPUにアクセスできるXサーバーのアドレスを:1
とする。
DISPLAY=:0 VGL_DISPLAY=:1 vglrun glxgears
とした場合、アプリケーションのレンダリング命令が:1
に行き、そのレンダリング結果が画像としてキャプチャされ、:0
に送られる。これは通常通り
DISPLAY=:0 glxgears
とした時に、GPUにアクセスできないXサーバー(例えばこれはssh -Xで転送されたクライアントのXサーバーなど)側にレンダリング命令が来てGPUを活用できない状況をパフォーマンス面で改善できるが、実際に:0
から見える結果は全く同じになる。
仮想ディスプレイを作るソフト。 ただしGPUは使わない。ソフトレンダリングのみならこれで十分。
Xサーバーがnvidia gpuを使えるように
nvidia-xconfig --query-gpu-info