Using snapd in WSL2

Disclaimer

Using snapd and snaps in WSL2 is considered a “hack”. You may encounter odd behaviour. This is not recommended for general use.

Prerequisites

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 unshare(1) utility.

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 apache2 using 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 nsenter(1):

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.

What’s next?

snap version

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.

9 Likes

Just wanted to chime in that I’m running Ubuntu 18.04 in WSL2 and it’s great. There are a couple of Redit threads with details on how to do it!

To always enable systemd when you start bash you can create a file in the /etc/profile.d folder which bash reads every time it opens an interactive shell. I’m logging my progress over on the snapcraft forum. This post has been edited to remove the duplicated content and link to the snapcraft forum so that there is only one place to update in the future when I improve the process.

1 Like

My instructions have been improved several times, and now they support running the Visual Studio Code WSL-Remote extension in addition to the Docker for WSL2 Technical Preview.

1 Like

i got a “error: access denied (see ‘snap help login’)” :face_with_thermometer:

Running into the same problem. Even with root (wsl snap list). Anyone fixed this?

Unfortunately I can’t edit the post over on the snapcraft forum anymore. The latest and greatest variant I maintain at diddledani/one-script-wsl2-systemd: The one-script variant of the systemd hack for WSL2 (github.com) now.

Of interest to those reading/involved with this issue:

Microsoft and Canonical jointly announced today that systemd now works within Windows Subsystem for Linux (WSL2). WSL can now run systemd inside of WSL Linux distributions for managing of services. Applications dependent upon systemd for use or simply for easy management can now run easier under this WSL environment on Windows 10/11.

For details on this and how to enable the functionality see:

https://ubuntu.com//blog/ubuntu-wsl-enable-systemd

2 Likes

The WSL version needed for this is available only for Windows 11, not Windows 10.

The latest Windows 10 update now means that this support is available for Windows 10 as well :slight_smile: