2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Incusでリモートデスクトップ環境の構築: GPUとサウンド対応でChromeが動作するまで

Last updated at Posted at 2024-09-01

はじめに

これまでDockerを用いてChromeを動作させる方法について紹介してきた。次のステップとして高性能PCを複数のエンジニアが共有して利用する開発用のリモートデスクトップ環境を構築を考える。

しかし、Dockerには「各コンテナはただ1つだけの用途を持つべき」(1コンテナ1アプリケーションプロセス)という設計哲学がある。この哲学により、systemdのような複数プロセスの管理を行う仕組みをDockerコンテナ内で使用することが推奨されていない。つまり、Dockerは開発用のリモートデスクトップ環境の構築には向いていない。

一方で、VirtualBoxやVMwareといった従来の仮想化ソリューションは、リソース消費が大きい。1台のPC上で多数のエンジニア向けの開発環境を提供するには適していない。

そこで、LXDからフォークされた軽量なシステムコンテナ仮想化ツールであるIncusを使って、リモートデスクトップ環境を構築する。

その後の記事では、Incusを用いて効率的かつスケーラブルなリモートデスクトップ環境を構築する方法を調査する。

Linuxコンテナ(LXC/CLD or Incus) と Dockerのユースケースの違い

Linuxコンテナ と Docker と VM のアーキテクチャの違い

LXDとIncusの紹介

LXDとは何か

LXDはLinuxコンテナ技術をベースにした軽量な仮想化ツールであり、LXC(Linux Containers)の拡張版として開発された。LXDは仮想マシンのように扱えるコンテナを提供し、効率的なリソース管理を可能にしている。LXDを使うことで、従来の仮想マシンに比べてはるかに軽量で、迅速な仮想環境の構築が可能となる。

LXDからフォークされたIncus

LXDは現時点ではUbuntuを開発しているCanonicalが開発しており、IncusはLXDプロジェクトからフォークされたコンテナ仮想化ツールである。LXDはバージョン5.2からライセンスがApache2からAGPL3に変更されたが、フォークしたIncusはApache2ラインセンスのままである。

フォークのアナウンスが2023年8月7日ということもあり、現時点ではLXDとIncusに大きな違いはUbuntu依存部分とのこと。コマンド名がldxなのかincusなのかの違いくらいしかないのであれば、現時点ではどちらを利用するかは、個人利用の範囲であればあまり重要ではなさそうだ。

ネットワーク環境

項目 IPアドレス OS 詳細
クライアントPC 192.168.1.100 MacOS ユーザーが手元で操作する端末
ホストPC 192.168.1.113 Ubuntu 24.04 Incusコンテナが動作するPC。クライアントPCからコンテナに接続する場合の踏み台サーバ(Bastion Server)になる
Incusコンテナ 10.107.73.63 Ubuntu 24.04 開発用のリモートデスクトップを動作させる。クライアントPCからホストPCを経由してIncusコンテナに接続する

Incusのインストールと設定

Ubuntu24.04の場合は標準でincusのパッケージが用意されている。

sudo update
sudo apt install -U -y incus

その他の環境向けの公式ドキュメント

初期設定

sudoなしでincusコマンドを実行できるようにする

ユーザーにIncusを制御する許可を与える。ユーザーグループは2つ存在する。

  • incus: 基本的なユーザーアクセスを許可
  • incus-admin: Incusの完全なコントロールを許可

すべてのコマンドをrootで実行することなくIncusを制御するには、自分のユーザ名をincus-adminグループに追加する。

sudo adduser YOUR-USERNAME incus-admin
newgrp incus-admin

newgrp incus-adminを行わない場合には端末の再起動(ロウアウトしてログイン)が必要となる

incus-adminグループにユーザ名が登録されたことを確認する

$ sudo cat /etc/group | grep incus
incus:x:984:
incus-admin:x:983:raiko

Incusの初期化

