Using snapd and snaps in WSL2 is considered a “hack”. You may encounter odd behaviour. This is not recommended for general use.
Windows 10 Home or Pro, following insiders fast ring or the equivalent “fall 2019” release once it ships. You will need about 10GB of disk space for Ubuntu.
Please start by installing the Ubuntu 18.04 app from the windows store. Ensure that you can get it to start successfully using WSL-1. There are plenty of guides on the internet for making that work and I’m unwilling to wipe my system to get to a clean slate to reproduce the instructions.
You must then enable WSL-2 by following instructions from https://docs.microsoft.com/en-us/windows/wsl/wsl2-install - the critical part is where you can convert an existing Ubuntu WSL-1 to Ubuntu WSL-2
You can check that you are running WSL-2 by looking at the output of
uname. If you are running 4.19 based kernel called
microsoft-standard then you are good to go.
Preparing for snapd
The WSL-2 model is almost ready for running snapd out of the box. The only missing element is systemd as the init system. Microsoft is using a custom
init that sets up what is effectively a container for each installed WSL-2 distribution. The init system is minimal and handles integration with WSL more than the tasks of a traditional distribution init system.
Systemd is preinstalled but inactive. You can still run systemd manually but it will refuse to start unless it is invoked as pid one. There’s one simple way to get that to work, put it in a “container”, where a container is really a poor man’s container based on the
The magic line is to run this:
sudo daemonize /usr/bin/unshare --fork --pid --mount-proc /lib/systemd/systemd --system-unit=basic.target
This will use
unshare(1) to create a new PID namespace. A PID namespace is effectively the part of Linux state that sees processes, if you look at your system and see pid 123 it is 123 in the PID namespace you are using the watch. In another PID namespace it may be something else or may not exist at all. Creating a PID namespace allows us to get PID 1 again. The remaining arguments tell unshared to mount
/proc again and to
fork(1), which is technically required for the PID namespace to work.
Once unshare is done we ask it to run systemd with the goal to reach
basic.target. You can read more about this in
systemd.target(5) manual page. Up front you will see
sudo daemonize which will run the entire command as root and detach it from the shell we used to invoke this.
Caution at this stage your WSL installation will start to behave oddly if you want to manage services on the “host” part of the distribution. For example if you had installed
apt-get you will no longer be able to start it because the
service management script will attempt to talk to systemd and fail to do so.
Jumping into a world with snapd
Now systemd is running but in our poor man’s container. How can we use it? Technically it is rather simple, we just want to inhabit the same namespaces that systemd is using. This is what it means to “be” inside a container. How can we do that? Using
exec sudo nsenter -t $(pidof systemd) -a su - $LOGNAME
This asks shell to execute
sudo (and replace the current shell with it), which runs
nsenter which will move us to all the namespaces
-a of a task (process) of systemd
-t $(pidof systemd). Once inside the container
nsenter will run
su - $LOGNAME to login as the same user we were using on the host.
If this didn’t fail you can now
snap install anything you like.
You can now snap install stuff. Note that you cannot uses graphical applications. My experiments with an X server and putty as the X11 forwarding bridge were rather poor and I don’t recommend that.
If you open another WSL shell you must repeat the
sudo nsenter command to “switch” to the container running systemd.
This broke my system, help!
Systemd is not “persistent”. If you reboot Windows you will be back to where you started. WSL data will be intact. You can try to run systemd again and again and again.