概要
下記の記事を参考にして、LXDを使用したGUI隔離環境の実践例と応用の手法を記載します。
以前 22.04 用のものを作成しましたが、今回は 26.04 版となります。
基本的に色々なところから持ってきた手順を切った貼ったした感じのドキュメントになります。
まだ未完成のため、後日、追加・訂正予定です。
注意事項
- このドキュメントはまだ不十分です
- 特に以下については検証が不十分です
-
XWaylandによるX11環境の利用 - NVIDIAのGPUの利用
-
検証環境
- OS: Ubuntu 26.04 LTS AMD64
基本構成
- Wayland もしくは XWayland によるX11互換環境
- 音声は
pipewire-pulseによるpulseaudio互換レイヤーを使用 - 日本語入力対応
| 用途 | 渡すもの | 方式 |
|---|---|---|
| Wayland 表示 | /run/user/1000/wayland-0 |
disk |
| XWayland |
/tmp/.X11-unix/X0 と認証クッキー |
disk |
| 音声 | ホストの pipewire-pulse ソケット(pulse/native) |
disk |
| 日本語入力 | ホストの IME を Wayland の text-input 経由で利用 | 追加のデバイスは不要 |
設計上のポイント
-
すべての disk device に
shift: "true"を付けます。 ただし共有するのは、ソケットと認証ファイル用ディレクトリだけです。セキュリティのため共有は最低限にします。書き込みはホストの UID 1000 の権限で行われます - ソケットは
/mnt配下にマウントします。 - 音声はホストの
pipewire-pulseによる互換レイヤーにPulseAudioクライアントとして接続します
LXDをインストールします。
$ sudo snap install lxd
$ sudo lxd init
Would you like to use LXD clustering? (yes/no) [default=no]:
Do you want to configure a new storage pool? (yes/no) [default=yes]:
Name of the new storage pool [default=default]:
Name of the storage backend to use (btrfs, dir, lvm, zfs, ceph) [default=zfs]: btrfs
Create a new BTRFS pool? (yes/no) [default=yes]:
Would you like to use an existing empty block device (e.g. a disk or partition)? (yes/no) [default=no]:
Size in GB of the new loop device (1GB minimum) [default=30GB]: 64GB
Would you like to connect to a MAAS server? (yes/no) [default=no]:
Would you like to create a new local network bridge? (yes/no) [default=yes]:
What should the new bridge be called? [default=lxdbr0]:
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: none
Would you like the LXD server to be available over the network? (yes/no) [default=no]:
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:
lxc network set lxdbr0 ipv6.address none
通常使用するユーザーがlxdグループに追加されているか確認して、ホストの再起動を行ってください。
また、UFW を導入している場合、LXD が用意してくれるブリッジである lxdbr0 を介しての通信を許可します。以下は ufw での例です。
sudo ufw allow in on lxdbr0
sudo ufw route allow in on lxdbr0
事前準備
準備としてホスト側の設定を変更します。
# idmapped mounts に対応しているかを確認
lxc info | grep -E 'idmapped_mounts|shiftfs'
uname -a
# XWayland の認証クッキー変換用(X11互換用)
sudo apt install xauth
# 認証ファイルを置くディレクトリ(存在しないとコンテナの作成に失敗する)
mkdir -p ~/lxd-gui/auth && chmod 700 ~/lxd-gui/auth
# 音声サーバーの確認
wpctl status # PipeWire 側の状態を確認
ls -l /run/user/1000/pulse/native /run/user/1000/wayland-0 # 存在することを確認
wpctl statusの内容は概ね以下の内容になっているはずです
PipeWire 'pipewire-0'
└─ Clients:
33. WirePlumber
38. WirePlumber [export]
39. pipewire
プロファイルについて
設定を簡単に行えるようにするため、プロファイルを作成します。
これにより、基本設定はほぼ自動で行えるようになりました。
プロファイルは2つに分けます。
| プロファイル名 | 用途 | 主な設定 |
|---|---|---|
gui-main-wl |
Wayland 専用の基本構成 | GPU、Wayland ソケット、pulse ソケット、認証ファイル用ディレクトリ |
gui-xwl |
X11 アプリが必要なときだけ追加 | X11 ソケット、DISPLAY などの環境変数 |
X11 が不要なコンテナには gui-xwl を使用しません。これにより、Wayland 専用構成となります。
プロファイルの作成
Waylandネイティブ構成 (Wayland + GPU + 音声 + 日本語)
<<<HOST_USER>>> はホストのユーザー名に置き換えます。UID が 1000 以外の場合はそこも変更してください。
name: gui-main-wl
description: Wayland and pipewire-pulse
config:
security.idmap.isolated: "true"
environment.LANG: ja_JP.UTF-8
environment.XDG_RUNTIME_DIR: /run/user/1000
environment.XDG_SESSION_TYPE: wayland
environment.WAYLAND_DISPLAY: /mnt/wayland-socket
environment.PULSE_SERVER: unix:/mnt/pulse-native
environment.PULSE_COOKIE: /mnt/auth/pulse-cookie
environment.DBUS_SESSION_BUS_ADDRESS: unix:path=/run/user/1000/bus
environment.GDK_BACKEND: wayland
environment.QT_QPA_PLATFORM: wayland
environment.SDL_VIDEODRIVER: wayland
environment.MOZ_ENABLE_WAYLAND: "1"
environment.ELECTRON_OZONE_PLATFORM_HINT: wayland
user.user-data: |
#config
package_update: true
packages:
- language-pack-ja
- fonts-noto-cjk
- mesa-utils
- mesa-vulkan-drivers
- vulkan-tools
- pulseaudio-utils
- wayland-utils
- qt6-wayland
- dbus-user-session
write_files:
- path: /etc/tmpfiles.d/lxd-gui.conf
content: |
d /tmp/.X11-unix 1777 root root -
L+ /tmp/.X11-unix/X0 - - - - /mnt/x11-socket
- path: /etc/pulse/client.conf.d/lxd.conf
content: |
enable-shm = no
runcmd:
- locale-gen ja_JP.UTF-8
- loginctl enable-linger ubuntu
- systemd-tmpfiles --create
devices:
gpu:
type: gpu
uid: "1000"
gid: "1000"
wayland:
type: disk
source: /run/user/1000/wayland-0
path: /mnt/wayland-socket
shift: "true"
required: "false"
pulse:
type: disk
source: /run/user/1000/pulse/native
path: /mnt/pulse-native
shift: "true"
required: "false"
auth:
type: disk
source: /home/<<<HOST_USER>>>/lxd-gui/auth
path: /mnt/auth
shift: "true"
readonly: "true"
-
security.idmap.isolated: "true"は、コンテナごとに別の ID レンジを割り当てる強化設定です。LXD の UID/GID の範囲に余裕があることを確認してください(通常は問題ないはず) - X11 用のシンボリックリンク(tmpfiles)は
gui-main-wlプロファイルに入れています。user.user-dataはプロファイルを重ねると後のもので丸ごと上書きされるためです。gui-xwlプロファイルを使わない場合、リンクは未使用のままで問題はありません -
WAYLAND_DISPLAYは絶対パス指定です。アプリが受け付けない場合は、/mnt/wayland-socketを/run/user/1000/wayland-0へシンボリックリンクして、変数をwayland-0に戻します - GPU の
gpudevice は、コンテナ内にデバイスノードを作成して UID/GID を設定するため、shift は不要のようです - NVIDIA の場合は、ホストに公式ドライバと
libnvidia-container系を導入し、nvidia.runtime: "true"とnvidia.driver.capabilities: allを追加すると良いようです(機器がないため未検証)
X11 アプリが必要なときの構成
DISPLAY の番号はホストで echo $DISPLAY を確認してください。
name: gui-xwl
description: XWayland を使う X11 アプリ用の追加プロファイル
config:
environment.DISPLAY: :0
environment.XAUTHORITY: /mnt/auth/Xauthority
environment.GDK_BACKEND: wayland,x11
environment.QT_QPA_PLATFORM: wayland;xcb
environment.ELECTRON_OZONE_PLATFORM_HINT: auto
devices:
x11:
type: disk
source: /tmp/.X11-unix/X0
path: /mnt/x11-socket
shift: "true"
required: "false"
GUIアプリを動かせるコンテナを作成(基本)
やりやすいようにコンテナ名を変数に入れる。
LXCNAME=gui-wl1
コンテナの作成
プロファイルのuser.user-data:部分については、最初のlxc launchコマンドの際にしか実行されない仕様となっています。
# プロファイルの読み込み
lxc profile create gui-main-wl
lxc profile edit gui-main-wl < gui-main-wl.yaml
lxc profile create gui-xwl # X11 も使用する場合のみ
lxc profile edit gui-xwl < gui-xwl.yaml # X11 も使用する場合のみ
# Wayland のみ
lxc launch ubuntu:26.04 $LXCNAME -p default -p gui-main-wl
# X11 も使う場合
lxc launch ubuntu:26.04 $LXCNAME -p default -p gui-main-wl -p gui-xwl
# プロファイルの user.user-data(cloud-init)による設定作業は、
# コンテナ起動後にバックグラウンドで進むため、その完了を待つ。
lxc exec $LXCNAME -- cloud-init status --wait
# 再起動
lxc exec $LXCNAME -- sh -c "reboot"
# コンテナの自動起動を停止
lxc config set $LXCNAME boot.autostart false
lxc exec $LXCNAME -- sh -c "reboot"
起動用スクリプト
#!/bin/sh
# ~/.local/bin/lxd-run 使い方: ~/.local/bin/lxd-run <<コンテナ名>> code
set -eu
c="$1"; shift
d="$HOME/lxd-gui/auth"
umask 077
# 対象コンテナが起動しているか確認
status=$(lxc list --format csv -c s "^${c}$")
if [ "$status" != "RUNNING" ]; then
lxc start "${c}"
lxc exec "${c}" -- cloud-init status --wait
status=$(lxc list --format csv -c s "^${c}$")
if [ "$status" != "RUNNING" ]; then
notify-send "Failed to start \"${c}\" container"
exit 1
fi
fi
# XWayland のクッキー(gui-xwayland を使う場合に必要。ファイル名はログインごとに変わる)
if [ -n "${XAUTHORITY:-}" ] && [ -n "${DISPLAY:-}" ]; then
: > "$d/Xauthority"
xauth -f "$XAUTHORITY" nlist "$DISPLAY" | sed -e 's/^..../ffff/' \
| xauth -f "$d/Xauthority" nmerge - 2>/dev/null || true
fi
# PulseAudio のクッキー(サーバーが要求する場合のみ使われる)
[ -f "$HOME/.config/pulse/cookie" ] && cp "$HOME/.config/pulse/cookie" "$d/pulse-cookie"
# 起動
exec lxc exec "$c" --user 1000 --group 1000 --cwd /home/ubuntu \
--env HOME=/home/ubuntu -- "$@"
確認手順(この順番で 1 つずつ)
# shift が効いているか
lxc exec $LXCNAME -- stat -c '%U(%u) %a %n' /mnt/wayland-socket /mnt/pulse-native /mnt/auth
# ubuntu(1000) と表示されれば OK。nobody(65534) なら shift が効いていない
# Wayland
~/.local/bin/lxd-run $LXCNAME wayland-info | head
# 音声
~/.local/bin/lxd-run $LXCNAME pactl info # "サーバー名: PulseAudio (on PipeWire )" と表示される
~/.local/bin/lxd-run $LXCNAME paplay /usr/share/sounds/freedesktop/stereo/bell.oga # 要 sound-theme-freedesktop
# GPU
~/.local/bin/lxd-run $LXCNAME glxinfo -B # llvmpipe でなく実 GPU か
~/.local/bin/lxd-run $LXCNAME vulkaninfo --summary
# XWayland でのテストGUIアプリ動作(別のアプリで行うなら不要)
lxc exec $LXCNAME -- apt install -y x11-apps
~/.local/bin/lxd-run $LXCNAME xeyes
# ホスト側から見て、コンテナのプロセスがホストの UID 1000 でないこと
ps -eo uid,cmd | grep -E 'xeyes|code' | grep -v grep # 1000000 番台などであれば大丈夫
実際にコンテナでGUIアプリを動作
今回はgoogle-chromeとVScodeを動作させます。
あらかじめ、コンテナにそれぞれをインストールします。
起動引数・環境変数
起動時にうまく動作しない場合、下記の引数を入れると改善する場合がある
| 引数・環境変数 | 役割 |
|---|---|
--ozone-platform=wayland |
Wayland を強制。接続できなければ起動失敗するため検証に最適 |
--ozone-platform-hint=auto |
環境に応じて自動選択(強制はしない) |
ELECTRON_OZONE_PLATFORM_HINT=wayland |
環境変数版。gui-base で設定済み(gui-xwayland を重ねると auto) |
--enable-features=WaylandWindowDecorations |
Wayland のウィンドウ装飾を有効化 |
--enable-wayland-ime |
日本語入力(text-input)を使う場合。バージョンと IME 側の対応に依存 |
--enable-features=UseOzonePlatform は現在の Electron では不要です。
起動
# google-chrome
~/.local/bin/lxd-run gui-vm01 google-chrome --ozone-platform=wayland --enable-features=WaylandWindowDecorations
# VS Code(MS公式リポジトリのdeb版)
~/.local/bin/lxd-run gui-vm01 code --ozone-platform=wayland --enable-features=WaylandWindowDecorations
AppImage形式
下記をインストールすれば動作するはずだが、動作しないアプリもあります。
lxc exec $LXCNAME -- sh -c "apt update && apt install fuse"
kritaを動作させてみる。
~/.local/bin/lxd-run gui-wl /home/ubuntu/bin/krita-6.0.4-x86_64.AppImage --ozone-platform=wayland
このため、いったん解凍して直接動作させます。
# 予めコンテナ内で解凍操作を実行
./krita-6.0.4-x86_64.AppImage --appimage-extract
# ホストから実行
~/.local/bin/lxd-run gui-wl /home/ubuntu/bin/squashfs-root/AppRun --ozone-platform=wayland
ホストのディレクトリをmountしたい場合
予めホストに/home/subdisk/lxc-share/krita-shaを作成し、
ゲストに/home/ubuntu/share-kritacl1を作成します。
その後マウント設定を追加します。このときshift=trueを忘れないようにしてください。
lxc config device add gui-wl1 share-dir disk source=/home/subdisk/lxc-share/krita-sha path=/home/ubuntu/share-kritacl1 shift=true
lxc config show gui-wl1
日本語入力
基本的にWayland ネイティブのアプリはホストの IME を使います
- GNOME(Mutter)側が ibus と連携するため、Wayland クライアントは text-input プロトコル経由で入力できます。コンテナ内に IME デーモンは不要です。ホストに
ibus-mozcを導入し、切り替えもホスト側で行います -
GTK_IM_MODULE、QT_IM_MODULE、XMODIFIERSは設定しなくても良いようです - Qt アプリは
qt6-waylandを入れます - フォントとロケールは、プロファイルの
fonts-noto-cjkとLANGで対応します
XWayland アプリで日本語入力が必要な場合
コンテナ内に IME が必要です。
lxc exec gui-xwl -- apt install -y fcitx5 fcitx5-mozc fcitx5-frontend-gtk3 fcitx5-frontend-qt5
# X11 専用の起動ラッパーだけで環境変数を設定する(プロファイル全体には入れない)
lxd-run gui-xwl env GDK_BACKEND=x11 QT_QPA_PLATFORM=xcb \
GTK_IM_MODULE=fcitx QT_IM_MODULE=fcitx XMODIFIERS=@im=fcitx \
sh -c 'fcitx5 -d; exec <アプリ>'
今後の予定
- 各アプリの起動時の注意点についてまとめる
- 複数のコンテナが動作するため
apt-cacher-ngを入れる
参考URL
https://www.fixes.pub/program/417137.html
http://bluearth.cocolog-nifty.com/blog/2020/04/post-8db9b1.html
https://astherier.com/blog/2020/08/install-fcitx-mozc-on-wsl2-ubuntu2004/
https://blog.goo.ne.jp/cinemaesprit/e/8805efd176e54a131c57bdb98c3a8b15
https://zenn.dev/tantan_tanuki/articles/7796a4f1d6d1b0
https://postgresweb.com/ubuntu-20-04-japanese
https://www.linux-setting.tokyo/2021/11/ubuntu-2110-impish-indri-ibus-mozc.html
https://matoken.org/blog/2019/07/19/direct-access-to-https-repository-with-apt-cacher-ng/
https://gihyo.jp/admin/serial/01/linux_containers/0015
https://matoken.org/blog/2019/07/19/direct-access-to-https-repository-with-apt-cacher-ng/
https://wiki.ubuntu.com/JammyJellyfish/ReleaseNotes/Ja
https://gihyo.jp/admin/clip/01/ubuntu-topics/202204/22
https://gihyo.jp/admin/serial/01/ubuntu-recipe/0717
https://gihyo.jp/admin/serial/01/ubuntu-recipe/0689
https://www.server-world.info/query?os=Ubuntu_22.04&p=japanese
https://gihyo.jp/admin/serial/01/ubuntu-recipe/0520