Workshop wiki · German

Kubernetes unter WSL auf Windows 11

Diese Datei beschreibt, wie du unter Windows 11 eine saubere WSL2-basierte Kubernetes-Workshop-Umgebung vorbereitest und anschließend unterschiedliche Kubernetes-Varianten provisionierst.

Workshop examples as ZIP files
Learning progress in the web app

Mark chapters as read, view reading progress and check off practice modules after enabling the optional web app. Workshop progress is calculated from chapters across all document pages. Your choices stay on this device; there is no account or server sync. Installation is not required. Withdrawing your choice in Privacy settings deletes the progress.

Reading progress0%
0%
0 / 39 chapters read
Other language versionEnglish ↗

Kubernetes unter WSL auf Windows 11

Diese Datei beschreibt, wie du unter Windows 11 eine saubere WSL2-basierte Kubernetes-Workshop-Umgebung vorbereitest und anschließend unterschiedliche Kubernetes-Varianten provisionierst.

Sie ersetzt eine echte Produktionsplattform nicht. Sie ist für lokale Labs, Demos, Automatisierung, YAML-Übungen, GitOps-Experimente, Ingress-Tests, Netzwerkgrundlagen und schnelle Wiederholbarkeit gedacht.



1. Zweck

Diese Datei beschreibt eine standardisierte Kubernetes-Übungsumgebung unter Windows 11 mit WSL2.

Du kannst sie verwenden, um:

  • WSL2 mit Ubuntu für Kubernetes-Labs vorzubereiten,
  • lokale Cluster mit kind, minikube, k3d, Docker Desktop Kubernetes, k3s oder experimentell mit kubeadm bereitzustellen,
  • Hostnamen so einzurichten, dass Endpunkte im Microsoft Edge Browser auf dem Windows-Host erreichbar sind,
  • die Workshop-Dateien reproduzierbar aus WSL heraus zu provisionieren,
  • typische Fehler im Zusammenspiel von Windows, WSL2, Docker, Ingress und Kubernetes zu debuggen.

Die Datei ist bewusst ausführlich. Sie ist nicht nur eine Installationsnotiz, sondern eine Betriebs- und Entscheidungsreferenz für den Workshop.


01 / 39

2. Zielbild

Am Ende hast du auf deinem Windows-11-Rechner:

  • eine aktuelle WSL2-Distribution, bevorzugt Ubuntu LTS,
  • aktiviertes systemd in WSL,
  • ein konsistentes Linux-Dateisystemlayout für Code, Tools und Cluster-Artefakte,
  • installierte Kubernetes-CLI-Werkzeuge,
  • mindestens eine lauffähige lokale Kubernetes-Variante,
  • eine funktionierende Verbindung vom Windows-Browser zu lokalen Kubernetes-Endpunkten,
  • eine dokumentierte Rückbau- und Wiederholungsstrategie.

2.1 Mentales Modell

WSL2 ist keine klassische Linux-VM, verhält sich für viele Entwicklungsaufgaben aber ähnlich genug. Kubernetes-Labs funktionieren gut, wenn du die Grenzen kennst:

  • WSL2 läuft in einer von Windows verwalteten Utility-VM.
  • Windows und WSL2 haben getrennte Netzwerkstacks, je nach Netzwerkmodus aber gute localhost-Integration.
  • Windows-Laufwerke sind in WSL typischerweise unter /mnt/c, /mnt/d und so weiter eingebunden.
  • Linux-Dateien im WSL-Dateisystem sind für Kubernetes- und Docker-Workflows performanter als Projektdateien unter /mnt/c.
  • Der Edge Browser läuft auf Windows, nicht in WSL. Deshalb musst du Browser-Endpunkte über Windows-DNS, Windows-Hosts-Datei oder localhost erreichbar machen.

02 / 39

3. Entscheidungsmodell

Wähle die Kubernetes-Variante nach Lernziel, Reproduzierbarkeit und Netzwerkbedarf.

Ziel Empfohlene Variante Begründung
Schnelle Kubernetes-Grundlagen kind Sehr schnell, reproduzierbar, ideal für YAML, Controller, Ingress-Labs und CI-nahe Tests.
Entwicklerfreundlicher Einzelcluster minikube mit Docker-Treiber Gute Add-ons, einfache Service-Kommandos, gut für Einsteiger.
K3s-nahe lokale Cluster k3d K3s läuft in Docker-Containern, gute Port-Mappings, schnell rückbaubar.
Einfacher Docker-Desktop-Kontext Docker Desktop Kubernetes Komfortabel, aber weniger transparent und weniger nah an echten Cluster-Bootstrap-Flows.
Bootstrap-Verständnis mit kubeadm kubeadm in WSL, nur experimentell Fachlich lehrreich, aber WSL hat Kernel-, Netzwerk- und Service-Eigenheiten. Für ernsthafte kubeadm-Labs ist eine VM besser.
Leichter Single-Node-Cluster k3s direkt in WSL Schnell und ressourcenschonend, braucht aber saubere Systemdienst- und Netzwerkbehandlung.
Produktionsnaher Betrieb Native VM, Bare Metal oder Managed Kubernetes WSL ist für lokale Labs gut, aber nicht die Referenz für Produktionsbetrieb.
Remote-Cluster bedienen WSL nur als Client Gute Option, wenn der Cluster bereits in Cloud, VM oder Bare Metal läuft.

3.1 Entscheidungsbaum

flowchart TD
    Start[Du brauchst eine Kubernetes-Umgebung unter Windows 11] --> NeedProd{Produktionsnaher Cluster?}
    NeedProd -->|Ja| VM[VM, Bare Metal oder Managed Kubernetes nutzen]
    NeedProd -->|Nein| NeedFast{Schnell und reproduzierbar?}
    NeedFast -->|Ja| Kind[kind unter WSL]
    NeedFast -->|Nein| NeedAddons{Viele Komfort-Add-ons?}
    NeedAddons -->|Ja| Mini[minikube]
    NeedAddons -->|Nein| NeedK3s{K3s-ähnliches Verhalten?}
    NeedK3s -->|Ja| K3d[k3d oder k3s]
    NeedK3s -->|Nein| NeedBootstrap{kubeadm lernen?}
    NeedBootstrap -->|Ja| Kubeadm[kubeadm in VM bevorzugen, WSL nur experimentell]
    NeedBootstrap -->|Nein| DockerDesktop[Docker Desktop Kubernetes oder Remote-Cluster]

03 / 39

4. Unterstützte Varianten

Diese Datei behandelt folgende Bereitstellungswege:

  1. WSL als Kubernetes-Client

    • kubectl, helm, kustomize, stern, k9s, jq, yq
    • Verbindung zu Remote-Clustern
  2. kind in WSL

    • Kubernetes-Nodes als Docker-Container
    • gute Port-Mappings für Ingress
    • sehr gut für Workshops
  3. minikube in WSL

    • bevorzugt mit Docker-Treiber
    • optional SSH- oder None-Treiber für Spezialfälle
    • Add-ons wie Ingress, Metrics Server und Dashboard
  4. k3d in WSL

    • K3s in Docker
    • einfache lokale Load-Balancer-Portfreigaben
    • schnell für K3s-nahe Labs
  5. Docker Desktop Kubernetes

    • Kubernetes in Docker Desktop aktivieren
    • schnell, aber weniger kontrollierbar
  6. kubeadm in WSL

    • nur für experimentelles Verständnis
    • nicht als Standard-Lab empfohlen
  7. k3s direkt in WSL

    • leichtgewichtig
    • Systemdienst- und Netzwerkbesonderheiten beachten
  8. MicroK8s, k0s und weitere Distributionen

    • optional erwähnen und einordnen

04 / 39

5. Architekturüberblick

5.1 Gesamtarchitektur Windows, WSL und Kubernetes

flowchart LR
    Edge[Microsoft Edge auf Windows] --> Hosts[Windows Hosts-Datei / DNS]
    Hosts --> Localhost[localhost / 127.0.0.1]
    Localhost --> WSLNet[WSL2 Netzwerk]
    WSLNet --> Docker[Docker Engine oder Docker Desktop WSL Backend]
    Docker --> Cluster[Kubernetes-Cluster]
    Cluster --> Ingress[Ingress Controller / Gateway]
    Ingress --> Service[Kubernetes Service]
    Service --> Pods[Pods]

    WSL[Ubuntu unter WSL2] --> Kubectl[kubectl / helm / kustomize]
    Kubectl --> API[Kubernetes API Server]
    API --> Cluster

5.2 WSL als Werkzeugschicht

flowchart TD
    Repo[Workshop-Dateien im WSL-Dateisystem] --> Scripts[Provisionierungs-Skripte]
    Scripts --> Tools[CLI-Werkzeuge]
    Tools --> Kubectl[kubectl]
    Tools --> Helm[helm]
    Tools --> Kind[kind]
    Tools --> Mini[minikube]
    Tools --> K3d[k3d]
    Kind --> Docker[Docker]
    Mini --> Docker
    K3d --> Docker
    Docker --> K8s[Kubernetes-Cluster]

5.3 Browser-Zugriff aus Windows

sequenceDiagram
    participant Edge as Edge Browser auf Windows
    participant Hosts as Windows Hosts-Datei
    participant WSL as WSL2 Netzwerk
    participant Ingress as Ingress Controller
    participant Svc as Kubernetes Service
    participant Pod as Pod

    Edge->>Hosts: demo.local auflösen
    Hosts-->>Edge: 127.0.0.1
    Edge->>WSL: HTTP/HTTPS auf localhost
    WSL->>Ingress: Port-Mapping oder Tunnel
    Ingress->>Svc: Host- und Pfad-Routing
    Svc->>Pod: Weiterleitung an Pod-IP
    Pod-->>Edge: Antwort

05 / 39

6. Voraussetzungen auf Windows 11

6.1 Windows-Voraussetzungen

Du brauchst:

  • Windows 11, bevorzugt aktueller Patchstand,
  • aktivierte Virtualisierung im BIOS oder UEFI,
  • WSL2,
  • eine Ubuntu-LTS-Distribution,
  • Administratorrechte für die Erstinstallation und für Änderungen an der Windows-Hosts-Datei,
  • ausreichend Ressourcen:
    • mindestens 4 CPU-Kerne empfohlen,
    • mindestens 8 GB RAM für einfache Labs,
    • 16 GB RAM oder mehr für parallele Cluster, Ingress, Observability und GitOps,
    • mindestens 40 GB freier Speicherplatz.

6.2 Empfohlene Windows-Komponenten

Installiere oder aktiviere:

  • Windows Subsystem for Linux,
  • Virtual Machine Platform,
  • optional Hyper-V, falls du zusätzliche VM-basierte Workflows nutzt,
  • Docker Desktop mit WSL2-Backend oder einen nativen Docker Engine in WSL,
  • Microsoft Edge für Browser-Labs,
  • Visual Studio Code mit WSL-Erweiterung, falls du interaktiv arbeiten willst.