Incusはネットワークとストレージでいくつかの初期設定が必要だ。自動設定で良いなら下記のコマンドを実行する。

自動設定
incus admin init --minimal

初期化オプションをチューニングしたい場合

対話式で設定
incus admin init

初期化オプションの詳細の公式ドキュメント

コンテナ起動と基本設定

コンテナの公式イメージ

コンテナの公式のイメージサーバーで利用可能な一覧は下記のコマンドで取得可能だ。

incus image list images:

コンテナを起動する

Ubuntu24.04のイメージを使ってnobleという名前のコンテナを起動する。

incus launch images:ubuntu/24.04 noble

コンテナ一覧を取得する

起動したコンテナを確認する。デフォルト設定の場合には起動したコンテナはNATでホストPCを経由して外部ネットワークに接続する。作成したコンテナのIPアドレスは10.07.73.63である。

incus list
incus listの表示
+-------+---------+----------------------+---------------------------------------------+-----------+-----------+
| NAME  |  STATE  |         IPV4         |                    IPV6                     |   TYPE    | SNAPSHOTS |
+-------+---------+----------------------+---------------------------------------------+-----------+-----------+
| noble | RUNNING | 10.107.73.63 (eth0) | fd42:8159:b94:458:216:3eff:feb8:9cc2 (eth0) | CONTAINER | 0         |
+-------+---------+----------------------+---------------------------------------------+-----------+-----------+

コンテナ内のユーザーの設定を行う

ここではデフォルトユーザのubuntuを使う。後ほどリモートデスクトップにログインで必要となるパスワードを設定しておく。

incus exec noble -- passwd ubuntu

コンテナからインターネットへのパケット到達を確認する

incus exec noble -- ping -c 4 8.8.8.8
bash incus exec noble -- ping -c 4 8.8.8.8 の出力
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=57 time=4.20 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=57 time=4.47 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=57 time=4.25 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=57 time=4.24 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 4.198/4.289/4.466/0.104 ms

筆者の環境ではコンテナからインターネットへのパケット到達の確認に失敗した。コンテナからのNAT接続に必要な設定を手動で行う必要があったのでメモを残しておく。筆者の場合には「NATルールの追加」と「FORWARDチェーンのデフォルトポリシーを変更」の二つでコンテナからインターネット接続が可能となった。

コンテナからインターネットに接続できない場合のNAT設定の例

NATルールの追加

コンテナから外部へのパケットはeth0のIPアドレスに変換して通信する

sudo iptables -t nat -A POSTROUTING -s 10.107.73.0/24 ! -d 10.107.73.0/24 -o eth0 -j MASQUERADE
FORWARDチェーンのデフォルトポリシーを変更

FORWARDチェーンのポリシーをACCEPTに変更する。

sudo iptables -P FORWARD ACCEPT

詳細は下記を参照のこと

コンテナにデスクトップ環境の構築する

デスクトップ環境のパッケージをコンテナにインストールする

ホストPCで実行
incus exec noble -- apt-get update
incus exec noble -- apt-get upgrade -y
incus exec noble -- sudo apt-get install -y lubuntu-desktop

SSHでコンテナに接続する

SSHでコンテナに接続する環境を構築する

ホストPCで実行
incus exec noble -- apt-get install -y openssh-server

# sshが起動しているか確認する
incus exec noble -- systemctl status ssh

# sshが起動していない場合は起動する
incus exec noble -- sudo systemctl start ssh

# 再起動時に自動でsshが起動するように設定する
incus exec noble -- sudo systemctl enable ssh

ポートフォワーディングで接続する場合

クライアントPCからホストPCを経由してコンテナにSSH接続するための設定を行う。
(1)incusのポートフォワーディングを利用する場合と、(2)SSHのトンネリングを利用する場合に2点について確認する。

ポートフォワーディング設定

ホストPCの10022ポートで接続された場合にコンテナnobleの22ポートに転送したい。
Incusでポートフォワーディング行う場合には、(1)ネットワークフォワードを作成し、(2)フォワードするポートを設定する。

