.gitignore | 3 years ago | ||
Dockerfile | 3 years ago | ||
README.md | 3 years ago | ||
run.sh | 3 years ago | ||
screenshot.png | 5 years ago | ||
server.sh | 3 years ago |
OpenGLやGLXなどを使ってグラフィック用途でGPUを使うアプリケーションを、画面のないheadlessサーバー上で、しかもDocker内で動かす方法の最新版
具体的には、Unityで作られたソフト本体の自動テスト環境やそれを使ったCI環境を、GPUインスタンスを含んだkubernetesクラスタ上に構築したい時に使える。
実行するには:
bash server.sh
自動テストサーバーを作るために、 https://github.com/lgsvl/simulator をKubernetes上で動かしたかった。
ECSもGPUインスタンスをサポートし始めたので、Docker内でグラフィック系アプリケーションをGPU機能込みで閉じ込めたい需要は割とあると思うので、まとめておく。
とりあえず使いたい人向けに手順をまず書く。
KVMクライアントへGPUのドライバとnvidia-docker2をインストールする。
ここで使ったのは それ以外は標準のままのインスタンス。us-west1-bに立ち上げた。起動時にwarningが出るが気にしない。ブラウザ上で設定したが、同様のコマンドは以下。
gcloud compute --project=$PROJECT_NAME create $INSTANCE_NAME \ --zone=us-west1-b \ --machine-type=n1-highmem-2 \ --subnet=default \ --network-tier=PREMIUM \ --metadata=framework=TensorFlow:1.13,google-logging-enable=0,google-monitoring-enable=0,install-nvidia-driver=True,status-config-url=https://runtimeconfig.googleapis.com/v1beta1/projects/sever-rendering/configs/tensorflow-1-config,status-uptime-deadline=600,status-variable-path=status,title=TensorFlow/Keras/Horovod.CUDA10.0,version=27 \ --maintenance-policy=TERMINATE \ --service-account=471732791036-compute@developer.gserviceaccount.com \ --scopes=https://www.googleapis.com/auth/compute,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring.write,https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/cloud.useraccounts.readonly,https://www.googleapis.com/auth/cloudruntimeconfig \ --accelerator=type=nvidia-tesla-t4,count=1 \ --tags=deeplearning-vm \ --image=tf-1-14-cu100-20190619 \ --image-project=click-to-deploy-images \ --boot-disk-size=100GB \ --boot-disk-type=pd-standard \ --boot-disk-device-name=tensorflow-1-vm-1 \ --labels=goog-dm=tensorflow-1
ssh port forwardを使うので、sshクライアントからログインできるようにセットアップしておく。(コンソールからssh鍵を登録する。ssh-keygen -t rsa -C "$USERNAME" -b 4096 -f ~/.ssh/$KEYNAME
コメントのユーザー名に指定したユーザーでしかログインできないので注意。)
sshログインしてnvidia-smi
を実行して、GPUが検出されることと、入っているドライババージョンを確認 上のVMでは、Tesla T4とドライババージョン410.104が入っていた。
X11サーバーとアプリケーションの入ったdocker containerをビルド、立ち上げる。
nvidia-docker build -t x11-GL-docker . docker run --runtime=nvidia --privileged -it --rm \ -p 5900:5900 \ # or --net=host -e BUSID=PCI:0:4:0 \ -e SCREEN_RESOLUTION=1280x1024 \ -e VNC_PASSWORD=passpass \ -v /home/ryonakabayashi/x11-docker/lgsvlsimulator-linux64-2019.05:/lg \ --name x11-GL-docker x11-GL-docker
run.shがdocker内で実行される。
5900ポートはVNC用。またホストマシンに一度ログインして、nvidia-xconfig --query-gpu-info
を実行し、BUSIDを控えておく。
docker内で起動しているVNCサーバーに、ssh経由で接続する。
ssh -i "$KEYFILE" -L 5900:localhost:5900 $USERNAME@$GCP_PUBLIC_IP -N &
でトンネルを作り、VNCクライアント(macならFinder)でvnc://localhost:5900
に接続する。
リモートのdocker内でレンダリングした結果が手元のmacbookで確認できる環境がこれで整った。
2つの要素が組み合わさってできている。
xorg xvfb x11vnc
などで仮想ディスプレイ環境を作れるが、GPUを使いたい場合はNVIDIAドライバの機能を使う必要がある。DISPLAY
/tmp/.X11-unix
を共有する方法ではなく、Xorgをコンテナ内で動かす方法。順番に解説する。
これに関しては解説がいろいろある。
大まかな手順としては
nvidia-xconfig
を使うと、headless環境で仮想displayを使うためのXorg向けの設定を出力できる。しかしコマンド自体のオプションのマニュアルが不足しているので、release noteを読んで確認する必要がある。
今回はTesla T4を使う。nvidia-xconfig --query-gpu-info
を見るとBUS idはPCI:0:4:0だったので
nvidia-xconfig \ -a \ --virtual=1280x1024 \ # 仮想スクリーンの解像度 --allow-empty-initial-configuration \ # ディスプレイがなくてもXサーバーを起動する --enable-all-gpus \ # GPUを有効化 --busid PCI:0:4:0 # GPUを見つけられるようにBUSIDを指定しておく
を実行した。これで出てきた/etc/X11/xorg.confはきちんと動いた。
--use-display-device=None
をつけるという記述があるが、Version 410.104(Linux)/412.29(Windows) :: NVIDIA Tesla Documentation によると410.104からサポートされなくなったらしく、つけると起動しなくなるので注意。
詳細についてはrepositoryの記述も読んでください。
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