リモートPC(Ubuntu20.04)でGazeboなど、OpenGL経由でGPUを利用する環境へアクセスできる環境を構築したので、その過程を記録しておきます。

環境について

  • OS: Linux (Ubuntu 20.04 LTS)
  • CPU: AMD Ryzen
  • MEM: 16GB
  • GPU: Nvidia Geforce GTX 1660
    • nvidia-dirver 470.xをインストール済
  • すでにsshd設定済み

WindowManagerの準備

VNCでリモート接続を行う場合、起動スクリプトが煩雑なGNOME(gdm3)よりLXDEやXfce(lightdm)とするのが楽かと思われます。

利用環境にはGNOMEを入れていたので、削除してからLXDEを導入します。

まずは以下のようにGNOME系を一通り削除します。

$sudo apt purge adwaita-icon-theme gedit-common gir1.2-gdm-1.0 \
gir1.2-gnomebluetooth-1.0 gir1.2-gnomedesktop-3.0 gir1.2-goa-1.0 \
gnome-accessibility-themes gnome-bluetooth gnome-calculator gnome-calendar \
gnome-characters gnome-control-center gnome-control-center-data \
gnome-control-center-faces gnome-desktop3-data \
gnome-font-viewer \
gnome-initial-setup gnome-keyring gnome-keyring-pkcs11 gnome-logs \
gnome-mahjongg gnome-menus gnome-mines gnome-online-accounts \
gnome-power-manager gnome-screenshot gnome-session-bin gnome-session-canberra \
gnome-session-common gnome-settings-daemon gnome-settings-daemon-common \
gnome-shell gnome-shell-common gnome-shell-extension-appindicator \
gnome-shell-extension-desktop-icons gnome-shell-extension-ubuntu-dock \
gnome-startup-applications gnome-sudoku gnome-system-monitor gnome-terminal \
gnome-terminal-data gnome-themes-extra gnome-themes-extra-data gnome-todo \
gnome-todo-common gnome-user-docs gnome-user-docs-ru gnome-video-effects \
language-pack-gnome-en language-pack-gnome-en-base language-pack-gnome-ru \
language-pack-gnome-ru-base language-selector-gnome libgail18 libgail18 \
libgail-common libgail-common libgnome-autoar-0-0 libgnome-bluetooth13 \
libgnome-desktop-3-19 libgnome-games-support-1-3 libgnome-games-support-common \
libgnomekbd8 libgnomekbd-common libgnome-menu-3-0 libgnome-todo libgoa-1.0-0b \
libgoa-1.0-common libpam-gnome-keyring libsoup-gnome2.4-1 libsoup-gnome2.4-1 \
nautilus-extension-gnome-terminal pinentry-gnome3 yaru-theme-gnome-shell
$sudo apt purge gnome-getting-started-docs gnome-getting-started-docs-ru
$sudo apt remove gdm3

そしてlxdeをインストールします。

$sudo apt install lxde

LXDEのスリープ問題

また、LXDEの電源オプションの問題で、20分経過でスリープされてSSHやVNCが勝手に切れてしまう問題があります。 毎度毎度WoLで起動するのは面倒ですし、これはどうもGUI上からでは変更できないようだったので、systemctlから設定を変更します。

$sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
Created symlink /etc/systemd/system/sleep.target → /dev/null.
Created symlink /etc/systemd/system/suspend.target → /dev/null.
Created symlink /etc/systemd/system/hibernate.target → /dev/null.
Created symlink /etc/systemd/system/hybrid-sleep.target → /dev/null.

maskはDisableの強化版みたいです。

参考:Ubuntu 20.04 の自動スリープを無効にする

VirtualGLの導入

公式のドキュメントVirtualGL, Docにしたがって、インストール作業を勧めます。

インストール

一度WindowManagerを終了してインストールを行います。 今回は最新の3.0系をインストールしました。

# LXDE
$ systemctl status display-manager.service
● lightdm.service - Light Display Manager
     Loaded: loaded (/lib/systemd/system/lightdm.service; indirect; vendor preset: en>
     Active: active (running) since Wed 2022-05-11 15:01:53 JST; 34s ago

$ sudo cp /etc/X11/xorg.conf /etc/X11/xorg.conf.20220511_bak
$ sudo nvidia-xconfig

$ sudo apt install libegl1-mesa libglvnd-dev
$ wget -O virtualgl_3.0_amd64.deb https://sourceforge.net/projects/virtualgl/files/3.0/virtualgl_3.0_amd64.deb/download
$ sudo dpkg -i virtualgl_3.0_amd64.deb
$ sudo apt install -f

$sudo systemctl stop lightdm.service

$sudo rmmod  nvidia_uvm
$sudo rmmod  nvidia_drm
$sudo rmmod  nvidia_modeset

rmmod: ERROR: Module nvidia_drm is in use

とエラーが出る場合は、

sudo lsof /dev/nvidia*でプロセス特定してkillします。

そしてVirtualGLの初期設定を行います。

$ sudo vglserver_config

1) Configure server for use with VirtualGL (GLX + EGL back ends)
2) Unconfigure server for use with VirtualGL (GLX + EGL back ends)
3) Configure server for use with VirtualGL (EGL back end only)
4) Unconfigure server for use with VirtualGL (EGL back end only)
X) Exit