# ネットワークフォワードを作成する 
#  - incusbr0: Incusの初期化時に作られたネットワーク名
#  - 192.168.1.133 はホストPCのIPアドレス
incus network forward create incusbr0 192.168.1.113

# フォワードするポートを設定する
#  - incusbr0: Incusの初期化時に作られたネットワーク名
#  - 192.168.1.133: ホストPCのIPアドレス
#  - tcp: 転送するプロトコル
#  - 13389: ホストPCで受け付けるポート番号
#  - 10.107.73.63: 転送先のコンテナのIPアドレス
#  - 22: 転送先のコンテナのポート番号 (ssh)
incus network forward port add incusbr0 192.168.1.113 tcp 10022 10.107.73.63 22

フォアワーディング設定を削除する場合

incus network forward port remove incusbr0 192.168.1.113 tcp 10022
incus network forward delete incusbr0 192.168.1.113

フォワーディングのポートを指定して接続する

クライアントPCで実行
ssh ubuntu@192.168.1.113 -p 10022

踏み台PC経由で接続する場合

クライアントPCからホストPC(192.168.1.113)を踏み台にコンテナ(10.107.73.63)のSSHサーバーに接続する。ホストPCでSSHサーバーが動作している必要があるが、ポートフォワーディングの設定が必要はない。

クライアントPCで実行
ssh -J raiko@192.168.1.113 ubuntu@10.107.73.63

トラブルシューティング

sshで接続できない場合にはsshのステータスやログを確認する

ホストPCで実行
# sshのステータスを確認する
incus exec noble -- systemctl status ssh

# sshのログを確認する
incus exec noble -- journalctl -u ssh

VScodeでコンテナのファイルをリモート編集する

クライアントPCのVScode(Visual Studio Code)でコンテナのファイルをリモート編集する。

拡張機能をインストール

クライアントPCのVScodeにVisual Studio Code Remote - SSH拡張をインストールする。

image.png

SSH経由でコンテナに接続

公式リファレンス

VSCodeのリモートエクスプローラーを開いてのSSHの右にあるボタンを押して、SSH経由でホストPCを踏み台にしてコンテナに接続する

image.png

sshでコンテナにログインする場合と同じコマンドを指定する

image.png

コンテナに接続するとVS Code Serverがコンテナに自動インストールされる
image.png

VS Code ServerがインストールされるとクライアントPCで動作しているVScodeからコンテナのファイルにリモート編集できるようになる。

image.png

XRDPでコンテナに接続する

XRDPでコンテナに接続する環境を構築する。

XRDPサーバ(xrdp)をコンテナにインストールする 

ホストPCで実行する
incus exec noble -- apt-get install -y xrdp

# xrdpの起動を確認する
incus exec noble -- systemctl status xrdp

# xrdpが起動していない場合
incus exec noble -- systemctl restart xrdp

ポートフォワーディングでxrdpに接続する場合

ホストPCの13380ポートにアクセスされた場合はコンテナnobleの3398ポートに転送する。

# ネットワークフォワードを作成する 
#  - incusbr0: Incusの初期化時に作られたネットワーク名
#  - 192.168.1.133 はホストPCのIPアドレス
# 未作成の場合は実行する
# incus network forward create incusbr0 192.168.1.113

# フォワードするポートを設定する
#  - incusbr0: Incusの初期化時に作られたネットワーク名
#  - 192.168.1.133: ホストPCのIPアドレス
#  - tcp: 転送するプロトコル
#  - 13389: ホストPCで受け付けるポート番号
#  - 10.107.73.63: 転送先のコンテナのIPアドレス
#  - 3389: 転送先のコンテナのポート番号 (RDP)
incus network forward port add incusbr0 192.168.1.113 tcp 13389 10.107.73.63 3389

フォアワーディング設定を削除する場合

