Sonntag, 22. November 2020

WSL - Windows Linux - wie macht man das?

Ich habe mich etwas mit Windows Subsystem Linux beschäftigt und versucht einen produktiven Ablauf für Setup und Verwendung zu finden. 

Als Ergebnis gibt es auf meiner GitHub Seite ein Powershell Script, welches den automatischen Start von WSL und einer Applikation darin bewerkstelligt. Ich werde dieses Script sicher aktualisieren und erweitern, eine kurze Anleitung zur Verwendung findet sich am Ende des Artikels.

Dieser Artikel ist die Mitschrift der Installation und Einrichtung von WSL und meiner ersten Versuche. Der Code ist eher prinzipiell und nicht unbedingt fehlertolerant.

Grundeinrichtung

Update 4.8.2021

Wenn man das Update KB5004296 installiert hat, kann man im aktuellen Windows 10 wohl einfach so in der Powershell Konsole installieren - dies war bisher nur mit der Insider Preview möglich:

wsl --install

Mit dem Befehl „--install“ werden die folgenden Aktionen ausgeführt (Quelle):

  • Die optionalen Komponenten von WSL und Plattform für virtuelle Computer werden aktiviert.
  • Der aktuelle Linux-Kernel wird heruntergeladen und installiert.
  • WSL 2 wird als Standard festgelegt.
  • Eine Linux-Verteilung wird heruntergeladen und installiert (möglicherweise ist ein Neustart erforderlich) .
  • Standardmäßig ist die installierte Linux-Verteilung Ubuntu. Dies kann mit wsl --install -d <Distribution Name> geändert werden.

Unter Windows 10 kann man das Feature WSL entweder per GUI oder per Powershell installieren. Zwei optionale Feature müssen aktiviert werden:

Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform,Microsoft-Windows-Subsystem-Linux

Danach ist ein Neustart fällig.

Das Admin-Tool für Windows Subsystem Linux ist wsl.exe. Damit kann man auch testen ob die Installation erfolgreiche war und aktive Distributionen und deren Status auflisten:

wsl -l -v

Es ist jetzt noch ein Kernelupdate fällig (auch bei 20H2)! 

Bevor man eine Distribution installiert sollte man die default WSL Version 2 setzen. 

wsl --set-default-version 2

Danach installiert man über den Windows Store eine Linux Distribution (debian). Die Installation ist immer zweistufig: download des appx Packetes und anschließend automatische Installation beim ersten Start. Beide Schritte entweder über suchen und zwei Klicks im Store direkt oder über zwei Powershell Befehle. Scheinbar sind die MS Store Versionen neuer als die auf der Download Seite!

Der Windows Store verhielt sich bei mir manchmal zickig: Es passiert beim Button drücken passiert nichts!? Es gibt zahlreiche Beiträge und einen extra Link in den Windows Einstellungen "Fehlerbehebung bei Microsoft Store Apps". Es gibt das cmd Programm wsreset.exe.

Die finale Installationroutine startet das Subsystem sofort und fragt Linux User und Passwort ab. 

Jeder weitere Aufruf von wsl.exe öffnet ein "Terminalfenster", der Erste startet das Subsystem.

wsl -d debian

Die Grundlage ist geschaffen und WSL wartet auf ein praktisches Beispiel: 

Anwendung (FHEM) in WSL installieren und starten

Für die FHEM Installation braucht man vorher noch (kann sich offenbar täglich ändern)

sudo apt install wget gnupg

danach funktioniert der debian easy way, allerdings wird FHEM am Ende nicht gestartet. 

Hinweis 2024: Die wsl ubuntu Distribution arbeitet mit systemd, fhem wird wie gewohnt gestartet wenn man wsl startet. Die folgende Fehlerbehebung ist in ubuntu nicht notwendig.

Es gibt eine Fehlermeldung am Ende, der Grund: Die debian Distribution enthält kein aktives init System (Systemd). Unschön ist, dass diese Fehlermeldung im dpkg status gespeichert bleibt und fortan jeder Befehl mit dpkg oder apt diesen Fehler anzeigen wird. 

Deswegen sollte man diesen Fehler unbedingt korrigieren:

sudo sed -i '/^Package: fhem/n;s/Status: install ok half-configured/Status: hold ok installed/' /var/lib/dpkg/status

Den Erfolg kann man leicht testen, der Fehler sollte verschwunden sein.

sudo apt install -f

