GPUコンテナ上でREALITYアバターを動かしてみた REALITY Advent Calendar #21
REALITY Advent Calendar 2022 21日目担当のtk_3118です!
REALITYでは普段はサーバ、インフラ、Unity周りに生息しています。
以前REALITY Techブログではコチラの記事などを書かせていただきました。
今回、REALITY開発合宿へ向かうに当たっていくつか取り組むテーマを考えていたわけですが、今回は「REALITYアバターを用いた画像生成をサーバサイドで動作させる」ということをやってみます。
似たようなことを以前取り組んだことはあるものの合宿の1日という時間でどこまで成果が出せるかドキドキでした…!
「REALITYアバターを用いた画像生成をサーバサイドで動作させる」とは、REALITYの場合、より具体的にはREALITYのUnityPlayerをLinux対応させ、スケールできるようにコンテナに乗せてかつ、GPUを使えるようにし、ヘッドレス環境でグラフィック処理を完結させてGKEに載せるというところまでやることになる訳で、
まあ実はこれは結構大変な部類の作業な訳なんですが、近いところでいうと
「クラウドゲーミング」で使われるような技術分野になります。
ここにgstreamerでキャプチャしてwebrtcで送ればほぼクラウドゲーミングといった感じなわけです。
(実際にはそんなに簡単ではないのですがここでは割愛…
そんなこんなでこれ一体どこに活用するの?という話しになるかと思うのですが、分かりやすいところでいうと「アバタースタンプ画像生成」で、
こちらはクライアント側で生成ボタンを押してクライアント内でスタンプ画像を生成するという手法をとっているのですが、バリエーションを増やすなどにあたって待ち時間の増加が発生することが見込まれ、クライアントで生成するにしてもバックグラウンドで生成するなり、サーバ側で生成するなり出来ないの?といった感じで開発の方でも頭を悩ませていた問題の一つでした。
これをサーバサイドでスタンプ画像生成を行うことによって
待ちによる操作できない時間を無くし、かつバリエーション豊かなスタンプが使えるようになることでしょう…!
それではやっていきましょう
機能について
といったところで今回作る機能としては、サーバサイドでREALITYアバターを用いた画像生成を行いたい訳で、かといって時間の都合もあるので、
あれもこれもと機能を詰め込むことは出来ません
なのでやりたい試みを最短経路で実装できそうなものとして、
管理ツールからAPIサーバに画像生成のリクエストをqueueに積み、コンテナ上で動くUnityPlayerが生成リクエストを取得し、REALITYのポーズをキャプチャして画像を生成した上でGCSへアップロードするという機能として作っていきます。
図にすると下のような感じになります。
今回はこの構成で実装していきます。
実装について…
上述の機能を実装していく訳ですが、REALITY Unity PlayerのLinuxビルドなどは事前に準備を行っていたので、おもむろにGPU付きのUbuntu上で動作させてみたところ動きません…
どうやら以前にビルドしたLinux向けAssetBundleが開発環境で読み込めなくなっていたようで、こちらを修正したところ以下のように無事Unity Player が動作しました
さて、ここからが本番で「GPUコンテナ上でUnityPlayerを動かしそれをKubernetes(GKE)に載せる」というところを深掘りしていきます。
GPUコンテナの構成に関して
コンテナ内でGPUを使えるようにするためには、
GPUが使えるインスタンスを用意した上でGPUが使えるコンテナを用意する必要があります。
何を当たり前のことをと思われる方も居るかもしれないのですが、普通GPUが使えるUbuntuなどでは、上述の例のようにUnityPlayerなどのGLXやVulkanのグラフィックスアプリケーションを動かすことは、大して難しくありません。
しかしこれをコンテナ上で動かそうとすると少し話は別で、GPUインスタンス上に立てたコンテナでは普通GPUが使えず、コンテナ側でもGPUが使えるようにする必要があります。
GPUをコンテナ内で使いたい場合、いくつか手法はあるのですが、今回GPUのデバイスはnvidia-dockerで共有しドライバはコンテナ内部でまごころを込めて1から作成することにしました。
X11に関して…
↑の内容でコンテナ内でGPUを使えるようになったので、これの上でUnityPlayer(=GLX/Vulkan)を動作させたい訳ですが、これを行うにはX11を使用する必要があります。
X11とはウィンドウシステムのことを指す訳ですが、
ubuntuなどをデスクトップとして使用したことがある人なら間違いなく使ったことがあるはずで、GUIアプリケーションを立ち上げた時に出てくるアプリはこれが使われています。例によってUnityPlayerなどのGLX/VulkanアプリもこのX11を対象にして初期化処理を行う為、これらを動作させるためにはX11が必要不可欠ということになります。(というか描き込む先が無いので何も出来ない)
ということでこれを用いてコンテナ内でGLX/Vulkanを動かしたいわけですが、どうやるのでしょうか…?
ここが実は一番の難所であり尚且つ間違えると技術的負債にもなりやすいとこかなという認識(最もクラウドゲーミングと近いところ)なんですが、こういったコンテナを用いてX11アプリケーションを描画する方式としては、ポピュラーな手法としてはホストの $DISPLAYを共有するといったのがメジャーですが、これを行う場合はホスト側にX11サーバの設定を行う必要があります。
今回、スケーラブルにするためにKubernetes上で動かすことから、コンテナベースである為にホストの環境に触りづらく、worker-nodeに対してX11などの環境設定をすることが難しく、特にオートスケールするworker-nodeのホスト自身を都度provisioningするというのは、イベントの取得や運用・実装などを踏まえてもかなり無理のある運用になると考えている為、コンテナ内でx11server/client共に動作させる形を構築します。(コンテナ内部で描画が完結する方式)
今回こちらの実装にはxorgを用いるのですが、例によってコチラもコンテナ内部でxorgのコンフィグに対してGPUが使えるように編集する必要があります。(これをしないとX11サーバがGPUを使えないのでGLX/Vulkan が描画できない)
以下はその例になります
nvidia-xconfig \
-a \
--virtual=1280x1024 \
--allow-empty-initial-configuration \
--enable-all-gpus \
--busid PCI:X:X:X
ここまで出来てGPUコンテナ上でX11サーバを起動すると、コンテナ内の仮想ディスプレイを描画対象としてGLX/Vulkanのアプリが動くようになるので UnityPlayerも動くようになっているはずです。
Kubernetes上で展開する
後はここまでのものをKubernetesに上げるわけですが、
一つGPUドライバのインストール方法に関してはいくつか手法があり注意が必要です。今回は一番簡単なcontainer-engine-acceleratorを使用して実装します。
取りうる手法によってGPUリソースの使用方法などに違いが出てくるので本番で使おうと考えている場合などは要検討になります。
GKEの場合あとは、ココを見ながら設定していく形になります。
残りの作業としては以下の感じで、GKEを使っている方であれば普段やっていることとさほど変わらないのと、GPU活用に関する部分で足りない部分があれば機械学習系で培われているノウハウが世の中にあるのでそちらで補填すればいけるでしょう。
クラスタ立てる(必要に応じて)
GPUが使えるノードプールを作成
nvidia-dockerでコンテナをビルド
↑をGCRにプッシュする
KubernetesのDeploymentリソースのマニフェストを書いてクラスタに反映
動作確認
お披露目
ここまでの機能を作成して管理ツールから生成依頼を実行してみました。
下記は管理ツール上での生成結果の確認を画面範囲指定してキャプチャしたものになるのですが、アバターの各ポーズがキャプチャされ画像としてアップロードされているのが分かります…!! (すばらしい)
こちらは、上述していたデバッグ用途でコンテナ内部の描画の様子を確認するために作成していたVNCの様子です。
しっかりコンテナ内部の描画の状況が確認できます…!!
費用について
本記事で話そうと思ったのですが、やたらと長くなってしまったので
アドベントカレンダー後日談として話そうかなと考えています。
最後に…
この記事が良かった、またはもっと技術に関する話しを聞きたいと思った方はいいねをいただけると執筆の励みになります…!
明日のアドベントカレンダーの担当は、「チームWelcome」で
「入室歓迎!welcome機能のプロトタイプ作ってみた」です!
明日もお楽しみに!!