incus network forward port remove incusbr0 192.168.1.113 tcp 13389
incus network forward delete incusbr0 192.168.1.113

クライアントPCからIncusコンテナに接続する

image.png

Incusコンテナで動作するディスクトップを表示できた

image.png

踏み台PCを使ってクライアントPCからIncusコンテナにXRDP接続する

クライアントPCからホストPC(踏み台PC)を経由してIncusコンテナまでのSSHトンネルを作成する。つまり、下記のコマンドでクライアントPCの3389ポートを、ホストPCを経由して、Incusコンテナの3389ポートにフォワーディングする。

# ssh -L 3389:<コンテナのIP>:3389 -J username@<ホストPCのIP> username@<コンテナのIP>
ssh -L 3389:10.107.73.63:3389 -J raiko@192.168.1.113 ubuntu@10.107.73.63

クライアントPC上で動作しているMicrosoft Remote Desktopアプリでlocalhost3389ポートに接続する。この接続はホストPCを経由してIncusコンテナのxrdpに接続する。

image.png

Incusコンテナのディスクトップを表示できた

image.png

トラブルシューティング

xrdpに接続できない場合にはxrdpのステータスやログを確認する

ホストPCで実行
# xrdpのステータスを確認する
incus exec noble -- systemctl status xrdp

# xrdpのログを確認する
incus exec noble -- journalctl -u xrdp

コンテナでChromeブラウザを動作させる

Chromeインストール手順

リモートデスクトップ環境が構築されたコンテナ内にChromeブラウザを追加でインストールする

ホストPCで実行
incus exec noble -- wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
incus exec noble -- apt-get install -y ./google-chrome-stable_current_amd64.deb

Chromeの動作確認

インストールが完了したらChromeを起動し正常に動作するか確認する。

XRDPで表示したリモートデスクトップのターミナルで実行
google-chrome

YouTubeで音声再生をサポートした状態で動画が再生されることを確認した。ただしRDP経由では音声の再生が安定せず、動画もカクカクと表示されることが多い。

image.png

chrome://gpuにアクセスするとGPUを利用せずソフトウェアレンダリングしていることがわかる

image.png

IncusコンテナでGPUをサポートする

GPUデバイスの追加

intelgpuという名前をつけてgpuデバイスをコンテナnobleに追加する。

ホストPCで実行する
incus config device add noble intelgpu gpu
incus config device add noble intelgpu gpuの出力
Device intelgpu added to noble

コンテナに追加したデバイスを確認する。

ホストPCで実行する
incus config device list noble
incus config device list nobleの出力
intelgpu

GPUデバイスのアクセス権限の確認

GPUにアクセスするための/dev/driを確認すると、card1renderD128のユーザIDとグループIDがどちらもrootとなっているため、ユーザubuntuからアクセスできないことが確認できる。

ホストPCで実行する
incus exec noble -- ls -la /dev/dri
incus exec noble -- ls -la /dev/dri/の出力
total 0
drwxr-xr-x 2 root root       80 Aug 27 01:56 .
drwxr-xr-x 9 root root      520 Aug 27 01:56 ..
crw-rw---- 1 root root 226,   1 Aug 27 01:56 card1
crw-rw---- 1 root root 226, 128 Aug 27 01:56 renderD128

GPUへのアクセス権限を解決しつつデバイスを追加

ホストPCで実行する
# 先ほど作成したGPUデバイスは一度削除する
incus config device remove noble intelgpu

# グループIDにvideoを指定してGPUデバイスを作成しなおす
incus config device add noble intelgpu gpu gid=`getent group video | cut -d: -f3`

# 作成したGPUデバイスへのアクセス権限を確認する
incus exec noble -- ls -l /dev/dri

videoグループに所属させれば/dev/dri以下へアクセス可能になる。