6.3 Nicht empfohlene Annahmen

Verlasse dich nicht darauf, dass:

  • jede Pod-IP direkt vom Windows-Host erreichbar ist,
  • jede Cluster-IP vom Browser erreichbar ist,
  • minikube ip unter dem Docker-Treiber immer direkt vom Windows-Browser erreichbar ist,
  • Änderungen an /etc/hosts automatisch für Edge gelten,
  • WSL sich exakt wie eine native Ubuntu-VM verhält.

Für Browser-Labs gilt: Windows muss den Namen auflösen können, und der Port muss aus Windows erreichbar sein.


06 / 39

7. WSL2 installieren und prüfen

7.1 WSL installieren

Öffne PowerShell als Administrator.

powershell
wsl --install -d Ubuntu-24.04

Falls Ubuntu 24.04 nicht verfügbar ist, prüfe die verfügbaren Distributionen:

powershell
wsl --list --online

Installiere dann eine passende Ubuntu-LTS-Version:

powershell
wsl --install -d Ubuntu

7.2 WSL aktualisieren

powershell
wsl --update
wsl --version

7.3 WSL2 als Standard setzen

powershell
wsl --set-default-version 2

7.4 Installierte Distributionen prüfen

powershell
wsl --list --verbose

Erwartung:

text
  NAME            STATE           VERSION
* Ubuntu-24.04    Running         2

Falls deine Distribution noch WSL1 verwendet:

powershell
wsl --set-version Ubuntu-24.04 2

7.5 Distribution starten

powershell
wsl -d Ubuntu-24.04

Oder über das Startmenü:

text
Ubuntu 24.04

7.6 Windows-Informationen erfassen

Für spätere Fehlersuche dokumentierst du:

powershell
winver
wsl --version
wsl --status
wsl --list --verbose

07 / 39

8. Ubuntu in WSL vorbereiten

8.1 System aktualisieren

In Ubuntu unter WSL:

bash
sudo apt update
sudo apt full-upgrade -y
sudo apt autoremove -y

8.2 Basiswerkzeuge installieren

bash
sudo apt install -y \
  apt-transport-https \
  bash-completion \
  ca-certificates \
  conntrack \
  curl \
  dnsutils \
  file \
  git \
  gnupg \
  htop \
  iproute2 \
  iptables \
  iputils-ping \
  jq \
  less \
  lsb-release \
  make \
  net-tools \
  netcat-openbsd \
  openssl \
  procps \
  python3 \
  python3-pip \
  rsync \
  socat \
  tar \
  traceroute \
  tree \
  unzip \
  vim \
  wget \
  yq \
  zip

8.3 Benutzer prüfen

bash
whoami
id
sudo -v

Dein Benutzer muss sudo nutzen können.

8.4 Zeitzone setzen

bash
timedatectl
sudo timedatectl set-timezone Europe/Berlin

Falls timedatectl noch nicht funktioniert, aktiviere zuerst systemd gemäß Kapitel 9.

8.5 Git konfigurieren

bash
git config --global user.name "Dein Name"
git config --global user.email "dein.name@example.com"
git config --global init.defaultBranch main
git config --global pull.rebase false

8.6 Projektverzeichnis anlegen

Nutze für Code bevorzugt das Linux-Dateisystem von WSL:

bash
mkdir -p ~/workshops
cd ~/workshops

Nicht empfohlen für intensive Kubernetes- und Docker-Workflows:

bash
cd /mnt/c/Users/<dein-user>/Documents

Das funktioniert, ist aber bei vielen kleinen Dateien und Bind-Mounts oft deutlich langsamer.


08 / 39

9. WSL-Konfiguration

WSL verwendet zwei zentrale Konfigurationsdateien:

Datei Ort Wirkung
.wslconfig Windows-Benutzerprofil, zum Beispiel C:\Users\<du>\.wslconfig Globale WSL2-VM-Einstellungen wie RAM, CPU, Swap, Netzwerkmodus.
wsl.conf Innerhalb der Distribution unter /etc/wsl.conf Einstellungen pro Distribution, zum Beispiel systemd, Automount, Hosts-Generierung, Interop.

9.1 .wslconfig für Workshop-Standard

Öffne PowerShell, nicht WSL:

powershell
notepad $env:USERPROFILE\.wslconfig

Empfohlener Standard für viele Workshop-Rechner:

ini
[wsl2]
memory=8GB
processors=4
swap=4GB
localhostForwarding=true
dnsTunneling=true
autoProxy=true

[experimental]
autoMemoryReclaim=gradual
sparseVhd=true

Danach WSL vollständig neu starten:

powershell
wsl --shutdown
wsl -d Ubuntu-24.04

9.2 Optional: Mirrored Networking

Wenn du häufig Probleme mit VPN, Firewall, Browser-Zugriff oder bidirektionaler Kommunikation hast, kannst du unter Windows 11 einen moderneren Netzwerkmodus testen.

ini
[wsl2]
networkingMode=mirrored
dnsTunneling=true
autoProxy=true
localhostForwarding=true

Danach:

powershell
wsl --shutdown

Hinweise:

  • mirrored ist für viele Unternehmensnetze hilfreich, kann aber in einzelnen Setups mit Firewall- oder Endpoint-Security-Regeln kollidieren.
  • Für den Workshop ist NAT mit localhostForwarding=true häufig ausreichend.
  • Wenn du mirrored aktivierst, teste Docker, kind, minikube, DNS und Edge-Zugriff erneut.

9.3 systemd in Ubuntu aktivieren

Öffne in WSL:

bash
sudo nano /etc/wsl.conf

Empfohlene Workshop-Konfiguration:

ini
[boot]
systemd=true

[automount]
enabled=true
root=/mnt/
mountFsTab=true

[network]
generateHosts=true
generateResolvConf=true

[interop]
enabled=true
appendWindowsPath=true

[user]
default=<dein-linux-user>

Ersetze <dein-linux-user> durch deinen Benutzernamen.

Danach in PowerShell:

powershell
wsl --shutdown
wsl -d Ubuntu-24.04

Prüfe in WSL:

bash
ps -p 1 -o comm=
systemctl is-system-running || true
systemctl list-unit-files --type=service | head

Erwartung:

text
systemd

9.4 Windows-Laufwerke prüfen

bash
ls -ld /mnt/c
ls -l /mnt/c/Windows/System32/drivers/etc/hosts

Wenn /mnt/c fehlt:

bash
mount | grep drvfs || true

Dann wsl.conf prüfen und WSL neu starten.

9.5 Interop prüfen

bash
powershell.exe -NoProfile -Command '$PSVersionTable.PSVersion'
cmd.exe /c ver
explorer.exe .

Wenn diese Kommandos nicht gefunden werden, ist appendWindowsPath=false gesetzt oder Windows-Interop deaktiviert. Für den Workshop ist Interop nützlich, weil du aus WSL heraus Windows-Tools starten kannst.


09 / 39

10. Dateisystem- und Workshop-Layout

10.1 Empfohlenes Layout

text
/home/<du>/workshops/
├── kubernetes-workshop/
├── clusters/
│   ├── kind/
│   ├── minikube/
│   └── k3d/
├── bin/
└── tmp/

Anlegen:

bash
mkdir -p ~/workshops ~/clusters/{kind,minikube,k3d} ~/bin ~/tmp

~/bin in den Pfad aufnehmen:

bash
grep -q 'export PATH="$HOME/bin:$PATH"' ~/.bashrc || echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

10.2 Workshop-Material laden

Die Dokumentation ist direkt im Orthevs Wiki verfügbar. Lade die benötigten Praxisbeispiele als ZIP von der Kubernetes-Workshop-Seite herunter und entpacke sie in dein lokales Übungsverzeichnis.

10.3 Workshop-Dateien prüfen

bash
find ~/workshops/kubernetes-workshop -maxdepth 3 -type f | sort | head -100

10.4 Geheimnisse vermeiden

Vor jeder Änderung:

bash
grep -RInE '(password|passwd|secret|token|apikey|api_key|private_key)' . \
  --exclude-dir=.git \
  --exclude='*.md' || true

Das ist nur eine Grobprüfung. Echte Secrets gehören nicht in die Lab-Umgebung.


10 / 39

11. Windows-Hosts-Datei, DNS und Edge-Erreichbarkeit

Dieses Kapitel ist zentral, weil Edge auf Windows läuft. Änderungen an /etc/hosts in WSL reichen für Edge nicht aus.

11.1 Welche Hosts-Datei ist relevant?

Ziel Datei
Namensauflösung in WSL /etc/hosts in Ubuntu
Namensauflösung in Microsoft Edge auf Windows C:\Windows\System32\drivers\etc\hosts
Zugriff aus WSL auf Windows-Datei /mnt/c/Windows/System32/drivers/etc/hosts

Für Browser-Labs musst du die Windows-Hosts-Datei anpassen.

11.2 Windows-Hosts-Datei anzeigen

Aus WSL:

bash
sudo cat /mnt/c/Windows/System32/drivers/etc/hosts | tail -40

Lesen funktioniert meist. Schreiben erfordert Windows-Administratorrechte.

11.3 Hosts-Datei sicher als Administrator öffnen

Empfohlen aus einer administrativen PowerShell:

powershell
notepad $env:windir\System32\drivers\etc\hosts

Füge für lokale Ingress-Labs zum Beispiel hinzu:

text
# Kubernetes WSL Workshop
127.0.0.1 demo.local
127.0.0.1 api.demo.local
127.0.0.1 grafana.demo.local
127.0.0.1 argocd.demo.local
127.0.0.1 keycloak.demo.local
127.0.0.1 prometheus.demo.local

Danach DNS-Cache leeren:

powershell
ipconfig /flushdns

11.4 Hosts-Datei aus WSL über PowerShell öffnen

bash
powershell.exe -NoProfile -Command 'Start-Process notepad -Verb RunAs -ArgumentList "$env:windir\System32\drivers\etc\hosts"'

Wenn die UAC-Abfrage erscheint, bestätigst du sie. Danach bearbeitest du die Datei in Notepad.

11.5 Wiederverwendbares PowerShell-Skript für Hosts-Einträge

Lege im Repository eine Datei an:

bash
mkdir -p scripts/windows
cat > scripts/windows/add-k8s-hosts.ps1 <<'EOF'
$ErrorActionPreference = "Stop"

$HostsPath = "$env:windir\System32\drivers\etc\hosts"
$MarkerStart = "# BEGIN Kubernetes WSL Workshop"
$MarkerEnd = "# END Kubernetes WSL Workshop"
$Block = @"
$MarkerStart
127.0.0.1 demo.local
127.0.0.1 api.demo.local
127.0.0.1 grafana.demo.local
127.0.0.1 argocd.demo.local
127.0.0.1 keycloak.demo.local
127.0.0.1 prometheus.demo.local
$MarkerEnd
"@