Choose:
1

WARNING: Configuring this server for use with VirtualGL will disable the
ability to log in locally with a Wayland session.

Continue?
[Y/n]
y

Restrict 3D X server access to vglusers group (recommended)?
[Y/n]
y

Restrict framebuffer device access to vglusers group (recommended)?
[Y/n]
y

Disable XTEST extension (recommended)?
[Y/n]
y
... Creating vglusers group ...
groupadd: グループ 'vglusers' は既に存在します
Could not add vglusers group (probably because it already exists.)
... Granting read permission to /etc/opt/VirtualGL/ for vglusers group ...
... Creating /etc/modprobe.d/virtualgl.conf to set requested permissions for
    /dev/nvidia* ...
... Attempting to remove nvidia module from memory so device permissions
    will be reloaded ...
... Granting write permission to /dev/nvidia-modeset /dev/nvidia-uvm /dev/nvidia-uvm-tools /dev/nvidia0 /dev/nvidiactl for vglusers group ...
... Modifying /etc/X11/xorg.conf to enable DRI permissions
    for vglusers group ...
... Adding vglgenkey to /etc/gdm3/Init/Default script ...
... Creating /usr/share/gdm/greeter/autostart/virtualgl.desktop ...
... Disabling Wayland in /etc/gdm3/custom.conf ...

Done. You must restart the display manager for the changes to take effect.

また、ここでsshd_configでX11Forwardingを許可、UseLoginを無効にしておきます。 UseLoginはデフォルトでOffらしいので、古い環境以外は関係ないと思いますが(OpenSSH7.4で廃止されたとか?)。

VNCの導入

続いてVNCの導入を行います。今回はTigerVNCを選択します。 VirtulaGLと同開発元のTurboVNCでなくてもVirtualGLには対応しているVNCServerは多い用で、ここではリポジトリに存在して管理しやすいTigerVNCを利用します。

VNC接続時はクライアントではAuto Scaleとしておくと使いやすいです。

$ sudo systemctl start lightdm.service
$ sudo apt install tigervnc-standalone-server
$ sudo usermod -a -G vglusers username
$ vncserver
# setting password
$ vncserver -kill :1

$ echo "vglrun startlxde" > ~/.vnc/xstartup
$ chmod 755 ~/.vnc/xstartup

$ vnvserver

VNCの簡単な使い方は以下の通りです。 PCの再起動をしてもvncserverの起動状況は残りますので、手動で終了する必要があります。

# パスワード設定
$vncpasswd

# 起動
$vncserver
$vncserver :1 # Port5901での起動(デフォルト) 

# リスト
$vncserver -list

# 終了
$vncserver -kill :1

これでクライアント側からVNC接続ができるようになりました。

安全のためにssh転送経由で外部から接続するようにしています。

LD_PRELOAD設定(VirtualGL 3.0)

今回は最新の3.0を利用したこともあり、比較的情報のある2.x系と一部設定が違うようです。LD_PRELOADまわりなど。

suなどの実行時に以下のようなエラーが出ました。

$ su -
ERROR: ld.so: object 'libdlfaker.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
ERROR: ld.so: object 'libvglfaker.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.

virtualgl3.0ではprofileにLD_PRELOAD設定をするのではなくて公式Docにあるようにsetuidすれば良いようです。 これでsuなどを行った際にERRORが表示されることはなくなりました。

VirtualGL3.0 Doc

chmod u+s /usr/lib/libvglfaker.so
chmod u+s /usr/lib/libdlfaker.so

なお、firefoxでabout:supportでWEBGL2.0はNVIDIAにはなってないが、WebGLデモページとかは問題なく動いているようにも見えます。 このあたりも2.x系とは異なるのでしょうか。

LD_PRELOADの設定(VirtualGL 2.x系?)

su実行時のLD_PRELOADエラーに関しては~/.profileに以下を追加するとよいという情報もありますが、VirtualGL3.0では機能しないようです。