incus exec noble -- ls -l /dev/dri の出力
total 0
crw-rw---- 1 root video 226,   1 Aug 27 02:07 card1
crw-rw---- 1 root video 226, 128 Aug 27 02:07 renderD128

GPUへのアクセス権限を付与する

ホストPCで実行する
# ユーザ(ubuntu)をvideoグループに追加する
incus exec noble -- adduser ubuntu video

# videoグループに追加されたことを確認する
incus exec noble -- cat /etc/group | grep video

# コンテナをリスタートする
incus restart noble

GPUへのアクセスを確認する

glxinfoコマンドでIntelのGPUが利用可能であると確認できる。

コンテナで実行する
glxinfo | grep OpenGL
glxinfo | grep OpenGL の出力
OpenGL vendor string: Intel
OpenGL renderer string: Mesa Intel(R) Graphics (RPL-S)
OpenGL core profile version string: 4.6 (Core Profile) Mesa 24.0.9-0ubuntu0.1
OpenGL core profile shading language version string: 4.60
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile
OpenGL core profile extensions:
OpenGL version string: 4.6 (Compatibility Profile) Mesa 24.0.9-0ubuntu0.1
OpenGL shading language version string: 4.60
OpenGL context flags: (none)
OpenGL profile mask: compatibility profile
OpenGL extensions:
OpenGL ES profile version string: OpenGL ES 3.2 Mesa 24.0.9-0ubuntu0.1
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20
OpenGL ES profile extensions:

vainfoコマンドでIntelのGPUのハードウェアデコーダが利用可能だと確認できる

コンテナで実行する
sudo apt-get update
sudo apt-get install vainfo
vainfo
vainfoの出力
libva info: VA-API version 1.20.0
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/iHD_drv_video.so
libva info: Found init function __vaDriverInit_1_20
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.20 (libva 2.12.0)
vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 24.1.0 ()
vainfo: Supported profile and entrypoints
      VAProfileNone                   : VAEntrypointVideoProc
      VAProfileNone                   : VAEntrypointStats
      VAProfileMPEG2Simple            : VAEntrypointVLD
      VAProfileMPEG2Main              : VAEntrypointVLD
      VAProfileH264Main               : VAEntrypointVLD
      VAProfileH264Main               : VAEntrypointEncSliceLP
      VAProfileH264High               : VAEntrypointVLD
      VAProfileH264High               : VAEntrypointEncSliceLP
      VAProfileJPEGBaseline           : VAEntrypointVLD
      VAProfileJPEGBaseline           : VAEntrypointEncPicture
      VAProfileH264ConstrainedBaseline: VAEntrypointVLD
      VAProfileH264ConstrainedBaseline: VAEntrypointEncSliceLP
      VAProfileHEVCMain               : VAEntrypointVLD
      VAProfileHEVCMain               : VAEntrypointEncSliceLP
      VAProfileHEVCMain10             : VAEntrypointVLD
      VAProfileHEVCMain10             : VAEntrypointEncSliceLP
      VAProfileVP9Profile0            : VAEntrypointVLD
      VAProfileVP9Profile0            : VAEntrypointEncSliceLP
      VAProfileVP9Profile1            : VAEntrypointVLD
      VAProfileVP9Profile1            : VAEntrypointEncSliceLP
      VAProfileVP9Profile2            : VAEntrypointVLD
      VAProfileVP9Profile2            : VAEntrypointEncSliceLP
      VAProfileVP9Profile3            : VAEntrypointVLD
      VAProfileVP9Profile3            : VAEntrypointEncSliceLP
      VAProfileHEVCMain12             : VAEntrypointVLD
      VAProfileHEVCMain422_10         : VAEntrypointVLD
      VAProfileHEVCMain422_12         : VAEntrypointVLD
      VAProfileHEVCMain444            : VAEntrypointVLD
      VAProfileHEVCMain444            : VAEntrypointEncSliceLP
      VAProfileHEVCMain444_10         : VAEntrypointVLD
      VAProfileHEVCMain444_10         : VAEntrypointEncSliceLP
      VAProfileHEVCMain444_12         : VAEntrypointVLD
      VAProfileHEVCSccMain            : VAEntrypointVLD
      VAProfileHEVCSccMain            : VAEntrypointEncSliceLP
      VAProfileHEVCSccMain10          : VAEntrypointVLD
      VAProfileHEVCSccMain10          : VAEntrypointEncSliceLP
      VAProfileHEVCSccMain444         : VAEntrypointVLD
      VAProfileHEVCSccMain444         : VAEntrypointEncSliceLP
      VAProfileAV1Profile0            : VAEntrypointVLD
      VAProfileHEVCSccMain444_10      : VAEntrypointVLD
      VAProfileHEVCSccMain444_10      : VAEntrypointEncSliceLP