Der sed Befehl 

  • patched die Datei direkt, 
  • er sucht die Zeile "Package: fhem" und 
  • ersetzt in der nächsten Zeile den Fehler. 

Der Start von FHEM benötigt zwei Befehlszeilen, mir ist das nur über einen Script Datei gelungen. Es ist wichtig diese Datei Linux konform zu erstellen. Die Windows Taste + cmd oder Powershell öffnet die Sitzung im Userpfad. Ein anschließendes wsl öffnet die Linux Sitzung im Userpfad. Jetzt einfach mit nano start.sh die Datei mit diesem Inhalt erstellen:

cd /opt/fhem
perl fhem.pl fhem.cfg

Das Script als Startbefehl übergeben und die Linux Distribution mit dem User fhem starten.

wsl -u fhem -d debian -e bash start.sh

Zugriff auf Ports innerhalb WSL

Um auf das Netzwerk in WSL zuzugreifen, kann man vom Host einfach auf localhost(127.0.0.1) zugreifen. Die Ports von WSL werden an diese Hostadresse geleitet (WSL 1 und 2).

http://localhost:8083

Will man aus dem restlichen Netzwerk auf FHEM (den WSL 2 Service) zugreifen, muss man einen PortProxy einrichten und die Ports in der Firewall freigeben. Dafür braucht man erhöhte Rechte, also Powershell im Administratormodus starten.

Anmerkung: Ich bin nicht sicher ob ich die Sache mit dem Portproxy und den Adressen richtig verstanden habe. Aber auf die Art wie ich es gelöst habe, funktioniert es zuverlässig. Im nächsten Beitrag habe ich noch meine Versuche und Erkenntnisse dokumentiert.

Da sich die IP Adresse bei jedem Neustart von WSL 2 ändert, muss man dieses Script bei jedem Start ausführen! Ich habe verschiedene Varianten zur Ermittlung der IP gefunden.

#$cAddr=(wsl -- ip addr show eth0 `| grep 'inet ') -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
#$cAddr=(bash.exe -c "ip addr show eth0 | grep 'inet '") -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
#$cAddr=$matches[0]
$cAddr=(wsl hostname -I).Trim()    # entferne Leerzeichen am Ende
$ports=8083,1883                   # Array mit allen Ports
if (netsh interface portproxy show all){netsh interface portproxy reset}
Foreach ($port in $ports){
   netsh interface portproxy add v4tov4 listenport=$port connectport=$port connectaddress=$cAddr
}

Die Firewall Rules braucht man nicht bei jedem Start neu machen

New-NetFireWallRule -DisplayName 'WSL Firewall Unlock' -Direction Outbound -LocalPort $ports -Action Allow -Protocol TCP
New-NetFireWallRule -DisplayName 'WSL Firewall Unlock' -Direction Inbound -LocalPort $ports -Action Allow -Protocol TCP

Sind die Regeln einmal vorhanden, kann man sie mit einem Befehl bez. der Ports modifizieren.

Set-NetFirewallRule -DisplayName 'WSL Firewall Unlock' -LocalPort $ports

Automatischer Start beim Windows Start

Ich habe ein Powershell Script erstellt, welches das komplette Setup erledigt. Nach dem Download in Zeile 3 kann man das Script natürlich noch anpassen.

Zur Vorbereitung braucht man vier Zeilen:

mkdir c:\scripts -force
cd c:\scripts
wget -O c:\scripts\SetupStartWsl.ps1 https://raw.githubusercontent.com/heinz-otto/Powershell/master/SetupStartWsl.ps1
Set-ExecutionPolicy RemoteSigned
.\SetupStartWsl.ps1

Das Setup Script erledigt 4 Schritte:

  1. Erzeugung des Shell Scripts für den Start innerhalb WSL. 
  2. Erzeugung des Powershell Scripts für den Taskscheduler, 
    • welches das Script aus 1. mit wsl startet, 
    • den Portproxy einrichtet und 
    • die FirewallRegeln anpasst.
  3. Firewall Regel als Grundlage erstellen.
  4. Registrierung der Aufgabe (Taskscheduler) beim Systemstart mit erhöhten Rechten das Script aus 2. auszuführen.

Man könnte noch folgendes einbauen:

  • die verwendeten Ports beim Start des wsl auslesen
  • eventuell eine Startverzögerung berücksichtigen 

Doku zu den Powershell cmdlets: Task mit Powershell


Keine Kommentare:

Kommentar veröffentlichen