WSL2 init: emerging OpenRC
WSL2 init: emerging OpenRC
Introduction
Since WSL2 has been released, the community has tried (quite successfully) to add SystemD to their distros.
Currently, the most commons solutions are:
- A single script by the awesome Dani - GitHub - diddledani/one-script-wsl2-systemd: The one-script variant of the systemd hack for WSL2
- A “fully integrated” packages and installer by the amazing Arkane Systems: GitHub - arkane-systems/genie: A quick way into a systemd “bottle” for WSL
Note: Other solutions exist, but these two are the most known in the WSL community.
Both solutions allow you to run SystemD as PID1. These solutions evolved along the years and are today very well integrated with WSL2 and, more recently, with WSL2g.
However, in the Linux community, there’s quite a debate on SystemD itself, and not all the Linux distros use it.
So, “what if” you could run another init system instead of SystemD?
Sources
As I often stated: all ideas have an inspiration or are an alternative to something already done/existing.
For this blog post, my main inspirations were:
- OpenRC on WSL2: Rancher Desktop WSL distro
- SystemD without
PID1: Blog by march1993
Also, a very special mention to the Gentoo wiki which might be one of the best sources of knowledge for Linux.
Other references will be properly linked in the blog post.
So to everyone who already took the time to create content: THANK YOU!
Prerequisites
The following list might be quite long, so I won’t explain how to install it. However I will put the links that I used my own setup.
Here is my setup:
-
OS: Windows 11 Insiders Dev channel
-
Windows 11 Features:
-
WSL2: a Store or Custom distro
- For OpenRC, I used Gentoo
- For SystemD, I used both Ubuntu 21.10 and FedoraRemix
-
[Optional] Windows Terminal
OpenRC: the challenger
OpenRC is the “other” very known init system, used by distros like Alpine, Gentoo and Devuan (just to name the few more known).
While quite known, OpenRC has never been implemented in a WSL2 distro (to my own knowledge), until Rancher Desktop v0.7.0.
The Rancher Desktop OS implemented OpenRC in its simplest form, without re-entering PID1 and it has a set of scripts that takes care of registering and launching the services.
This is where you will “fork” it, and build an OpenRC init system with PID1, by copying what as been done with SystemD on WSL2.
Getting ready
As stated, you’ll use Gentoo as the distro for this example. And, as you might already know, Gentoo is not on the store, therefore you have to create a custom distro.
As there’s already a lot of blogs on how to create a custom distro (i.e. WSL2+RHEL8: The Whale with the Red Hat), here is the “fast track” (read: commands only):
# [Optional] Create a `bin` directory on Windows home and add it to your PATH variablemkdir $env:USERPROFILE\bin$userenv = [System.Environment]::GetEnvironmentVariable("Path", "User")[System.Environment]::SetEnvironmentVariable("PATH", $userenv + "; " + $env:USERPROFILE + "\bin", "User")## Restart your terminal or add temporarily the directory to your PATH variable$env:PATH="$env:USERPROFILE\bin;$env:PATH"
# Assuming you don't have any container runtime (Docker Desktop, Podman, Rancher Desktop), download Google Craneinvoke-webrequest -URI https://github.com/google/go-containerregistry/releases/download/v0.8.0/go-containerregistry_Windows_x86_64.tar.gz -Outfile $env:USERPROFILE\bin\crane.tar.gz
# Check the file contenttar -tf $env:USERPROFILE\bin\crane.tar.gz
# Extract only the "crane.exe" file to the "bin" directorytar -C $env:USERPROFILE\bin -xzf $env:USERPROFILE\bin\crane.tar.gz crane.exe
## [Optional] Delete the archive filerm $env:USERPROFILE\bin\crane.tar.gz
# [Optional] Create a "wslsources" and "wsldistros" directoriesmkdir C:\wsldistros,C:\wslsources
# Download Gentoo rootfs on Docker Hubcrane.exe export gentoo/stage3 C:\wslsources\gentoo.tar
# Create the Gentoo WSL2 custom distrowsl.exe --import gentoo C:\wsldistros\gentoo C:\wslsources\gentoo.tar --version 2
# Launch the Gentoo WSL2 custom distrowsl.exe -d gentoo
Note: Google Crane allows us to save a container image into a
rootfs, instead of saving the layers (i.e.docker save <container image>)
We have now a new WSL2 custom distro, so it’s time to configure OpenRC.
Lightning fast configuration
Before you configure anything, as the OS is brand new, you need to ensure it’s up-to-date. If you also picked Gentoo, then the package manager is Portage:
emerge --sync
With the OS updated, you can install applications that you’ll need later on:
emerge vim sudoInitial configuration
The first configuration file that you need to create, is wsl.conf. This file has several settings that will be applied to the current distro only. One of these settings is the [boot] setting, which runs a command when the distro is started.
For OpenRC, the init process is /sbin/init:
# Create/Edit the wsl.conf file with your favorite editorvi /etc/wsl.conf
# Add/Edit the [boot] command and save the file[boot]command = "/usr/bin/env -i /usr/bin/unshare --pid --mount-proc --fork --propagation private -- sh -c 'exec /sbin/init'"[Optional] We can already see what this change to by terminating the distro session and starting a new one
# Terminate the WSL2 distro session from Powershellwsl.exe --terminate gentoo
# Start a new WSL2 distro sessionwsl.exe -d gentooOnce the new session started, you can check the running processes:
# Check the running processesps -ef
# Check the OpenRC statusrc-status
# Check the current OpenRC servicesrc-update
PID1 is the target
While OpenRC is now running and you can list the services, the WSL2 init process is still the one running as PID1. Thanks to all the work done on WSL2 SystemD, you can leverage the knowledge and apply it to OpenRC:
# Create a script for entering PID 1 and save it in /etc/profile.d/vi /etc/profile.d/wsl-init.sh
## Content of the file /etc/profile.d/wsl-init.sh#!/bin/bash
# Get PID of /sbin/initsleep 1pid="$(ps -u root -o pid,args | awk -e '$2 ~ /^init/ { print $1 }')"
# Run WSL service scriptif [ "$pid" -ne 1 ]; then # Export ENV variables if [ "$USER" != "root" ]; then [ -f "$HOME/.openrc.env" ] && rm "$HOME/.openrc.env" export > "$HOME/.openrc.env" fi
echo "Entering /sbin/init PID: $pid" exec sudo /usr/bin/nsenter -p -m -t "${pid}" -- su - "$USER"fi
# Import ENV variablesif [ -f "$HOME/.openrc.env" ]; then set -a source "$HOME/.openrc.env" set +a rm "$HOME/.openrc.env"fiNote: the scripts located in
/etc/profile.d/do not need to be made executable (i.e.chmod +x ...)
You can now terminate the WSL2 distro session and start a new one where you will have OpenRC as PID1:
# Terminate the WSL2 distro session from Powershellwsl.exe --terminate gentoo
# Start a new WSL2 distro sessionwsl.exe -d gentooOnce the new session started, you can check the running processes:
# Check the running processesps -ef
Conclusion
While SystemD is now as small as a one script, or has very advanced and useful installers, OpenRC implementation seems very simple in comparison.
But, as stated in the introduction, this due to the fact that the work of community has come this far and implementing it now, makes maybe even more sense as we have a better grasp on how WSL2 works.
I hope this will help you and as usual, if you do anything (cool or not) with it, tag me on Twitter (@nunixtech) as I’m always willing to see what are your own crazy ideas.
>>> Nunix out <<<
Bonus 1: Docker on WSL2, the service way
I could not resist and add a Bonus section to show what OpenRC on WSL2 could do for us.
One of the main advantages, is that it will allow us to run applications such as Docker, and allow them to start when the session start.
Here is the installation, still on Gentoo:
# Search for Docker in the Gentoo repoemerge -s Gentoo
# Install the Docker packageemerge app-containers/docker
As stated at the end of the install log, you can find the command to run for starting Docker “at boot”:
# Add Docker to the "default" boot profilerc-update add docker default
# Check if the service has been correctly registeredrc-update show default
# Check if Docker is correctly runningdocker version
Finally, terminate the WSL2 distro session:
# Terminate the WSL2 distro session from Powershellwsl.exe --terminate gentoo
# Start a new WSL2 distro sessionwsl.exe -d gentooAnd start a new WSL2 distro session, Docker should be running:
# Check if Docker is runningdocker version
# [Optional] Create your first Docker containerdocker run --rm hello-world
Bonus 2: OpenRC loves Ketchup (K3sup)
Ok, I must admit I’m really excited by all the opportunities we have with OpenRC (same goes for SystemD). So while we are in the containers/Cloud Native world, let’s use two of the best tools I came across for deploying, very easily, a K3s node cluster (K3sup) and the needed tooling (Arkade)
Let’s install Arkade first and get all the tools needed with it:
# Install Arkade with the official scriptcurl -sLS https://get.arkade.dev | sh
# Get both K3sup and Kubectlark get k3sup kubectl
Now, create a one node K3s cluster:
# [Optional] Update your path with the Arkade bin directoryexport PATH=$PATH:$HOME/.arkade/bin/
# Create the K3s cluster with K3supk3sup install --local
# Test the cluster with the commands displayed at the end of the install logexport KUBECONFIG=/root/kubeconfigkubectl config set-context defaultkubectl get node -o wide
# Check if the service is correctly registeredrc-status default