Chromeブラウザでchrome://gpuを開くことでGPUでのハードウェアアクセラレーションが有効になっていることが確認できる。

image.png

XRDPでリモート表示させる場合は転送速度が間に合わないためカクカク表示されるが、3Dベンチマークのレンダリングは50fp以上で行われていることが確認できる。
incus_gpu.gif

まとめ

ここまでの作業情報をまとめておく。

コンテナの起動

ホストPCで実行する
# コンテナの起動
incus launch images:ubuntu/24.04 noble

コンテナがネットワーク接続できない場合

デスクトップ環境の構築

ホストPCで実行する
# パッケージのインストール
incus exec noble -- apt-get update
incus exec noble -- apt-get upgrade -y
incus exec noble -- sudo apt-get install -y lubuntu-desktop openssh-server xrdp 

# ユーザとパスワードの設定
incus exec noble -- passwd ubuntu

# Chromeのインストール
incus exec noble -- wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
incus exec noble -- apt-get install -y ./google-chrome-stable_current_amd64.deb

# コンテナをリスタートする
incus restart noble

ポートフォワーディングの設定

ホストPCとコンテナのIPアドレスを確認する

ホストPCで実行する
# ホストPCのIPアドレス
ip a

# コンテナのIPアドレス
incus list
ホストPCで実行する
# IPアドレスを設定する
HOST_ADDRESS=192.168.1.113
CONTAINER_ADDRESS=10.107.73.126

# ネットワークフォワードを作成する 
incus network forward create incusbr0 ${HOST_ADDRESS}

# 転送先のコンテナのポート番号 (ssh)
incus network forward port add incusbr0 ${HOST_ADDRESS} tcp 10022 ${CONTAINER_ADDRESS} 22

# 転送先のコンテナのポート番号 (RDP)
incus network forward port add incusbr0 ${HOST_ADDRESS} tcp 13389 ${CONTAINER_ADDRESS} 3389

GPUを有効にする

ホストPCで実行する
# グループIDにvideoを指定してGPUデバイスを作成する
incus config device add noble intelgpu gpu gid=`getent group video | cut -d: -f3`

# ユーザ(ubuntu)をvideoグループに追加する
incus exec noble -- adduser ubuntu video

# コンテナをリスタートする
incus restart noble

# GPUでのハードウェアデコーダが有効であることを確認する
incus exec noble -- apt-get install -y vainfo
incus exec noble -- vainfo

GPUが有効であることを確認する

XRDPでログインしたコンテナのターミナルで実行する
# GPUが認識されていることを確認する
glxinfo | grep OpenGL

ダウンロードしたキャッシュを削除する

コンテナのターミナルで実行する
apt clean
rm -rf /var/lib/apt/lists/*

踏み台PC経由でSSHに接続する

クライアントPCからホストPC(192.168.1.113)を踏み台にコンテナ(10.107.73.63)のSSHサーバーに接続する。ホストPCでSSHサーバーが動作している必要があるが、ポートフォワーディングの設定が必要はない。

クライアントPCで実行
ssh -J raiko@192.168.1.113 ubuntu@10.107.73.63
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?