$Current = Get-Content -Path $HostsPath -Raw
$Pattern = [regex]::Escape($MarkerStart) + "(?s).*?" + [regex]::Escape($MarkerEnd)

if ($Current -match $Pattern) {
    $New = [regex]::Replace($Current, $Pattern, $Block.Trim())
    Set-Content -Path $HostsPath -Value $New -NoNewline
} else {
    Add-Content -Path $HostsPath -Value "`r`n$Block"
}

ipconfig /flushdns | Out-Null
Write-Host "Kubernetes-WSL-Hosts-Einträge wurden gesetzt."
EOF

Aus einer administrativen PowerShell ausführen:

powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Pfad\zum\Repository\scripts\windows\add-k8s-hosts.ps1

Oder aus WSL heraus starten:

bash
powershell.exe -NoProfile -ExecutionPolicy Bypass -Command \
  "Start-Process powershell -Verb RunAs -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File \"$(wslpath -w scripts/windows/add-k8s-hosts.ps1)\"'"

11.6 Hosts-Einträge entfernen

bash
cat > scripts/windows/remove-k8s-hosts.ps1 <<'EOF'
$ErrorActionPreference = "Stop"

$HostsPath = "$env:windir\System32\drivers\etc\hosts"
$MarkerStart = "# BEGIN Kubernetes WSL Workshop"
$MarkerEnd = "# END Kubernetes WSL Workshop"
$Current = Get-Content -Path $HostsPath -Raw
$Pattern = "(?ms)^" + [regex]::Escape($MarkerStart) + ".*?" + [regex]::Escape($MarkerEnd) + "\r?\n?"
$New = [regex]::Replace($Current, $Pattern, "")
Set-Content -Path $HostsPath -Value $New -NoNewline
ipconfig /flushdns | Out-Null
Write-Host "Kubernetes-WSL-Hosts-Einträge wurden entfernt."
EOF

Administrative PowerShell:

powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Pfad\zum\Repository\scripts\windows\remove-k8s-hosts.ps1

11.7 Prüfen aus Windows

In PowerShell:

powershell
Resolve-DnsName demo.local
Test-NetConnection demo.local -Port 80

Im Browser:

text
http://demo.local

11.8 Prüfen aus WSL

bash
getent hosts demo.local
curl -v http://demo.local || true
curl -v http://127.0.0.1 || true

11.9 Wichtige Regel

Für kind und k3d verwendest du für Browser-Labs meistens:

text
127.0.0.1 demo.local

Für minikube hängt es vom Treiber und Zugriffspfad ab:

  • bei kubectl port-forward: 127.0.0.1,
  • bei minikube tunnel: meist 127.0.0.1 oder eine Tunnel-Adresse,
  • bei VM-/SSH-Treibern: unter Umständen die Node-IP,
  • bei Docker-Treiber unter WSL: lieber Port-Forwarding oder explizite Portfreigabe verwenden.

11 / 39

12. Container Runtime und Docker-Strategie

Die meisten empfohlenen WSL-Varianten nutzen Docker:

  • kind benötigt Docker, Podman oder eine kompatible Container Runtime.
  • k3d benötigt Docker.
  • minikube mit Docker-Treiber benötigt Docker.
  • Docker Desktop Kubernetes läuft direkt im Docker-Desktop-Stack.

12.1 Empfohlene Strategie für Workshops

Für gemischte Teilnehmergruppen ist meist am stabilsten:

text
Windows 11 + WSL2 + Ubuntu + Docker Desktop WSL Integration + kind

Vorteile:

  • schnelle Installation,
  • gute Windows-Integration,
  • relativ vorhersehbares Netzwerk,
  • einfache Rücksetzung,
  • weniger systemnahe Eingriffe in WSL.

12.2 Docker Desktop mit WSL-Integration

In Docker Desktop:

  1. Settings öffnen.
  2. Resources auswählen.
  3. WSL Integration öffnen.
  4. Integration für deine Ubuntu-Distribution aktivieren.
  5. Docker Desktop neu starten.

In WSL prüfen:

bash
docker version
docker context ls
docker run --rm hello-world

12.3 Native Docker Engine in WSL

Alternativ kannst du Docker direkt in Ubuntu unter WSL installieren. Das ist transparenter, aber stärker abhängig von Systemdienst- und Netzwerkeinstellungen.

Beispiel für Ubuntu:

bash
sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

. /etc/os-release
printf 'deb [arch=%s signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu %s stable\n' \
  "$(dpkg --print-architecture)" "$VERSION_CODENAME" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker "$USER"
newgrp docker

Prüfen:

bash
systemctl status docker --no-pager
docker info
docker run --rm hello-world

12.4 Docker Desktop oder native Docker Engine?

Kriterium Docker Desktop Native Docker Engine in WSL
Einsteigerfreundlichkeit Hoch Mittel
Unternehmensrichtlinien Lizenz und Policy prüfen Häufig flexibler, aber manuell zu pflegen
WSL-Integration Sehr gut Gut, aber stärker selbst verwaltet
kind und k3d Sehr gut Sehr gut
Systemnähe Geringer Höher
Troubleshooting Teilweise Docker-Desktop-spezifisch Linux-näher

12 / 39

13. Basiswerkzeuge installieren

13.1 Kubernetes-Versionen bewusst behandeln

Setze die Kubernetes-Version nicht hart in jedes Skript. Nutze Variablen:

bash
export K8S_MINOR="1.36"
export K8S_STABLE="$(curl -L -s https://dl.k8s.io/release/stable.txt)"
echo "$K8S_STABLE"

Hinweise:

  • Für Paket-Repositories wird häufig der Minor-Stream verwendet, zum Beispiel v1.36.
  • Für einzelne Binärdateien oder Cluster-Images kannst du eine konkrete Patchversion verwenden.
  • Für Workshops solltest du Versionen vorab einfrieren, damit alle Teilnehmer denselben Stand verwenden.

13.2 kubectl über Kubernetes-Paketquelle installieren

bash
export K8S_MINOR="1.36"

sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg
sudo mkdir -p /etc/apt/keyrings

curl -fsSL "https://pkgs.k8s.io/core:/stable:/v${K8S_MINOR}/deb/Release.key" | \
  sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

printf 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v%s/deb/ /\n' "${K8S_MINOR}" | \
  sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt update
sudo apt install -y kubectl
kubectl version --client

13.3 kubectl Autovervollständigung

bash
echo 'source <(kubectl completion bash)' >> ~/.bashrc
echo 'alias k=kubectl' >> ~/.bashrc
echo 'complete -o default -F __start_kubectl k' >> ~/.bashrc
source ~/.bashrc

13.4 Helm installieren

bash
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
helm version

13.5 Kustomize prüfen

kubectl bringt kustomize-Funktionalität mit:

bash
kubectl kustomize --help | head

Optional eigenständiges kustomize:

bash
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo install -m 0755 kustomize /usr/local/bin/kustomize
kustomize version

13.6 Nützliche Zusatzwerkzeuge

bash
# stern für Log-Tailing
curl -fsSL https://github.com/stern/stern/releases/latest/download/stern_linux_amd64.tar.gz -o /tmp/stern.tar.gz
mkdir -p /tmp/stern
sudo tar -xzf /tmp/stern.tar.gz -C /tmp/stern
sudo install -m 0755 /tmp/stern/stern /usr/local/bin/stern

# k9s über GitHub-Release oder Paketmanager installieren, je nach Unternehmensrichtlinie
# Beispiel absichtlich nicht automatisiert, da Version und Architektur festgelegt werden sollten.

13.7 Tooling validieren

bash
for cmd in git curl jq yq docker kubectl helm; do
  printf '%-12s' "$cmd"
  command -v "$cmd" || true
done

13 / 39

14. Variante A: kind unter WSL

kind steht für Kubernetes in Docker. Es startet Kubernetes-Nodes als Container. Für WSL-Workshops ist kind meistens die beste Standardvariante.

14.1 Wann du kind nimmst

Nutze kind, wenn du:

  • schnell Cluster erstellen und löschen willst,
  • YAML, Deployments, Services, Ingress und Controller üben willst,
  • reproduzierbare Labs brauchst,
  • mehrere Cluster parallel testen willst,
  • CI-nahe Cluster simulieren möchtest.

14.2 Grenzen von kind

Beachte:

  • Nodes sind Container, keine echten Maschinen.
  • Storage ist lokal und lab-orientiert.
  • LoadBalancer-Verhalten braucht Zusatzkomponenten oder Port-Mappings.
  • Kernel- und Node-Betrieb unterscheiden sich von Bare Metal oder VM-Clustern.

14.3 kind installieren

Variante über Go:

bash
sudo apt install -y golang-go
go install sigs.k8s.io/kind@latest
mkdir -p ~/bin
ln -sf "$(go env GOPATH)/bin/kind" ~/bin/kind
kind version

Variante über Binärdatei:

bash
KIND_VERSION="v0.30.0"
curl -Lo /tmp/kind "https://kind.sigs.k8s.io/dl/${KIND_VERSION}/kind-linux-amd64"
chmod +x /tmp/kind
sudo install -m 0755 /tmp/kind /usr/local/bin/kind
kind version

Passe KIND_VERSION vor dem Workshop an die gewünschte Version an.

14.4 Einfachen Cluster erstellen

bash
kind create cluster --name workshop
kubectl cluster-info --context kind-workshop
kubectl get nodes -o wide

14.5 Cluster-Konfiguration mit Ingress-Port-Mapping

Lege eine Konfiguration an:

bash
mkdir -p clusters/kind
cat > clusters/kind/workshop.yaml <<'EOF'
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: workshop
nodes:
  - role: control-plane
    kubeadmConfigPatches:
      - |
        kind: InitConfiguration
        nodeRegistration:
          kubeletExtraArgs:
            node-labels: "ingress-ready=true"
    extraPortMappings:
      - containerPort: 80
        hostPort: 80
        protocol: TCP
      - containerPort: 443
        hostPort: 443
        protocol: TCP
      - containerPort: 30080
        hostPort: 30080
        protocol: TCP
  - role: worker
  - role: worker
EOF

Cluster erstellen:

bash
kind delete cluster --name workshop || true
kind create cluster --config clusters/kind/workshop.yaml
kubectl get nodes -o wide

14.6 Wenn Port 80 oder 443 blockiert ist

Wenn Windows, Docker Desktop oder ein anderes Tool Port 80/443 bereits nutzt, nimm höhere Ports:

yaml
extraPortMappings:
  - containerPort: 80
    hostPort: 8080
    protocol: TCP
  - containerPort: 443
    hostPort: 8443
    protocol: TCP

Dann verwendest du im Browser:

text
http://demo.local:8080
https://demo.local:8443

14.7 Ingress-NGINX installieren

