Containerlize gui apps with wayland

As we know, we can use host’s wayland socket to display container’s gui app.
overview-gui-inside-containers
So, why won’t we go farther, containerlize wayland compositor and gui apps in separate containers.

Please, do forgive my poor English, I don’t how to express this in English. What I want to say is like the image, “passthrough” display to container, so we will not mess up host environment, containerlizing gui apps, so the wayland compositor container environment will be relatively clean. For example, only the gui app container need to install gtk3.

Important thing first, we need install a wayland compositor in host, so we can use the wayland socket.
I’m using sway, you can choose anything you like.
I edited sway config like this to hide titlebar and swaybar, but you can skip:

~/.config/sway/config
default_border none
default_floating_border none
font pango:monospace 0
titlebar_padding 1
titlebar_border_thickness 0
#bar {
#    position top
    # When the status_command prints a new line to stdout, swaybar updates.
    # The default just shows the current date and time.
#    status_command while date +'%Y-%m-%d %I:%M:%S %p'; do sleep 1; done
#    colors {
#        statusline #ffffff
#        background #323232
#        inactive_workspace #32323200 #32323200 #5c5c5c
#    }
#}

Let’s say, I want firefox saves file in $HOME/Downloads, and not directly showing in host wayland compositor, and in a separate container. To do that the container istalled firefox must access $HOME/Downloads and $XDG_RUNTIME_DIR in wayland compositor container.
Thank to incus, we can mount a volume between containers, so we put $HOME and $XDG_RUNTIME_DIR in the volume,and problem solved.
Because I’m lazy, $XDG_RUNTIME_DIR will stay in $HOME. It will be better they are in separate volumes.

incus storage volume create default home --type=filesystem
incus profile create mount
incus profile edit mount
mount
config: {}
description: share volume between containers
devices:
  home:
    pool: default
    type: disk
    source: home
    path: /home/
    propagation: private
name: mount

And profile for wayland socket and gpu accelerate. By default, sway will create wayland-1 as wayland socket.

wayland
config: {}
description: Let containers use host display
devices:
  waylandSocket:
    type: proxy
    bind: container
    connect: unix:/run/user/1000/wayland-1
    listen: unix:/mnt/wayland-1
    mode: '0700'
    security.gid: '1000'
    security.uid: '1000'
    gid: '1000'
    uid: '1000'
  mygpu:
    type: gpu
    gid: '1000'
    uid: '1000'
name: wayland

So let’s create wayland compositor container. I’m using labwc, so it will call labwc.

incus launch images:alpine/3.19 labwc -p default -p wayland -p mount
incus exec labwc ash
apk update
apk upgrade
apk add mesa-dri-gallium labwc labwc-doc font-dejavu

Wayland won’t let root use gui, so create one called lxc.

adduser -s /bin/ash -g "lxc" lxc
adduser lxc video
adduser lxc input

It’s a wayland compositor thing, they need config before start. Alpine linux won’t auto set XDG_RUNTIME_DIR without seatd manager. And we need point it to use host(sway) wayland socket. Start labwc, and you will see a black screen with a cursor.

su -l lxc
mkdir -p ~/.config
cp -r /usr/share/doc/labwc/ ~/.config/
mkdir -pm 0700 ~/.run/
ln -s /mnt/wayland-1 /home/lxc/.run/wayland-1
export XDG_RUNTIME_DIR=/home/lxc/.run/
export WAYLAND_DISPLAY=wayland-1
labwc

Then gui app container. I’m using firefox, so it will call firefox.
Yes, same user, same uid, same $HOME, same $XDG_RUNTIME_DIR.
We use wayland-0(labwc wayland socket) this time, so firefox will show in container wayland compositor(labwc).

incus launch images:alpine/3.19 firefox -p default -p mount
apk update
apk upgrade
apk add font-dejavu firefox
adduser -s /bin/ash -g "lxc" lxc
su -l lxc
export XDG_RUNTIME_DIR=/home/lxc/.run/
export WAYLAND_DISPLAY=wayland-0
export MOZ_ENABLE_WAYLAND=1
firefox
2 Likes

Thanks for this and welcome!

(I cannot try it at the moment as I have both iGPU and NVidia, and Nvidia cannot get disabled through MB options.).

A tip, you can launch a images:alpine/3.19/cloud container, and you get for free a alpine non-root account.
Then, get a shell into that container with

incus exec myalpine -- su -l alpine 

If it’s convenient, you can make it an alias,

incus alias add alpine "exec @ARGS@ -- su -l alpine"

and finally

$ incus alpine myalpine
myalpine:~$

Thanks for the tip.

Wlroots is NVidia unfriendly.
So I write another way to do it. You don’t need to read above.

Host OS: debian 12
Host desktop environment: xfce4
Weston wayland compositor container OS: fedora 39
Container wayland compositor: weston
GUI app container OS: alpine 3.19
Container GUI app: firefox

This time, we will use X11 as a platform for cotainer wayland compositor. Because wayland compositor can run on top of X11. I’m sure any window managers or wayland compositors can be the platform.
There are a lot of wayland compositor, and I’ve only used wlroots based and weston.I will use weston this time. Weston is not suit for daily use, but enough for demonstration. You can use any wayland compositor you want.

config: {}
description: share home between containers
devices:
 home:
   pool: default
   type: disk
   source: home
   path: /home/
   propagation: private
name: home
config: {}
description: x11
devices:
  x11:
    bind: container
    connect: unix:@/tmp/.X11-unix/X0
    listen: unix:@/tmp/.X11-unix/X0
    security.gid: '1000'
    security.uid: '1000'
    type: proxy
name: x11
incus launch images:fedora/39 weston -p default -p home -p x11
incus exec weston bash
dnf update
dnf install weston weston-demo
useradd -m -G video -s /bin/bash lxc
su -l lxc
mkdir -pm 0700 ~/.run/
export XDG_RUNTIME_DIR=/home/lxc/.run/
export DISPLAY=:0
weston

I tried separate $XDG_RUNTIME_DIR in another volume. But in another container, $XDG_RUNTIME_DIR will belong to root, and after chown to 1000, it became empty.

incus launch images:alpine/3.19 firefox -p default -p home
incus exec firefox ash
apk update
apk upgrade
apk add font-dejavu firefox
adduser -s /bin/ash -g "lxc" lxc
su -l lxc
export XDG_RUNTIME_DIR=/home/lxc/.run/
export WAYLAND_DISPLAY=wayland-1
export MOZ_ENABLE_WAYLAND=1
firefox

Firefox will crush immediately after showing in weston, but it’s not relevant about what we do.

(crashreporter:888): Gtk-WARNING **: 06:51:14.730: Could not load a pixbuf from /org/gtk/libgtk/theme/Adwaita/assets/check-symbolic.svg.
This may indicate that pixbuf loaders or the mime database could not be found.
1 Like

Can we do this for the pipewire too?

Pipewire also has a Unix socket. Search the forum for pipewire to get the exact fragment to put into the Incus profile.

Yes, it’s in this post: https://discuss.linuxcontainers.org/t/a-detail-step-to-run-desktop-environment-in-container/