Copied from my thread over in the WSLg GitHub discussions.
Let’s begin by taking a look at all the processes, from the top, running when I log into my normal WSL session:
init-+-dbus-daemon | |
|-init(mnt,pid,uts)-+-init---unshare(mnt)---systemd(pid)-+-atd | |
| | |-automount---3*[{automount}] | |
| | |-colord(mnt)---2*[{colord}] | |
| | |-cupsd---{cupsd} | |
| | |-daemon.start(mnt)---lxd-+-dnsmasq | |
| | | `-18*[{lxd}] | |
| | |-dbus-daemon | |
| | |-lxcfs(mnt)---2*[{lxcfs}] | |
| | |-msmtpd(mnt) | |
| | |-polkitd---2*[{polkitd}] | |
| | |-rpcbind | |
| | |-rsyslogd---3*[{rsyslogd}] | |
| | |-snapd---14*[{snapd}] | |
| | |-systemd-+-(sd-pam) | |
| | | |-dbus-daemon | |
| | | |-emacs---{emacs} | |
| | | |-gnome-keyring-d---3*[{gnome-keyring-d}] | |
| | | |-gvfs-afc-volume---3*[{gvfs-afc-volume}] | |
| | | |-gvfs-goa-volume---2*[{gvfs-goa-volume}] | |
| | | |-gvfs-gphoto2-vo---2*[{gvfs-gphoto2-vo}] | |
| | | |-gvfs-mtp-volume---2*[{gvfs-mtp-volume}] | |
| | | |-gvfs-udisks2-vo---3*[{gvfs-udisks2-vo}] | |
| | | |-gvfsd---2*[{gvfsd}] | |
| | | |-gvfsd-fuse---5*[{gvfsd-fuse}] | |
| | | |-kbfsfuse---14*[{kbfsfuse}] | |
| | | |-keybase---15*[{keybase}] | |
| | | |-keybase-redirec---10*[{keybase-redirec}] | |
| | | |-tmux: server---zsh | |
| | | |-tracker-miner-f---6*[{tracker-miner-f}] | |
| | | |-zsh---gitstatusd-linu---8*[{gitstatusd-linu}] | |
| | | |-zsh---zsh | |
| | | `-zsh | |
| | |-systemd-journal | |
| | |-systemd-logind(mnt,uts) | |
| | |-systemd-machine(uts) | |
| | |-systemd-network(mnt) | |
| | |-systemd-resolve(mnt) | |
| | |-systemd-socket- | |
| | |-systemd-timesyn(mnt,uts)---{systemd-timesyn} | |
| | |-systemd-udevd(mnt,uts) | |
| | |-tor(mnt) | |
| | |-udisksd---4*[{udisksd}] | |
| | |-unattended-upgr---{unattended-upgr} | |
| | |-upowerd(mnt,user)---2*[{upowerd}] | |
| | |-watchdog | |
| | `-zsh-+-(sd-pam) | |
| | `-tmux: client | |
| |-init---init---genie-+-machinectl | |
| | `-8*[{genie}] | |
| `-2*[{init}] | |
|-init---WSLGd-+-dbus-daemon | |
| |-mstsc.exe | |
| |-pulseaudio---2*[{pulseaudio}] | |
| `-weston-+-Xwayland | |
| `-14*[{weston}] | |
|-init---init---bash---pstree | |
`-{init} | |
What you are looking at here is a process tree taken from inside the WSLg system distribution on my machine, while it is running a single Debian distribution, while it is in turn running genie and systemd. As you can see, namespace transitions are included next to those processes which use them, so you can see what's going on.
If you've been following along with WSL hackery for long, you know that every distro running inside WSL essentially runs inside its own container-style namespace(s), sharing the single kernel instance and VM. This is why, for example, kernel threads don't show up in a ps aux
, and certain non-namespaced features are shared between distros so that, for example, kernel modules loaded in one distro show up when you lsmod
in a different distro.
WSLg appears to complicate this a bit. In the leftmost major column there, you have the processes of the system distribution, but what you will notice, the second major column, is that the processes of the user distribution, my Debian distro, are child processes of the system distro's init. That is to say, the user distro now runs as a mount, pid, and UTS namespace within the system distro.
Under that you can see genie's work (the line containing unshare
and systemd
) which creates another mount and pid namespace in order to create an environment in which systemd can own pid 1. While the details of the implementation vary, this much is common to all the hacks which run systemd under WSL. And then beneath it, in turn, you can see all the systemd services (including the user systemd) which it is happy to manage for you.
Below it, you can see genie invoking machinectl, which is its way to get systemd-containerd to handle all the work of setting up a login session properly for it.
So, yes, the best way I've found to run everything is in a container inside a container inside a container...
I’m also going to quote here for your further information a comment I received on the above writeup from @spronovo, who as the Microsoft OS engineering lead for WSLg knows what is:
If you are curious as to why we decided to run the system distro as a sort of parent of it's associated user distro, it was two fold. First to allow us to share IPC namespace so we can use shared memory seamlessly (for example for X11 MIT-SHM protocol)... also because the system distro sometime needs to attach to the pid and mountspace of the user distro it's paired with (to find .desktop file, load icon files, etc...). That seemed the nicest and cleanest way to achieve this transparently.