bash
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml

kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=180s

14.8 Demo-Anwendung bereitstellen

bash
kubectl create namespace demo --dry-run=client -o yaml | kubectl apply -f -

kubectl create deployment web \
  --image=nginx:1.27 \
  --replicas=2 \
  -n demo

kubectl expose deployment web \
  --port=80 \
  --target-port=80 \
  -n demo

Ingress:

bash
cat > /tmp/demo-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  namespace: demo
spec:
  ingressClassName: nginx
  rules:
    - host: demo.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80
EOF

kubectl apply -f /tmp/demo-ingress.yaml

Windows-Hosts-Datei:

text
127.0.0.1 demo.local

Test aus WSL:

bash
curl -H 'Host: demo.local' http://127.0.0.1
curl http://demo.local

Test im Edge Browser:

text
http://demo.local

14.9 kind mit lokaler Registry

Lokale Registry starten:

bash
docker run -d --restart=always -p 127.0.0.1:5001:5000 --name kind-registry registry:2

kind-Konfiguration mit Registry-Mirror:

bash
cat > clusters/kind/workshop-registry.yaml <<'EOF'
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: workshop
containerdConfigPatches:
  - |-
    [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:5001"]
      endpoint = ["http://kind-registry:5000"]
nodes:
  - role: control-plane
    extraPortMappings:
      - containerPort: 80
        hostPort: 80
        protocol: TCP
      - containerPort: 443
        hostPort: 443
        protocol: TCP
  - role: worker
  - role: worker
EOF

Cluster erstellen und Registry mit dem kind-Netz verbinden:

bash
kind delete cluster --name workshop || true
kind create cluster --config clusters/kind/workshop-registry.yaml

docker network connect kind kind-registry || true

Image bauen und pushen:

bash
docker build -t localhost:5001/demo-app:0.1.0 .
docker push localhost:5001/demo-app:0.1.0

Im Manifest:

yaml
image: localhost:5001/demo-app:0.1.0

14.10 kind-Cluster löschen

bash
kind delete cluster --name workshop
docker rm -f kind-registry || true

14 / 39

15. Variante B: minikube unter WSL

minikube erstellt lokale Kubernetes-Cluster mit verschiedenen Treibern. Unter WSL ist der Docker-Treiber meistens die praktikable Variante.

15.1 Wann du minikube nimmst

Nutze minikube, wenn du:

  • einen Einsteigerpfad mit vielen eingebauten Add-ons brauchst,
  • minikube addons verwenden willst,
  • schnell metrics-server, Dashboard, Ingress oder Registry aktivieren möchtest,
  • Übungen mit Service-Zugriff über minikube service machen willst.

15.2 minikube installieren

bash
curl -LO https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-amd64
sudo install -m 0755 minikube-linux-amd64 /usr/local/bin/minikube
rm -f minikube-linux-amd64
minikube version

15.3 Cluster mit Docker-Treiber starten

bash
minikube start \
  --driver=docker \
  --cpus=4 \
  --memory=8192 \
  --disk-size=30g

Prüfen:

bash
kubectl config current-context
kubectl get nodes -o wide
minikube status

15.4 Kubernetes-Version setzen

bash
K8S_STABLE="$(curl -L -s https://dl.k8s.io/release/stable.txt)"
minikube start \
  --driver=docker \
  --kubernetes-version="$K8S_STABLE" \
  --cpus=4 \
  --memory=8192

Wenn du einen Workshop reproduzierbar halten willst, setze eine konkrete Version:

bash
minikube start --driver=docker --kubernetes-version=v1.36.1

Passe die Patchversion vor dem Workshop an.

15.5 Add-ons aktivieren

bash
minikube addons list
minikube addons enable ingress
minikube addons enable metrics-server

Prüfen:

bash
kubectl get pods -A
kubectl top nodes || true

15.6 Demo-Anwendung

bash
kubectl create namespace demo --dry-run=client -o yaml | kubectl apply -f -
kubectl create deployment web --image=nginx:1.27 -n demo
kubectl expose deployment web --port=80 --target-port=80 -n demo

NodePort-Service:

bash
kubectl expose deployment web \
  --name=web-nodeport \
  --type=NodePort \
  --port=80 \
  --target-port=80 \
  -n demo

kubectl get svc -n demo
minikube service web-nodeport -n demo --url

15.7 Zugriff aus Edge

Für WSL und Windows ist der stabilste Pfad häufig Port-Forwarding:

bash
kubectl port-forward -n demo --address 0.0.0.0 svc/web 8080:80

Dann in Edge:

text
http://localhost:8080

Oder mit Hostname:

Windows-Hosts-Datei:

text
127.0.0.1 demo.local

Browser:

text
http://demo.local:8080

15.8 Ingress mit minikube

Ingress aktivieren:

bash
minikube addons enable ingress
kubectl wait -n ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=180s

Ingress-Objekt:

bash
cat > /tmp/minikube-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  namespace: demo
spec:
  ingressClassName: nginx
  rules:
    - host: demo.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80
EOF

kubectl apply -f /tmp/minikube-ingress.yaml

Je nach Treiber erreichst du den Ingress über:

bash
minikube ip
curl -H 'Host: demo.local' http://$(minikube ip)

Wenn Windows diese IP nicht erreicht, nimm Port-Forwarding oder minikube tunnel.

15.9 minikube tunnel

minikube tunnel kann Services vom Typ LoadBalancer erreichbar machen. Unter Windows/WSL können dafür erhöhte Rechte und Routing-Anpassungen nötig sein.

bash
minikube tunnel

In einem zweiten Terminal:

bash
kubectl create deployment lb-demo --image=nginx:1.27 -n demo
kubectl expose deployment lb-demo --type=LoadBalancer --port=80 -n demo
kubectl get svc -n demo -w

15.10 minikube löschen

bash
minikube delete

15 / 39

16. Variante C: k3d unter WSL

k3d startet K3s-Cluster in Docker. Es ist schnell, ressourcenschonend und für lokale Labs gut geeignet.

16.1 Wann du k3d nimmst

Nutze k3d, wenn du:

  • K3s-Verhalten lokal testen willst,
  • sehr schnell Cluster starten möchtest,
  • Port-Mappings über einen Load-Balancer-Container brauchst,
  • mehrere lokale Cluster verwenden möchtest.

16.2 k3d installieren

bash
curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
k3d version

Für strengere Umgebungen solltest du das Installationsskript vorher herunterladen, prüfen und versionieren.

16.3 Cluster mit Port-Mapping erstellen

bash
k3d cluster create workshop \
  --servers 1 \
  --agents 2 \
  --api-port 127.0.0.1:6550 \
  -p "80:80@loadbalancer" \
  -p "443:443@loadbalancer"

Prüfen:

bash
kubectl cluster-info
kubectl get nodes -o wide
k3d cluster list

16.4 Demo-Anwendung mit Ingress

K3s bringt standardmäßig Traefik mit, wenn du es nicht deaktivierst.

bash
kubectl create namespace demo --dry-run=client -o yaml | kubectl apply -f -
kubectl create deployment web --image=nginx:1.27 -n demo
kubectl expose deployment web --port=80 --target-port=80 -n demo

Ingress:

bash
cat > /tmp/k3d-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  namespace: demo
spec:
  rules:
    - host: demo.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80
EOF

kubectl apply -f /tmp/k3d-ingress.yaml

Windows-Hosts-Datei:

text
127.0.0.1 demo.local

Test:

bash
curl http://demo.local

Browser:

text
http://demo.local

16.5 k3d ohne Traefik und mit Ingress-NGINX

bash
k3d cluster delete workshop || true
k3d cluster create workshop \
  --servers 1 \
  --agents 2 \
  --api-port 127.0.0.1:6550 \
  -p "80:80@loadbalancer" \
  -p "443:443@loadbalancer" \
  --k3s-arg "--disable=traefik@server:*"

Ingress-NGINX installieren:

bash
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
  -n ingress-nginx \
  --create-namespace \
  --set controller.service.type=LoadBalancer

16.6 k3d löschen

bash
k3d cluster delete workshop

16 / 39

17. Variante D: Docker Desktop Kubernetes

Docker Desktop kann einen lokalen Kubernetes-Cluster bereitstellen.

17.1 Wann du Docker Desktop Kubernetes nimmst

Nutze diese Variante, wenn du:

  • sehr schnell einen lokalen Kubernetes-Kontext brauchst,
  • keine zusätzliche Cluster-CLI installieren willst,
  • Docker Desktop ohnehin im Workshop verwendest,
  • keine tiefe Bootstrap-Transparenz benötigst.

17.2 Aktivieren

In Docker Desktop:

  1. Settings öffnen.
  2. Kubernetes auswählen.
  3. Enable Kubernetes aktivieren.
  4. Anwenden und warten.

Prüfen in WSL:

bash
kubectl config get-contexts
kubectl config use-context docker-desktop
kubectl get nodes -o wide

17.3 Demo

bash
kubectl create namespace demo --dry-run=client -o yaml | kubectl apply -f -
kubectl create deployment web --image=nginx:1.27 -n demo
kubectl expose deployment web --port=80 --target-port=80 -n demo
kubectl port-forward -n demo --address 0.0.0.0 svc/web 8080:80

Browser:

text
http://localhost:8080

17.4 Grenzen

Docker Desktop Kubernetes ist praktisch, aber:

  • weniger transparent als kind, minikube oder kubeadm,
  • abhängig von Docker-Desktop-Version und Einstellungen,
  • nicht ideal für Betriebslabs zu Control Plane, Node-Lifecycle oder CNI,
  • in Unternehmen lizenz- und policyabhängig.

17 / 39

18. Variante E: kubeadm experimentell in WSL

kubeadm ist der klassische Bootstrap-Pfad für Kubernetes-Cluster. In WSL ist diese Variante nicht die Standardempfehlung. Für produktionsnahe Labs solltest du eine native VM oder Bare-Metal-Umgebung nutzen.

Trotzdem ist kubeadm in WSL lehrreich, weil du Control Plane, kubelet, containerd, CNI, Zertifikate und Cluster-Bootstrap direkt siehst.

18.1 Voraussetzungen

Du brauchst:

  • WSL2,
  • systemd=true,
  • funktionierende containerd-Runtime,
  • deaktivierten Swap oder korrektes kubelet-Verhalten,
  • passende Kernel- und Netzwerkfunktionen,
  • Bereitschaft zu Fehlersuche.

18.2 containerd installieren

bash
sudo apt update
sudo apt install -y containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml >/dev/null

Systemd-cgroup setzen:

bash
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
sudo systemctl enable containerd

Prüfen:

bash
systemctl status containerd --no-pager
sudo ctr version

18.3 Kernel- und Netzwerkparameter

bash
cat <<'EOF' | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay || true
sudo modprobe br_netfilter || true

cat <<'EOF' | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

sudo sysctl --system

Wenn modprobe br_netfilter in WSL fehlschlägt, ist das ein WSL-Kernel-Thema. Für echte kubeadm-Labs wechselst du dann auf eine VM.

18.4 kubeadm, kubelet und kubectl installieren

bash
export K8S_MINOR="1.36"

sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg
sudo mkdir -p /etc/apt/keyrings

curl -fsSL "https://pkgs.k8s.io/core:/stable:/v${K8S_MINOR}/deb/Release.key" | \
  sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

printf 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v%s/deb/ /\n' "${K8S_MINOR}" | \
  sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

18.5 Swap prüfen

bash
swapon --show || true
free -h

Falls Swap aktiv ist und kubelet damit nicht umgehen soll:

bash
sudo swapoff -a

WSL-Swap wird über .wslconfig gesteuert. Für echte kubeadm-Labs solltest du das Verhalten bewusst festlegen.

18.6 kubeadm-Konfiguration

bash
mkdir -p clusters/kubeadm
cat > clusters/kubeadm/init.yaml <<'EOF'
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 127.0.0.1
  bindPort: 6443
nodeRegistration:
  criSocket: unix:///run/containerd/containerd.sock
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
# Beispielversion: Prüfe und pinne die Patchversion vor dem Workshop.
kubernetesVersion: v1.36.1
networking:
  podSubnet: 10.244.0.0/16
  serviceSubnet: 10.96.0.0/12
apiServer:
  certSANs:
    - 127.0.0.1
    - localhost
    - kubeadm.local
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
EOF

18.7 Cluster initialisieren

bash
sudo kubeadm init --config clusters/kubeadm/init.yaml

kubectl konfigurieren:

bash
mkdir -p ~/.kube
sudo cp -i /etc/kubernetes/admin.conf ~/.kube/config
sudo chown "$(id -u):$(id -g)" ~/.kube/config
kubectl get nodes

18.8 CNI installieren

Beispiel mit Flannel:

bash
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

Warten:

bash
kubectl get pods -A -w

18.9 Single-Node Scheduling erlauben

bash
kubectl taint nodes --all node-role.kubernetes.io/control-plane- || true
kubectl get nodes

18.10 Demo testen

bash
kubectl create namespace demo --dry-run=client -o yaml | kubectl apply -f -
kubectl create deployment web --image=nginx:1.27 -n demo
kubectl expose deployment web --port=80 --target-port=80 -n demo
kubectl port-forward -n demo --address 0.0.0.0 svc/web 8080:80

Browser:

text
http://localhost:8080

18.11 kubeadm zurückbauen

bash
sudo kubeadm reset -f
sudo rm -rf ~/.kube /etc/cni/net.d /var/lib/cni /var/lib/kubelet /var/lib/etcd
sudo systemctl restart containerd

18.12 Fachliche Einordnung

Für den Workshop gilt:

  • kubeadm in WSL ist eine fortgeschrittene Demo, nicht die robuste Standardumgebung.
  • Für kubeadm-Grundlagen ist eine native VM mit Ubuntu besser.
  • Für reine Kubernetes-Objekte, Deployments und Ingress ist kind meist sinnvoller.

18 / 39

19. Variante F: k3s direkt in WSL

k3s ist eine leichtgewichtige Kubernetes-Distribution. Sie kann in WSL laufen, wenn systemd und Netzwerk sauber funktionieren.

19.1 Wann du k3s nimmst

Nutze k3s direkt in WSL, wenn du:

  • eine leichte Single-Node-Distribution testen willst,
  • K3s-spezifisches Verhalten betrachten möchtest,
  • Systemdienst-Betrieb üben willst,
  • weniger Docker-Container-Nodes als bei k3d möchtest.

19.2 Installation

bash
curl -sfL https://get.k3s.io | \
  INSTALL_K3S_EXEC="--write-kubeconfig-mode=644" \
  sh -

Prüfen:

bash
sudo systemctl status k3s --no-pager
kubectl --kubeconfig /etc/rancher/k3s/k3s.yaml get nodes

Kubeconfig übernehmen:

bash
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown "$(id -u):$(id -g)" ~/.kube/config
kubectl get nodes -o wide

19.3 Demo

bash
kubectl create namespace demo --dry-run=client -o yaml | kubectl apply -f -
kubectl create deployment web --image=nginx:1.27 -n demo
kubectl expose deployment web --port=80 --target-port=80 -n demo
kubectl port-forward -n demo --address 0.0.0.0 svc/web 8080:80

Browser:

text
http://localhost:8080

19.4 Rückbau

bash
sudo /usr/local/bin/k3s-uninstall.sh
rm -rf ~/.kube/config

19 / 39

20. Variante G: MicroK8s, k0s und weitere Optionen

20.1 MicroK8s

MicroK8s ist eine kompakte Kubernetes-Distribution von Canonical. Unter Windows wird häufig ein eigener Installationspfad mit WSL oder Multipass genutzt.

Einfache Einordnung:

Punkt Bewertung
Einsteigerfreundlichkeit Hoch
Snap-Abhängigkeit Muss zur Umgebung passen
Add-ons Sehr komfortabel
Workshop-Fokus Gut, wenn MicroK8s explizit Thema ist
Standard für diese Datei Nein, kind ist allgemeiner und reproduzierbarer

20.2 k0s

k0s ist eine weitere Kubernetes-Distribution mit eigenem Installations- und Betriebsmodell.

Unter WSL kannst du sie für Speziallabs betrachten. Für allgemeine Workshop-Übungen ist kind, minikube oder k3d in der Regel schneller.

20.3 Podman-basierte Varianten

Einige Werkzeuge unterstützen Podman oder rootless Container. Unter WSL ist das möglich, aber für gemischte Workshops fehleranfälliger.

Empfehlung:

  • Docker Desktop WSL Integration für Standardworkshops,
  • native Docker Engine in WSL für Linux-nähere Workshops,
  • Podman/rootless nur als Fortgeschrittenenthema.

20 / 39

21. Remote-Cluster aus WSL verwalten

WSL eignet sich sehr gut als Linux-CLI-Umgebung für Remote-Cluster.

21.1 kubeconfig ablegen

bash
mkdir -p ~/.kube
chmod 700 ~/.kube
cp /mnt/c/Users/<windows-user>/Downloads/kubeconfig ~/.kube/config
chmod 600 ~/.kube/config

21.2 Kontext prüfen

bash
kubectl config get-contexts
kubectl config current-context
kubectl cluster-info
kubectl get nodes -o wide

21.3 Mehrere kubeconfigs nutzen

bash
mkdir -p ~/.kube/configs
cp kubeconfig-dev ~/.kube/configs/dev.yaml
cp kubeconfig-prod ~/.kube/configs/prod.yaml

export KUBECONFIG="$HOME/.kube/configs/dev.yaml:$HOME/.kube/configs/prod.yaml"
kubectl config view --flatten > ~/.kube/config.merged
mv ~/.kube/config.merged ~/.kube/config
chmod 600 ~/.kube/config

21.4 Sicherheitsregel

Teile keine admin.conf, keine Cloud-Kubeconfigs und keine Token in Workshop-Dateien. Kubeconfigs sind Zugangsdaten.


21 / 39

22. Ingress-, Gateway- und Browser-Zugriff

22.1 Grundregel

Damit Edge einen Kubernetes-Endpunkt erreicht, müssen drei Dinge stimmen:

  1. Der Hostname muss in Windows auflösbar sein.
  2. Der Zielport muss auf Windows erreichbar sein.
  3. Der Cluster muss den Hostnamen routen können.

22.2 Standard für kind

text
Windows Hosts-Datei: 127.0.0.1 demo.local
kind extraPortMappings: hostPort 80 -> containerPort 80
Ingress: host demo.local
Browser: http://demo.local

22.3 Standard für k3d

text
Windows Hosts-Datei: 127.0.0.1 demo.local
k3d Port-Mapping: 80:80@loadbalancer
Ingress: host demo.local
Browser: http://demo.local

22.4 Standard für minikube

Für robuste Windows-/WSL-Workshops:

text
kubectl port-forward --address 0.0.0.0 svc/web 8080:80
Windows Hosts-Datei: 127.0.0.1 demo.local
Browser: http://demo.local:8080

Alternativ:

text
minikube tunnel
Service type LoadBalancer
Browser abhängig von Tunnel-Adresse und Routing

22.5 Gateway API als optionales Lab

Gateway API kann Ingress in modernen Workshops ergänzen.

Beispielstruktur:

flowchart TD
    Browser[Edge Browser] --> Hosts[Windows Hosts-Datei]
    Hosts --> Gateway[Gateway Listener]
    Gateway --> Route[HTTPRoute]
    Route --> Service[Service]
    Service --> Pod[Pod]

Beispielobjekte hängen vom Gateway-Controller ab. Für lokale Labs kannst du zum Beispiel Envoy Gateway, Contour oder Gateway-Unterstützung deines Ingress-Controllers verwenden.


22 / 39

23. Zertifikate und lokale TLS-Entwicklung

23.1 Lokales TLS-Zielbild

Für TLS-Labs brauchst du:

  • einen lokalen Hostnamen,
  • ein Zertifikat für diesen Hostnamen,
  • einen Ingress oder Gateway mit TLS-Konfiguration,
  • Vertrauen im Browser oder bewusste Ausnahme.

23.2 Selbstsigniertes Zertifikat erstellen

bash
mkdir -p certs
openssl req -x509 -nodes -days 365 \
  -newkey rsa:2048 \
  -keyout certs/demo.local.key \
  -out certs/demo.local.crt \
  -subj "/CN=demo.local" \
  -addext "subjectAltName=DNS:demo.local,DNS:api.demo.local,DNS:grafana.demo.local"

Kubernetes Secret:

bash
kubectl create secret tls demo-local-tls \
  --cert=certs/demo.local.crt \
  --key=certs/demo.local.key \
  -n demo \
  --dry-run=client -o yaml | kubectl apply -f -

Ingress mit TLS:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  namespace: demo
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - demo.local
      secretName: demo-local-tls
  rules:
    - host: demo.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80

23.3 Zertifikat in Windows vertrauen

Für echte Browser-Vertrauensketten nutzt du besser eine lokale CA, zum Beispiel mit mkcert.

Installationsidee:

bash
sudo apt install -y libnss3-tools
curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64"
chmod +x mkcert-*-linux-amd64
sudo mv mkcert-*-linux-amd64 /usr/local/bin/mkcert
mkcert -install
mkcert demo.local api.demo.local grafana.demo.local

Bei WSL musst du beachten: Vertrauen in WSL bedeutet nicht automatisch Vertrauen in Windows Edge. Für Edge muss die CA im Windows-Zertifikatsspeicher landen. Das erledigst du am einfachsten, indem du mkcert zusätzlich nativ unter Windows installierst oder die CA manuell importierst.


23 / 39

24. Registry, Images und Build-Flows

24.1 Bild direkt in kind laden

bash
docker build -t demo-app:0.1.0 .
kind load docker-image demo-app:0.1.0 --name workshop

Manifest:

yaml
image: demo-app:0.1.0
imagePullPolicy: IfNotPresent

24.2 Bild direkt in minikube bauen

bash
eval "$(minikube docker-env)"
docker build -t demo-app:0.1.0 .

Danach Deployment im Cluster:

yaml
image: demo-app:0.1.0
imagePullPolicy: IfNotPresent

Zurück zum normalen Docker:

bash
eval "$(minikube docker-env -u)"

24.3 k3d-Image importieren

bash
docker build -t demo-app:0.1.0 .
k3d image import demo-app:0.1.0 -c workshop

24.4 Lokale Registry verwenden

Für längere Workshops ist eine lokale Registry sauberer als wiederholtes Image-Loading.

bash
docker run -d --restart=always \
  --name local-registry \
  -p 127.0.0.1:5001:5000 \
  registry:2

Image:

bash
docker build -t localhost:5001/demo-app:0.1.0 .
docker push localhost:5001/demo-app:0.1.0

Achte darauf, dass dein Cluster die Registry ebenfalls erreichen kann. Bei kind und k3d brauchst du dafür eine passende Container-Network- oder Registry-Konfiguration.

24.5 ImagePull-Probleme prüfen

bash
kubectl describe pod <pod> -n <namespace>
kubectl get events -n <namespace> --sort-by=.lastTimestamp
kubectl get pod <pod> -n <namespace> -o jsonpath='{.status.containerStatuses[*].state.waiting.reason}'

Typische Ursachen:

  • falscher Image-Name,
  • fehlender Tag,
  • private Registry ohne Secret,
  • Cluster kann lokale Registry nicht erreichen,
  • imagePullPolicy: Always trotz nur lokal geladenem Image.

24 / 39

25. Storage in WSL-basierten Clustern

25.1 Grundsatz

Lokaler Storage in WSL ist für Labs geeignet, aber nicht mit produktivem Storage gleichzusetzen.

25.2 kind Storage

kind bringt standardmäßig einen lokalen StorageClass-Mechanismus mit.

bash
kubectl get storageclass
kubectl get pv,pvc -A

PVC-Test:

bash
kubectl create namespace storage-demo --dry-run=client -o yaml | kubectl apply -f -
cat > /tmp/pvc.yaml <<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data
  namespace: storage-demo
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
EOF
kubectl apply -f /tmp/pvc.yaml
kubectl get pvc -n storage-demo

25.3 minikube Storage

bash
minikube addons list | grep -i storage || true
kubectl get storageclass

25.4 WSL-Dateien als Bind-Mounts

Bei Docker-basierten Clustern kannst du Host-Verzeichnisse einbinden. Nutze bevorzugt Linux-Pfade unter /home, nicht /mnt/c.

Beispiel kind:

yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
    extraMounts:
      - hostPath: /home/<du>/workshops/data
        containerPath: /data

25.5 Backup-Regel

Für Workshopdaten gilt:

  • Manifeste ins Git-Repository,
  • generierte Daten nach ~/tmp oder ~/clusters,
  • keine produktiven Secrets,
  • Cluster jederzeit löschbar halten,
  • wichtige Notizen außerhalb des Cluster-Storage sichern.

25 / 39

26. Netzwerkmodell und typische Stolperstellen

26.1 WSL-NAT und localhost

Im Standardmodus läuft WSL2 hinter NAT. Anwendungen, die in WSL auf localhost lauschen, sind in vielen Fällen vom Windows-Host über localhost erreichbar. Das reicht für kubectl port-forward und viele Ingress-Port-Mappings.

26.2 Mirrored Networking

Mirrored Networking spiegelt Windows-Netzwerkschnittstellen stärker nach WSL. Das kann mit VPNs und LAN-Zugriff helfen. Es kann aber auch neue Firewall-Fragen erzeugen.

26.3 Firewall

Wenn Edge den Dienst nicht erreicht:

powershell
Test-NetConnection localhost -Port 8080
Test-NetConnection demo.local -Port 80

Prüfe:

  • Windows Defender Firewall,
  • Unternehmens-Endpoint-Security,
  • Docker Desktop Firewall-Hinweise,
  • blockierte Ports,
  • belegte Ports.

26.4 Belegte Ports finden

PowerShell:

powershell
Get-NetTCPConnection -LocalPort 80 -ErrorAction SilentlyContinue
Get-Process -Id (Get-NetTCPConnection -LocalPort 80).OwningProcess

WSL:

bash
sudo ss -tulpn | grep -E ':80|:443|:8080|:8443' || true

26.5 DNS-Fehler unterscheiden

Windows:

powershell
Resolve-DnsName demo.local

WSL:

bash
getent hosts demo.local
nslookup demo.local || true

Cluster:

bash
kubectl run dns-debug --rm -it --restart=Never --image=busybox:1.36 -- nslookup kubernetes.default.svc.cluster.local

26.6 Ingress-Fehler unterscheiden

bash
kubectl get ingress -A
kubectl describe ingress -n demo web
kubectl get pods -n ingress-nginx -o wide
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller --tail=100
curl -v -H 'Host: demo.local' http://127.0.0.1

26 / 39

27. Provisionierungsablauf für die Workshop-Dateien

27.1 Ziel

Bereite die Workshop-Umgebung aus WSL heraus reproduzierbar vor.

Allgemeiner Ablauf:

flowchart TD
    Material[Workshop-Material laden] --> Check[Preflight prüfen]
    Check --> Tools[Werkzeuge installieren]
    Tools --> Runtime[Docker oder Runtime prüfen]
    Runtime --> Variant[Cluster-Variante wählen]
    Variant --> Cluster[Cluster erstellen]
    Cluster --> Addons[Add-ons installieren]
    Addons --> Hosts[Windows Hosts-Datei setzen]
    Hosts --> Validate[Validierung]
    Validate --> Labs[Workshop-Labs]

27.2 Workshop-Material laden

Öffne die Dokumentation im Orthevs Wiki und lade die für deine Übung benötigten Beispiel-ZIPs von der Kubernetes-Workshop-Seite. Entpacke die Pakete in ~/workshops/kubernetes-workshop.

27.3 Dry-Run verwenden

Wenn du in deiner eigenen Übungsumgebung ein Provisionierungsskript verwendest:

bash
./scripts/provision.sh --dry-run

Für eine WSL-kind-Variante könnte ein Ziel so aussehen:

bash
./scripts/provision.sh --target wsl-kind --dry-run
./scripts/provision.sh --target wsl-kind

Für minikube:

bash
./scripts/provision.sh --target wsl-minikube --dry-run
./scripts/provision.sh --target wsl-minikube

Für k3d:

bash
./scripts/provision.sh --target wsl-k3d --dry-run
./scripts/provision.sh --target wsl-k3d

Falls das Repository solche Targets noch nicht enthält, kannst du die folgenden Konventionen verwenden.

27.4 Empfohlene Target-Namen

Target Bedeutung
wsl-tools Installiert CLI-Werkzeuge.
wsl-docker-check Prüft Docker-Verfügbarkeit.
wsl-kind Erstellt kind-Cluster mit Ingress-Port-Mapping.
wsl-minikube Erstellt minikube-Cluster mit Docker-Treiber.
wsl-k3d Erstellt k3d-Cluster mit Port-Mappings.
wsl-hosts Erstellt Windows-Hosts-Skripte oder startet Admin-Prompt.
wsl-validate Prüft Werkzeuge, Cluster, DNS, Ingress und Browser-Pfade.
wsl-clean Baut lokale Cluster zurück.

27.5 Beispiel: Makefile

makefile
.PHONY: wsl-tools wsl-kind wsl-minikube wsl-k3d wsl-validate wsl-clean

wsl-tools:
	./scripts/wsl/install-tools.sh

wsl-kind:
	kind create cluster --config clusters/kind/workshop.yaml
	kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml

wsl-minikube:
	minikube start --driver=docker --cpus=4 --memory=8192
	minikube addons enable ingress
	minikube addons enable metrics-server

wsl-k3d:
	k3d cluster create workshop --servers 1 --agents 2 --api-port 127.0.0.1:6550 -p "80:80@loadbalancer" -p "443:443@loadbalancer"

wsl-validate:
	./scripts/wsl/validate.sh

wsl-clean:
	kind delete cluster --name workshop || true
	minikube delete || true
	k3d cluster delete workshop || true

27.6 Beispiel: Preflight-Skript

bash
mkdir -p scripts/wsl
cat > scripts/wsl/preflight.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

required=(git curl jq yq kubectl docker)
missing=0

for cmd in "${required[@]}"; do
  if ! command -v "$cmd" >/dev/null 2>&1; then
    echo "FEHLT: $cmd"
    missing=1
  else
    echo "OK: $cmd -> $(command -v "$cmd")"
  fi
done

if ! docker info >/dev/null 2>&1; then
  echo "FEHLER: Docker ist nicht erreichbar. Prüfe Docker Desktop WSL Integration oder native Docker Engine."
  missing=1
fi

if ! grep -qi microsoft /proc/version; then
  echo "WARNUNG: Diese Umgebung sieht nicht nach WSL aus."
fi

if [ "$missing" -ne 0 ]; then
  exit 1
fi
EOF
chmod +x scripts/wsl/preflight.sh

Ausführen:

bash
./scripts/wsl/preflight.sh

27 / 39

28. Validierung

28.1 WSL-Basis

bash
uname -a
cat /etc/os-release
ps -p 1 -o comm=
mount | grep drvfs || true

Erwartung:

  • Ubuntu LTS,
  • WSL2-Kernel,
  • systemd als PID 1,
  • /mnt/c eingebunden.

28.2 Docker

bash
docker version
docker info --format '{{.ServerVersion}}'
docker run --rm hello-world

28.3 Kubernetes-CLI

bash
kubectl version --client
kubectl config get-contexts
kubectl config current-context || true

28.4 Cluster

bash
kubectl cluster-info
kubectl get nodes -o wide
kubectl get pods -A
kubectl get events -A --sort-by=.lastTimestamp | tail -50

28.5 DNS im Cluster

bash
kubectl run dns-test --rm -it --restart=Never --image=busybox:1.36 -- \
  nslookup kubernetes.default.svc.cluster.local

28.6 Service und Ingress

bash
kubectl get svc -A
kubectl get ingress -A
curl -v http://localhost || true
curl -v http://demo.local || true

28.7 Windows-Browser

PowerShell:

powershell
Resolve-DnsName demo.local
Test-NetConnection demo.local -Port 80

Edge:

text
http://demo.local

28.8 Validierungstabelle

| Prüfung | Kommando | Erwartung | |---|---|---| | WSL2 aktiv | wsl -l -v | Ubuntu läuft mit Version 2. | | systemd aktiv | ps -p 1 -o comm= | systemd. | | Docker erreichbar | docker run --rm hello-world | Container läuft. | | kubectl installiert | kubectl version --client | Client-Version wird angezeigt. | | Cluster erreichbar | kubectl get nodes | Mindestens ein Node. | | CoreDNS läuft | kubectl get pods -n kube-system | DNS-Pods laufen. | | Ingress läuft | kubectl get pods -A | grep ingress | Controller läuft. | | Windows-DNS passt | Resolve-DnsName demo.local | 127.0.0.1 oder Zieladresse. | | Edge erreicht App | Browser-Test | HTTP-Antwort der Demo-App. |


28 / 39

29. Troubleshooting

29.1 Docker ist in WSL nicht erreichbar

Symptom:

text
Cannot connect to the Docker daemon

Prüfen:

bash
docker context ls
docker info
ls -l /var/run/docker.sock || true

Lösung Docker Desktop:

  • Docker Desktop starten.
  • WSL Integration für Ubuntu aktivieren.
  • WSL neu starten.
powershell
wsl --shutdown

Lösung native Docker Engine:

bash
sudo systemctl status docker --no-pager
sudo systemctl restart docker
sudo usermod -aG docker "$USER"
newgrp docker

29.2 systemctl funktioniert nicht

Symptom:

text
System has not been booted with systemd

Lösung:

bash
sudo tee /etc/wsl.conf <<'EOF'
[boot]
systemd=true
EOF

PowerShell:

powershell
wsl --shutdown

Danach WSL neu starten und prüfen:

bash
ps -p 1 -o comm=

29.3 Edge erreicht demo.local nicht

Prüfen:

powershell
Resolve-DnsName demo.local
Test-NetConnection demo.local -Port 80

Wenn DNS falsch ist:

  • Windows-Hosts-Datei prüfen,
  • ipconfig /flushdns ausführen,
  • Browser neu laden.

Wenn Port nicht erreichbar ist:

  • kind/k3d Port-Mapping prüfen,
  • Ingress Controller prüfen,
  • Portbelegung prüfen,
  • Firewall prüfen.

29.4 curl http://demo.local funktioniert in WSL, aber Edge nicht

Wahrscheinliche Ursache:

  • Nur /etc/hosts in WSL wurde geändert.
  • Windows-Hosts-Datei fehlt.

Lösung:

powershell
notepad $env:windir\System32\drivers\etc\hosts
ipconfig /flushdns

Eintrag:

text
127.0.0.1 demo.local

29.5 Edge funktioniert, aber curl in WSL nicht

Mögliche Ursachen:

  • WSL /etc/hosts hat keinen Eintrag,
  • DNS-Generierung überschreibt Einträge,
  • Proxy oder VPN beeinflusst WSL.

Prüfen:

bash
getent hosts demo.local
cat /etc/hosts | tail -50

Für WSL-internen Test kannst du direkt setzen:

bash
echo '127.0.0.1 demo.local' | sudo tee -a /etc/hosts

Beachte: Bei generateHosts=true kann WSL /etc/hosts beim Neustart neu erzeugen.

29.6 Ingress gibt 404 zurück

Prüfen:

bash
kubectl get ingress -A
kubectl describe ingress -n demo web
kubectl get svc -n demo
kubectl get endpoints -n demo
curl -v -H 'Host: demo.local' http://127.0.0.1

Typische Ursachen:

  • falscher Hostname im Ingress,
  • falsche ingressClassName,
  • Service-Port falsch,
  • Service hat keine Endpoints,
  • Deployment-Pods sind nicht bereit.

29.7 Service hat keine Endpoints

bash
kubectl get svc,endpoints,pods -n demo -o wide
kubectl describe svc web -n demo
kubectl get pods -n demo --show-labels

Ursache meist:

  • Service-Selector passt nicht zu Pod-Labels.

29.8 Pod bleibt Pending

bash
kubectl describe pod <pod> -n <namespace>
kubectl get events -n <namespace> --sort-by=.lastTimestamp
kubectl describe nodes

Mögliche Ursachen:

  • zu wenig CPU oder Speicher,
  • PVC nicht gebunden,
  • Taints ohne Tolerations,
  • Image kann nicht gezogen werden,
  • Scheduler-Constraints passen nicht.

29.9 Pod ist CrashLoopBackOff

bash
kubectl logs <pod> -n <namespace> --previous
kubectl describe pod <pod> -n <namespace>

Mögliche Ursachen:

  • App startet nicht,
  • falsche Umgebungsvariable,
  • Secret fehlt,
  • ConfigMap falsch,
  • Probe zu aggressiv,
  • falscher Startbefehl.

29.10 ImagePullBackOff

bash
kubectl describe pod <pod> -n <namespace>
kubectl get events -n <namespace> --sort-by=.lastTimestamp

Lösung je nach Ursache:

bash
kind load docker-image demo-app:0.1.0 --name workshop
k3d image import demo-app:0.1.0 -c workshop
eval "$(minikube docker-env)"
docker build -t demo-app:0.1.0 .

29.11 Port 80 ist belegt

PowerShell:

powershell
Get-NetTCPConnection -LocalPort 80 -ErrorAction SilentlyContinue

WSL:

bash
sudo ss -tulpn | grep ':80' || true

Lösung:

  • Port ändern, zum Beispiel 8080,
  • blockierenden Dienst beenden,
  • Docker/kind/k3d Port-Mapping anpassen.

29.12 WSL verliert DNS bei VPN

Prüfen:

bash
cat /etc/resolv.conf
nslookup github.com || true
curl -I https://kubernetes.io || true

Mögliche Lösungen:

  • WSL aktualisieren,
  • dnsTunneling=true setzen,
  • autoProxy=true setzen,
  • Unternehmens-Proxy korrekt konfigurieren,
  • WSL neu starten.

29 / 39

30. Rückbau

30.1 kind

bash
kind get clusters
kind delete cluster --name workshop

30.2 minikube

bash
minikube delete
rm -rf ~/.minikube

30.3 k3d

bash
k3d cluster list
k3d cluster delete workshop

30.4 Docker Desktop Kubernetes

In Docker Desktop:

  • Kubernetes deaktivieren oder Reset verwenden.

CLI-Prüfung:

bash
kubectl config delete-context docker-desktop || true

30.5 kubeadm

bash
sudo kubeadm reset -f
sudo rm -rf ~/.kube /etc/cni/net.d /var/lib/cni /var/lib/kubelet /var/lib/etcd
sudo systemctl restart containerd || true

30.6 k3s

bash
sudo /usr/local/bin/k3s-uninstall.sh || true

30.7 Windows-Hosts-Einträge entfernen

Administrative PowerShell:

powershell
notepad $env:windir\System32\drivers\etc\hosts
ipconfig /flushdns

Oder das Entfernen-Skript aus Kapitel 11 verwenden.

30.8 Docker aufräumen

Achtung: Das löscht lokale Container, Netzwerke und Images nach Auswahl.

bash
docker ps -a
docker network ls
docker volume ls

docker container prune
docker network prune
docker image prune

30 / 39

31. Workshop-Labs

31.1 Lab 1: WSL installieren und systemd aktivieren

Ziel:

  • Du installierst WSL2 mit Ubuntu.
  • Du aktivierst systemd.
  • Du prüfst Windows-/WSL-Interop.

Abnahme:

bash
ps -p 1 -o comm=
systemctl list-unit-files --type=service | head
powershell.exe -NoProfile -Command '$PSVersionTable.PSVersion'

31.2 Lab 2: Docker aus WSL nutzen

Ziel:

  • Du verbindest WSL mit Docker Desktop oder installierst Docker Engine in WSL.

Abnahme:

bash
docker version
docker run --rm hello-world

31.3 Lab 3: kind-Cluster mit Ingress

Ziel:

  • Du erstellst einen kind-Cluster mit Port-Mapping.
  • Du installierst Ingress-NGINX.
  • Du erreichst eine App im Edge Browser.

Abnahme:

bash
kubectl get nodes
kubectl get pods -A
curl -H 'Host: demo.local' http://127.0.0.1

Browser:

text
http://demo.local

31.4 Lab 4: Windows-Hosts-Datei automatisieren

Ziel:

  • Du erstellst ein PowerShell-Skript für Hosts-Einträge.
  • Du entfernst die Einträge wieder sauber.

Abnahme:

powershell
Resolve-DnsName demo.local
ipconfig /displaydns | Select-String demo.local

31.5 Lab 5: minikube mit Add-ons

Ziel:

  • Du startest minikube mit Docker-Treiber.
  • Du aktivierst Ingress und Metrics Server.
  • Du testest kubectl top.

Abnahme:

bash
minikube status
kubectl top nodes || true
kubectl get pods -A

31.6 Lab 6: k3d mit Traefik oder Ingress-NGINX

Ziel:

  • Du erstellst einen K3s-basierten Cluster.
  • Du routest Traffic über Port 80.

Abnahme:

bash
k3d cluster list
kubectl get ingress -A
curl http://demo.local

31.7 Lab 7: Image-Build und lokales Laden

Ziel:

  • Du baust ein lokales Image.
  • Du lädst es in kind, minikube oder k3d.

Abnahme:

bash
kubectl get pods -n demo
kubectl describe pod -n demo -l app=demo-app

31.8 Lab 8: Troubleshooting

Ziel:

  • Du unterscheidest DNS-, Port-, Ingress-, Service- und Pod-Probleme.

Abnahme:

bash
kubectl get events -A --sort-by=.lastTimestamp | tail -50
kubectl describe ingress -A
kubectl get svc,endpoints,pods -n demo -o wide

31 / 39

32. Sicherheits- und Betriebsregeln

32.1 Keine produktiven Daten

In WSL-Labs gehören keine produktiven:

  • Kundendaten,
  • Tokens,
  • Cloud-Zugangsdaten,
  • privaten Schlüssel,
  • Registry-Credentials,
  • produktiven Kubeconfigs.

32.2 Kubeconfigs schützen

bash
chmod 700 ~/.kube
chmod 600 ~/.kube/config

32.3 Secrets prüfen

bash
grep -RInE '(BEGIN PRIVATE KEY|password|token|secret|AKIA|client_secret)' . \
  --exclude-dir=.git || true

32.4 Cluster sind wegwerfbar

Lokale WSL-Cluster sollten jederzeit löschbar sein. Der autoritative Zustand liegt in:

  • Git,
  • dokumentierten Skripten,
  • versionierten Manifesten,
  • reproduzierbaren Konfigurationen.

32.5 Adminrechte bewusst nutzen

Du brauchst Administratorrechte nur für:

  • WSL-Installation,
  • einzelne Windows-Features,
  • Hosts-Datei,
  • gegebenenfalls Firewall-Regeln,
  • Docker Desktop Installation.

Führe Kubernetes-Labs nicht dauerhaft in einer administrativen Shell aus.


32 / 39

33. Checklisten

33.1 Preflight Windows

Punkt Status
Windows 11 aktuell
Virtualisierung im BIOS/UEFI aktiv
WSL installiert
WSL aktualisiert
Ubuntu läuft mit WSL2
Docker Desktop oder Docker Engine verfügbar
Hosts-Datei darf administrativ bearbeitet werden
Unternehmensproxy geklärt
Keine produktiven Secrets im Lab

33.2 Preflight WSL

Punkt Kommando Status
Ubuntu-Version cat /etc/os-release
systemd ps -p 1 -o comm=
sudo sudo -v
Docker docker run --rm hello-world
kubectl kubectl version --client
helm helm version
Git git status
Windows-Interop powershell.exe -NoProfile -Command '$PSVersionTable'

33.3 Cluster-Check

Punkt Kommando Status
Kontext korrekt kubectl config current-context
Nodes Ready kubectl get nodes
System-Pods Ready kubectl get pods -A
DNS funktioniert kubectl run dns-test ...
Demo-Service hat Endpoints kubectl get endpoints -n demo
Ingress existiert kubectl get ingress -A
Browser-Zugriff funktioniert http://demo.local

33.4 Rückbau-Check

Punkt Kommando Status
kind gelöscht kind get clusters
minikube gelöscht minikube status
k3d gelöscht k3d cluster list
k3s entfernt systemctl status k3s
kubeadm zurückgesetzt kubectl get nodes
Hosts-Einträge entfernt Windows-Hosts-Datei prüfen
Docker-Reste geprüft docker ps -a

33 / 39

34. Referenzkommandos

34.1 WSL-Kommandos in PowerShell

powershell
wsl --install -d Ubuntu-24.04
wsl --update
wsl --version
wsl --status
wsl --list --verbose
wsl --set-default-version 2
wsl --set-version Ubuntu-24.04 2
wsl --shutdown
wsl -d Ubuntu-24.04

34.2 Windows-Hosts-Datei

powershell
notepad $env:windir\System32\drivers\etc\hosts
ipconfig /flushdns
Resolve-DnsName demo.local
Test-NetConnection demo.local -Port 80

34.3 WSL-Systemprüfung

bash
uname -a
cat /etc/os-release
ps -p 1 -o comm=
systemctl is-system-running || true
ip addr
ip route
cat /etc/resolv.conf

34.4 Docker

bash
docker version
docker info
docker ps
docker network ls
docker volume ls
docker run --rm hello-world

34.5 kubectl

bash
kubectl version --client
kubectl config get-contexts
kubectl config current-context
kubectl cluster-info
kubectl get nodes -o wide
kubectl get pods -A
kubectl get events -A --sort-by=.lastTimestamp | tail -50

34.6 kind

bash
kind version
kind create cluster --name workshop
kind create cluster --config clusters/kind/workshop.yaml
kind get clusters
kind load docker-image demo-app:0.1.0 --name workshop
kind delete cluster --name workshop

34.7 minikube

bash
minikube version
minikube start --driver=docker --cpus=4 --memory=8192
minikube status
minikube addons list
minikube addons enable ingress
minikube addons enable metrics-server
minikube service <service> -n <namespace> --url
minikube tunnel
minikube delete

34.8 k3d

bash
k3d version
k3d cluster create workshop --servers 1 --agents 2 --api-port 127.0.0.1:6550 -p "80:80@loadbalancer" -p "443:443@loadbalancer"
k3d cluster list
k3d kubeconfig get workshop
k3d image import demo-app:0.1.0 -c workshop
k3d cluster delete workshop

34.9 kubeadm

bash
sudo kubeadm init --config clusters/kubeadm/init.yaml
mkdir -p ~/.kube
sudo cp -i /etc/kubernetes/admin.conf ~/.kube/config
sudo chown "$(id -u):$(id -g)" ~/.kube/config
kubectl get nodes
sudo kubeadm reset -f

34.10 k3s

bash
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--write-kubeconfig-mode=644" sh -
sudo systemctl status k3s --no-pager
kubectl --kubeconfig /etc/rancher/k3s/k3s.yaml get nodes
sudo /usr/local/bin/k3s-uninstall.sh

34 / 39

Primäre Referenzen für diese Datei:

  • Microsoft Learn: WSL installieren
    https://learn.microsoft.com/en-us/windows/wsl/install
  • Microsoft Learn: WSL-Konfiguration mit .wslconfig und wsl.conf
    https://learn.microsoft.com/en-us/windows/wsl/wsl-config
  • Microsoft Learn: Netzwerkzugriff mit WSL
    https://learn.microsoft.com/en-us/windows/wsl/networking
  • Docker Docs: Docker Desktop WSL2 Backend
    https://docs.docker.com/desktop/features/wsl/
  • Docker Docs: Docker Desktop Kubernetes
    https://docs.docker.com/desktop/use-desktop/kubernetes/
  • Kubernetes Docs: kubectl installieren
    https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/
  • Kubernetes Docs: kubeadm
    https://kubernetes.io/docs/reference/setup-tools/kubeadm/
  • Kubernetes Docs: kubeadm installieren
    https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
  • Kubernetes Docs: Cluster mit kubeadm erstellen
    https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/
  • Kubernetes Docs: Container Runtimes
    https://kubernetes.io/docs/setup/production-environment/container-runtimes/
  • kind Dokumentation
    https://kind.sigs.k8s.io/docs/user/quick-start/
  • kind Konfiguration und Port-Mappings
    https://kind.sigs.k8s.io/docs/user/configuration/
  • kind unter WSL2
    https://kind.sigs.k8s.io/docs/user/using-wsl2/
  • minikube Start und Treiber
    https://minikube.sigs.k8s.io/docs/start/
    https://minikube.sigs.k8s.io/docs/drivers/
  • minikube App-Zugriff
    https://minikube.sigs.k8s.io/docs/handbook/accessing/
  • k3d Dokumentation
    https://k3d.io/
  • K3s Dokumentation
    https://docs.k3s.io/
  • MicroK8s WSL2
    https://microk8s.io/docs/install-wsl2

35 / 39

Anhang A: Minimaler kind-End-to-End-Quickstart

bash
# 1. Docker prüfen
docker run --rm hello-world

# 2. kind-Konfiguration
mkdir -p clusters/kind
cat > clusters/kind/workshop.yaml <<'EOF'
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: workshop
nodes:
  - role: control-plane
    kubeadmConfigPatches:
      - |
        kind: InitConfiguration
        nodeRegistration:
          kubeletExtraArgs:
            node-labels: "ingress-ready=true"
    extraPortMappings:
      - containerPort: 80
        hostPort: 80
        protocol: TCP
      - containerPort: 443
        hostPort: 443
        protocol: TCP
  - role: worker
EOF

# 3. Cluster erstellen
kind create cluster --config clusters/kind/workshop.yaml

# 4. Ingress installieren
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=180s

# 5. Demo bereitstellen
kubectl create namespace demo --dry-run=client -o yaml | kubectl apply -f -
kubectl create deployment web --image=nginx:1.27 -n demo
kubectl expose deployment web --port=80 --target-port=80 -n demo
cat > /tmp/ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  namespace: demo
spec:
  ingressClassName: nginx
  rules:
    - host: demo.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80
EOF
kubectl apply -f /tmp/ingress.yaml

# 6. Test aus WSL
curl -H 'Host: demo.local' http://127.0.0.1

Windows-Hosts-Datei:

text
127.0.0.1 demo.local

Edge:

text
http://demo.local

36 / 39

Anhang B: Minimaler minikube-End-to-End-Quickstart

bash
# 1. Cluster starten
minikube start --driver=docker --cpus=4 --memory=8192

# 2. Add-ons
minikube addons enable ingress
minikube addons enable metrics-server

# 3. Demo
kubectl create namespace demo --dry-run=client -o yaml | kubectl apply -f -
kubectl create deployment web --image=nginx:1.27 -n demo
kubectl expose deployment web --port=80 --target-port=80 -n demo

# 4. Stabiler Browser-Zugriff über Port-Forward
kubectl port-forward -n demo --address 0.0.0.0 svc/web 8080:80

Edge:

text
http://localhost:8080

37 / 39

Anhang C: Minimaler k3d-End-to-End-Quickstart

bash
# 1. Cluster erstellen
k3d cluster create workshop \
  --servers 1 \
  --agents 2 \
  --api-port 127.0.0.1:6550 \
  -p "80:80@loadbalancer" \
  -p "443:443@loadbalancer"

# 2. Demo
kubectl create namespace demo --dry-run=client -o yaml | kubectl apply -f -
kubectl create deployment web --image=nginx:1.27 -n demo
kubectl expose deployment web --port=80 --target-port=80 -n demo

# 3. Ingress
cat > /tmp/k3d-demo-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  namespace: demo
spec:
  rules:
    - host: demo.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80
EOF
kubectl apply -f /tmp/k3d-demo-ingress.yaml

# 4. Test
curl -H 'Host: demo.local' http://127.0.0.1

Windows-Hosts-Datei:

text
127.0.0.1 demo.local

Edge:

text
http://demo.local

38 / 39

Anhang D: Empfohlene Workshop-Standardentscheidung

Für die meisten Gruppen verwendest du:

text
Windows 11
  -> WSL2
    -> Ubuntu LTS
      -> Docker Desktop WSL Integration
        -> kind
          -> Ingress-NGINX
            -> Windows Hosts-Datei
              -> Edge Browser

Warum:

  • am schnellsten reproduzierbar,
  • wenig VM-Overhead,
  • gute Übereinstimmung mit CI-Clustern,
  • gut für Kubernetes-Objektmodell, Deployments, Services, Ingress, ConfigMaps, Secrets, RBAC und Troubleshooting,
  • einfach rückbaubar.

Für kubeadm, HA, CNI-Deep-Dive, etcd, Node-Lifecycle und produktionsnahen Betrieb wechselst du auf native VM-, Bare-Metal- oder Remote-Cluster.

39 / 39

K8S · Orthevs Academy

31 modules as one continuous learning path.

The sequence remains unchanged: from the lab skeleton through technical foundations and operating models to final troubleshooting. The technical directory names are deliberately preserved.

Orthevs – Engineering the foundation for what comes next.

Orthevs as an app

Install Orthevs

The Orthevs web app can be installed on supported mobile devices and desktop browsers.

iPhone and iPad

Open Orthevs in Safari. Tap Share, then Add to Home Screen. Enable Open as Web App if offered, then tap Add.

Android

For the web app, open the browser menu and choose Install app or Add to Home screen. Confirm the installation.

Desktop browser

Open the browser menu or the install icon in the address bar, then choose Install app or Add to Dock.

Web app installation depends on your browser. If no install prompt appears, follow the browser steps shown above.