はじめに
これまで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
+-------+---------+----------------------+---------------------------------------------+-----------+-----------+
| 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
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
詳細は下記を参照のこと
コンテナにデスクトップ環境の構築する
デスクトップ環境のパッケージをコンテナにインストールする
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でコンテナに接続する環境を構築する
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
フォワーディングのポートを指定して接続する
ssh ubuntu@192.168.1.113 -p 10022
踏み台PC経由で接続する場合
クライアントPCからホストPC(192.168.1.113)を踏み台にコンテナ(10.107.73.63)のSSHサーバーに接続する。ホストPCでSSHサーバーが動作している必要があるが、ポートフォワーディングの設定が必要はない。
ssh -J raiko@192.168.1.113 ubuntu@10.107.73.63
トラブルシューティング
ssh
で接続できない場合にはssh
のステータスやログを確認する
# 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
拡張をインストールする。
SSH経由でコンテナに接続
公式リファレンス
VSCodeのリモートエクスプローラーを開いてのSSHの右にある➕
ボタンを押して、SSH経由でホストPCを踏み台にしてコンテナに接続する
sshでコンテナにログインする場合と同じコマンドを指定する
コンテナに接続するとVS Code Server
がコンテナに自動インストールされる
VS Code Server
がインストールされるとクライアントPCで動作しているVScode
からコンテナのファイルにリモート編集できるようになる。
XRDPでコンテナに接続する
XRDPでコンテナに接続する環境を構築する。
XRDPサーバ(xrdp)をコンテナにインストールする
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コンテナに接続する
Incusコンテナで動作するディスクトップを表示できた
踏み台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アプリでlocalhost
の3389
ポートに接続する。この接続はホストPCを経由してIncusコンテナのxrdpに接続する。
Incusコンテナのディスクトップを表示できた
トラブルシューティング
xrdp
に接続できない場合にはxrdp
のステータスやログを確認する
# xrdpのステータスを確認する
incus exec noble -- systemctl status xrdp
# xrdpのログを確認する
incus exec noble -- journalctl -u xrdp
コンテナでChromeブラウザを動作させる
Chromeインストール手順
リモートデスクトップ環境が構築されたコンテナ内に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
Chromeの動作確認
インストールが完了したらChromeを起動し正常に動作するか確認する。
google-chrome
YouTubeで音声再生をサポートした状態で動画が再生されることを確認した。ただしRDP経由では音声の再生が安定せず、動画もカクカクと表示されることが多い。
chrome://gpu
にアクセスするとGPUを利用せずソフトウェアレンダリングしていることがわかる
IncusコンテナでGPUをサポートする
GPUデバイスの追加
intelgpu
という名前をつけてgpu
デバイスをコンテナnoble
に追加する。
incus config device add noble intelgpu gpu
Device intelgpu added to noble
コンテナに追加したデバイスを確認する。
incus config device list noble
intelgpu
GPUデバイスのアクセス権限の確認
GPUにアクセスするための/dev/dri
を確認すると、card1
とrenderD128
のユーザIDとグループIDがどちらもroot
となっているため、ユーザubuntu
からアクセスできないことが確認できる。
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へのアクセス権限を解決しつつデバイスを追加
# 先ほど作成した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
以下へアクセス可能になる。
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へのアクセス権限を付与する
# ユーザ(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
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
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でのハードウェアアクセラレーションが有効になっていることが確認できる。
XRDPでリモート表示させる場合は転送速度が間に合わないためカクカク表示されるが、3Dベンチマークのレンダリングは50fp以上で行われていることが確認できる。
まとめ
ここまでの作業情報をまとめておく。
コンテナの起動
# コンテナの起動
incus launch images:ubuntu/24.04 noble
コンテナがネットワーク接続できない場合
デスクトップ環境の構築
# パッケージのインストール
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のIPアドレス
ip a
# コンテナのIPアドレス
incus list
# 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を有効にする
# グループ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が有効であることを確認する
# 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サーバーが動作している必要があるが、ポートフォワーディングの設定が必要はない。
ssh -J raiko@192.168.1.113 ubuntu@10.107.73.63