Previous Post | Top | Next Post |
TOC
Here is a series of memos of me trying to use LXC/LXD on Debian 12 (bookworm
).
Running GUI application in container
Unlike console applications, running GUI applications in container is a bit complicate. For now, I found some HOWTOs:
- Incus / LXD profile for GUI apps: Wayland, X11 and Pulseaudio (2023-11-17)
- Use Wayland and Xorg applications (updated 2023-10-07)
- LXD Containers for Wayland GUI Apps (2022-08-28)
- How to run GUI apps in LXD containers (2022-08-04)
- HOWTO: Use the Host’s Wayland and XWayland Servers inside containers (updated 2022-03-18)
- GUI application via Wayland from Ubuntu LXD container on Arch Linux host (2018-01-01)
All these interesting references are not always using GNOME wayland under the Debian bookworm environment.
Also, there are subtle differences.
# | Wayland | X11 | PulseA | PipeW | GPU | Note |
---|---|---|---|---|---|---|
1 | disk | disk | disk | — | Yes | |
2 | proxy | proxy | — | — | Yes | |
3.1 | proxy | — | — | — | — | basic |
3.2 | disk | — | — | — | — | for browsers |
3.3 | disk | — | proxy | — | — | for audio |
4 | proxy | — | — | — | — | |
5 | proxy | proxy | — | — | Yes | Xwayland |
6 | disk | disk | — | — | Yes | share /run/user/1000 |
It seems that the use of the disk
device has some advantages.
I will try similar things as above references using GNOME Wayland under the Debian bookworm environment in the followings.
YAML setting for profile=default
Let’s see the default LXD profile:
$ lxc profile show default
config: {}
description: Default LXD profile
devices:
eth0:
name: eth0
network: lxdbr0
type: nic
root:
path: /
pool: default
type: disk
name: default
used_by:
- /1.0/instances/d0
- /1.0/instances/d1
- /1.0/instances/d2
The last list for key=used_by
changes as I use this profile.
Unless this list is empty, profile can’t be deleted.
User specific sockets used by IPC
For my primary user (name=osamu
, UID=1000
) on the host system running
Debian 12 bookworm with GNOME wayland, I see following user accessible sockets under /run/user/
and /tmp
:
$ ls -l $(find /run/user -type s 2>/dev/null)
srwxrwxrwx 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/at-spi/bus
srw-rw-rw- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/bus
srw-rw-rw- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/gcr/ssh
srw------- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/gnupg/S.dirmngr
srw------- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/gnupg/S.gpg-agent
srw------- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/gnupg/S.gpg-agent.browser
srw------- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/gnupg/S.gpg-agent.extra
srw------- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/gnupg/S.gpg-agent.ssh
srw-rw-rw- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/keyring/control
srwxr-xr-x 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/keyring/pkcs11
srw------- 1 osamu osamu 0 Nov 25 07:14 /run/user/1000/keyring/.ssh
srwxr-xr-x 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/keyring/ssh
srwxrwxr-x 1 osamu osamu 0 Nov 25 07:47 /run/user/1000/nvim.11027.0
srw------- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/openssh_agent
srw-rw-rw- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/pipewire-0
srw-rw-rw- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/pk-debconf-socket
srw-rw-rw- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/pulse/native
srw-rw-rw- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/snapd-session-agent.socket
s--------- 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/systemd/inaccessible/sock
srwxr-xr-x 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/systemd/notify
srwx------ 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/systemd/private
srwxr-xr-x 1 osamu osamu 0 Nov 25 07:13 /run/user/1000/wayland-0
$ ls -l $(find /tmp -type s 2>/dev/null)
srwxr-xr-x 1 osamu osamu 0 Nov 25 07:15 /tmp/.com.google.Chrome.0JD6Mr/SingletonSocket
srwxrwxrwx 1 Debian-gdm Debian-gdm 0 Nov 25 07:13 /tmp/.ICE-unix/1847
srwxrwxrwx 1 osamu osamu 0 Nov 25 07:13 /tmp/.ICE-unix/2702
srwxr-xr-x 1 osamu osamu 0 Nov 25 07:13 /tmp/.X11-unix/X0
srwxr-xr-x 1 osamu osamu 0 Nov 25 07:13 /tmp/.X11-unix/X1
srwxr-xr-x 1 Debian-gdm Debian-gdm 0 Nov 25 07:13 /tmp/.X11-unix/X1024
srwxr-xr-x 1 Debian-gdm Debian-gdm 0 Nov 25 07:13 /tmp/.X11-unix/X1025
Let me check further who uses X sockets while running GNOME desktop on Wayland.
$ lsof -U |grep -e '[^@]/tmp/\.X11-unix/'
gnome-she 2733 osamu 45u unix 0x0000000061b9b072 0t0 38083 /tmp/.X11-unix/X1 type=STREAM (LISTEN)
Xwayland 3244 osamu 5u unix 0x000000005899b02d 0t0 38081 /tmp/.X11-unix/X0 type=STREAM (LISTEN)
$ ps aux |grep '\(273[3]\|324[4]\)'
osamu 2733 3.1 0.9 5187384 299252 ? Ssl 07:12 1:04 /usr/bin/gnome-shell
osamu 3244 0.3 0.3 788556 123388 ? Sl 07:12 0:07 /usr/bin/Xwayland :0 -rootless -noreset -accessx -core -auth /run/user/1000/.mutter-Xwaylandauth.VC1EF2 -listenfd 4 -listenfd 5 -displayfd 6 -initfd 7
So the monitor screen is accessed as /run/user/1000/wayland-0
from Wayland on
my environment.
If sound needs to be accessed, sockets such as /run/user/1000/pipewire-0
may
be needed. If X program needs to be accessed, sockets such as
/tmp/.X11-unix/X0
may be needed.
I will address these more complex cases later. For now, let me focus on to use
wayland-0
socket.
YAML to allow display to Wayland using extra disk device
Here is a simple YAML data example (wayland.yaml
) to add disk
device for
the Wayland socket.
config:
boot.autostart: false
raw.idmap: both 1000 1000
user.user-data: |
#cloud-config
users:
- name: osamu
lock_passwd: True
groups: [adm, audio, cdrom, dialout, dip, floppy, plugdev, sudo, video]
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
shell: /bin/bash
write_files:
- path: /usr/local/bin/mystartup.sh
permissions: 0755
content: |
#!/bin/sh
uid=$(id -u)
run_dir=/run/user/$uid
mkdir -p $run_dir && chmod 700 $run_dir && chown $uid:$uid $run_dir
ln -sf /mnt/runuser/wayland-0 $run_dir/wayland-0
- path: /usr/local/etc/mystartup.service
content: |
[Unit]
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/mystartup.sh
[Install]
WantedBy=default.target
runcmd:
- mkdir -p /home/osamu/.config/systemd/user/default.target.wants
- ln -s /usr/local/etc/mystartup.service /home/osamu/.config/systemd/user/default.target.wants/mystartup.service
- ln -s /usr/local/etc/mystartup.service /home/osamu/.config/systemd/user/mystartup.service
- chown -R osamu:osamu /home/osamu
- echo 'export WAYLAND_DISPLAY=wayland-0' >> /home/osamu/.profile
description: Wayland LXD profile
devices:
eth0:
name: eth0
network: lxdbr0
type: nic
root:
path: /
pool: default
type: disk
wayland-0:
source: /run/user/1000/wayland-0
path: /mnt/runuser/wayland-0
type: disk
Here, raw.idmap: both 1000 1000
ensures permissions of
/mnt/runuser/wayland-0
is matches with the host to offer R/W access from
osamu
UID=1000
.
The mystartup.sh
script in user.user-data
is generated and applied when
cloud-init
applies user.user-data
at the first boot of the instance to set
up systemd startup script. This startup script links the Wayland socket to its
usual location in the container (/run/user/1000/wayland-0
) every time when the
primary user osamu
logs in.
Running Wayland GUI application eog
in container
Let me first create a profile wayland
:
$ lxc profile create wayland
$ lxc profile edit wayland < wayland.yaml
$ lxc profile ls
+---------+---------------------+---------+
| NAME | DESCRIPTION | USED BY |
+---------+---------------------+---------+
| default | Default LXD profile | 3 |
+---------+---------------------+---------+
| wayland | Wayland LXD profile | 0 |
+---------+---------------------+---------+
Let me start wayland
instance with wayland
profile
$ lxc launch images:debian/12/cloud wayland --profile wayland
Let me inspect this instance. (We need to expand to see effective configuration settings.)
$ lxc config show wayland -e
architecture: x86_64
config:
boot.autostart: "false"
image.architecture: amd64
image.description: Debian bookworm amd64 (20231124_05:24)
image.os: Debian
image.release: bookworm
image.serial: "20231124_05:24"
image.type: squashfs
image.variant: cloud
raw.idmap: both 1000 1000
user.user-data: |
#cloud-config
users:
- name: osamu
lock_passwd: True
groups: [adm, audio, cdrom, dialout, dip, floppy, plugdev, sudo, video]
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
shell: /bin/bash
write_files:
- path: /usr/local/bin/mystartup.sh
permissions: 0755
content: |
#!/bin/sh
uid=$(id -u)
run_dir=/run/user/$uid
mkdir -p $run_dir && chmod 700 $run_dir && chown $uid:$uid $run_dir
ln -sf /mnt/runuser/wayland-0 $run_dir/wayland-0
- path: /usr/local/etc/mystartup.service
content: |
[Unit]
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/mystartup.sh
[Install]
WantedBy=default.target
runcmd:
- mkdir -p /home/osamu/.config/systemd/user/default.target.wants
- ln -s /usr/local/etc/mystartup.service /home/osamu/.config/systemd/user/default.target.wants/mystartup.service
- ln -s /usr/local/etc/mystartup.service /home/osamu/.config/systemd/user/mystartup.service
- chown -R osamu:osamu /home/osamu
- echo 'export WAYLAND_DISPLAY=wayland-0' >> /home/osamu/.profile
volatile.base_image: 03e51acc22a673de40cf411923bebc3215bea394cf828cafabb6b61925fd722f
volatile.cloud-init.instance-id: 731cdfd7-9f7e-4e76-a900-9c53b6caf3ba
volatile.eth0.host_name: veth1db326cc
volatile.eth0.hwaddr: 00:16:3e:d9:a7:2a
volatile.idmap.base: "0"
volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":231072,"Nsid":0,"Maprange":1000},{"Isuid":true,"Isgid":true,"Hostid":1000,"Nsid":1000,"Maprange":1},{"Isuid":true,"Isgid":false,"Hostid":232073,"Nsid":1001,"Maprange":9999000},{"Isuid":false,"Isgid":true,"Hostid":231072,"Nsid":0,"Maprange":1000},{"Isuid":true,"Isgid":true,"Hostid":1000,"Nsid":1000,"Maprange":1},{"Isuid":false,"Isgid":true,"Hostid":232073,"Nsid":1001,"Maprange":9999000}]'
volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":231072,"Nsid":0,"Maprange":1000},{"Isuid":true,"Isgid":true,"Hostid":1000,"Nsid":1000,"Maprange":1},{"Isuid":true,"Isgid":false,"Hostid":232073,"Nsid":1001,"Maprange":9999000},{"Isuid":false,"Isgid":true,"Hostid":231072,"Nsid":0,"Maprange":1000},{"Isuid":true,"Isgid":true,"Hostid":1000,"Nsid":1000,"Maprange":1},{"Isuid":false,"Isgid":true,"Hostid":232073,"Nsid":1001,"Maprange":9999000}]'
volatile.last_state.idmap: '[]'
volatile.last_state.power: RUNNING
volatile.uuid: 514a4bb8-aa7d-4b33-b76e-feb8d9d3f3c8
devices:
eth0:
name: eth0
network: lxdbr0
type: nic
root:
path: /
pool: default
type: disk
wayland-0:
path: /mnt/runuser/wayland-0
source: /run/user/1000/wayland-0
type: disk
ephemeral: false
profiles:
- wayland
stateful: false
description: ""
Now, we can see full contents of user.user_data:
and devices:
.
This user.user_data:
YAML data is passed to cloud-init
to create files and
execute commands as the container starts.
$ lxc exec wayland -- apt install eog
$ lxc exec wayland -- sudo -u osamu -i eog
This container environment allowed me to run an Wayland GUI program eog
in
container and displaying its result to the host GNOME Desktop. Nice.
Running Wayland GUI application firefox
in container using disk device
I installed and tried the firefox-esr
package.
Then started firefox
:
$ lxc exec wayland -- apt install firefox-esr
$ lxc exec wayland -- sudo -u osamu -i firefox
[GFX1-]: glxtest: libpci missing
This can be fixed by installing libpci3
package (some web
article
implies to install libpci-dev
which installs more packages in addition to
libpci3
as a cure.):
$ lxc exec wayland -- apt install libpci3
$ lxc exec wayland -- sudo -u osamu -i firefox
Normally, pciutils
package which has “priority: standard” is installed and
pulls in libpci3
. But firefox-esr
doesn’t list libpci3
explicitly as
Depends:
nor Recommends:
. I suppose this is a
bug.
Previous Post | Top | Next Post |