1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LXD で作る仮想化 GUI 環境 - Ubuntu 26.04 LTS 版

1
Posted at

概要

下記の記事を参考にして、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をインストールします。

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]:
後からIPv6を無効にする場合
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 以外の場合はそこも変更してください。

gui-main-wl.yaml
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 の gpu device は、コンテナ内にデバイスノードを作成して UID/GID を設定するため、shift は不要のようです
  • NVIDIA の場合は、ホストに公式ドライバと libnvidia-container 系を導入し、nvidia.runtime: "true" と nvidia.driver.capabilities: all を追加すると良いようです(機器がないため未検証)

X11 アプリが必要なときの構成

DISPLAY の番号はホストで echo $DISPLAY を確認してください。

gui-xwl.yaml
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アプリを動かせるコンテナを作成(基本)

やりやすいようにコンテナ名を変数に入れる。

ホスト名 gui-wl1
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

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?