export LD_PRELOAD=/usr/lib/libdlfaker.so:/usr/lib/libvglfaker.so:$LD_PRELOAD

設定後、VNC上でターミナル開くと以下のようになってしまいます。

ERROR: ld.so: object '/usr/lib//usr/lib/' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
ERROR: ld.so: object '/usr/lib//usr/lib/' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
ERROR: ld.so: object '/usr/lib//usr/lib/' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
ERROR: ld.so: object '/usr/lib//usr/lib/' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
ERROR: ld.so: object '/usr/lib//usr/lib/' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.

~$ echo $LD_PRELOAD
libdlfaker.so:libvglfaker.so:/usr/lib//usr/lib/

2.x系で通用した対処方法のようです。3.0ではchmod u+sの方がドキュメントに記載されています。

Glmark2によるテスト

また、glmark2でテストしようとしても、NVIDIA Driverの問題か途中で終了します。 glmark2 Issue, Ubuntu Issueなどに問題として報告されているようです。

$ glmark2
=======================================================
    glmark2 2021.02
=======================================================
    OpenGL Information
    GL_VENDOR:     NVIDIA Corporation
    GL_RENDERER:   NVIDIA GeForce GTX 1660/PCIe/SSE2
    GL_VERSION:    4.6.0 NVIDIA 470.103.01
=======================================================
[build] use-vbo=false: FPS: 2190 FrameTime: 0.457 ms
[build] use-vbo=true: FPS: 2564 FrameTime: 0.390 ms
[texture] texture-filter=nearest: FPS: 2534 FrameTime: 0.395 ms
[texture] texture-filter=linear: FPS: 2534 FrameTime: 0.395 ms
[texture] texture-filter=mipmap: FPS: 2534 FrameTime: 0.395 ms
[shading] shading=gouraud: FPS: 2555 FrameTime: 0.391 ms
[shading] shading=blinn-phong-inf: FPS: 2564 FrameTime: 0.390 ms
[shading] shading=phong: FPS: 2575 FrameTime: 0.388 ms
[shading] shading=cel: FPS: 2506 FrameTime: 0.399 ms
[bump] bump-render=high-poly: FPS: 2553 FrameTime: 0.392 ms
[bump] bump-render=normals: FPS: 2552 FrameTime: 0.392 ms
Error: Failed to add fragment shader from file None:
Error:   0(15) : error C0000: syntax error, unexpected identifier, expecting "::" at token "highp"
Error: 0(36) : warning C1503: undefined variable "TextureCoord"
Error: 0(37) : warning C1503: undefined variable "TextureCoord"
Error: 0(38) : warning C1503: undefined variable "TextureCoord"
Error: 
[bump] bump-render=height: Set up failed
[effect2d] kernel=0,1,0;1,-4,1;0,1,0;: FPS: 2676 FrameTime: 0.374 ms
[effect2d] kernel=1,1,1,1,1;1,1,1,1,1;1,1,1,1,1;: FPS: 2530 FrameTime: 0.395 ms
[pulsar] light=false:quads=5:texture=false: FPS: 2520 FrameTime: 0.397 ms
[desktop] blur-radius=5:effect=blur:passes=1:separable=true:windows=4: FPS: 1176 FrameTime: 0.850 ms
[desktop] effect=shadow:windows=4: FPS: 930 FrameTime: 1.075 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 1087 FrameTime: 0.920 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=subdata: FPS: 1110 FrameTime: 0.901 ms
[buffer] columns=200:interleave=true:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 1248 FrameTime: 0.801 ms
[ideas] speed=duration: FPS: 2161 FrameTime: 0.463 ms
[jellyfish] <default>: FPS: 2475 FrameTime: 0.404 ms
Error: Failed to add fragment shader from file None:
Error:   0(26) : warning C7022: unrecognized profile specifier "highp"
Error: 0(26) : error C0502: syntax error at token "highp"
Error: 
Error: Failed to add fragment shader from file None:
Error:   0(75) : warning C7022: unrecognized profile specifier "highp"
Error: 0(75) : error C0502: syntax error at token "highp"
Error: 
[terrain] <default>:Segmentation fault (??????????)

一方、glxgearsなどは正常にFPS発揮できているのでVirtualGLは問題なく機能しているようにも思えます。

$ glxgears
25260 frames in 5.0 seconds = 5051.934 FPS

これで一通りのVirtualGL+VNC環境が完成しました。

まとめ

  • VirtualGL + TigerVNCでリモート環境を構築
  • glxgearsで正常にFPSが発揮できることを確認
  • GUI対応のGPUリモート環境の構築が出来た