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,k3soder experimentell mitkubeadmbereitzustellen, - 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.
2. Zielbild
Am Ende hast du auf deinem Windows-11-Rechner:
- eine aktuelle WSL2-Distribution, bevorzugt Ubuntu LTS,
- aktiviertes
systemdin 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/dund 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
localhosterreichbar machen.
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]
4. Unterstützte Varianten
Diese Datei behandelt folgende Bereitstellungswege:
WSL als Kubernetes-Client
kubectl,helm,kustomize,stern,k9s,jq,yq- Verbindung zu Remote-Clustern
kind in WSL
- Kubernetes-Nodes als Docker-Container
- gute Port-Mappings für Ingress
- sehr gut für Workshops
minikube in WSL
- bevorzugt mit Docker-Treiber
- optional SSH- oder None-Treiber für Spezialfälle
- Add-ons wie Ingress, Metrics Server und Dashboard
k3d in WSL
- K3s in Docker
- einfache lokale Load-Balancer-Portfreigaben
- schnell für K3s-nahe Labs
Docker Desktop Kubernetes
- Kubernetes in Docker Desktop aktivieren
- schnell, aber weniger kontrollierbar
kubeadm in WSL
- nur für experimentelles Verständnis
- nicht als Standard-Lab empfohlen
k3s direkt in WSL
- leichtgewichtig
- Systemdienst- und Netzwerkbesonderheiten beachten
MicroK8s, k0s und weitere Distributionen
- optional erwähnen und einordnen
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
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 ipunter dem Docker-Treiber immer direkt vom Windows-Browser erreichbar ist,- Änderungen an
/etc/hostsautomatisch 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.
7. WSL2 installieren und prüfen
7.1 WSL installieren
Öffne PowerShell als Administrator.
wsl --install -d Ubuntu-24.04
Falls Ubuntu 24.04 nicht verfügbar ist, prüfe die verfügbaren Distributionen:
wsl --list --online
Installiere dann eine passende Ubuntu-LTS-Version:
wsl --install -d Ubuntu
7.2 WSL aktualisieren
wsl --update
wsl --version
7.3 WSL2 als Standard setzen
wsl --set-default-version 2
7.4 Installierte Distributionen prüfen
wsl --list --verbose
Erwartung:
NAME STATE VERSION
* Ubuntu-24.04 Running 2
Falls deine Distribution noch WSL1 verwendet:
wsl --set-version Ubuntu-24.04 2
7.5 Distribution starten
wsl -d Ubuntu-24.04
Oder über das Startmenü:
Ubuntu 24.04
7.6 Windows-Informationen erfassen
Für spätere Fehlersuche dokumentierst du:
winver
wsl --version
wsl --status
wsl --list --verbose
8. Ubuntu in WSL vorbereiten
8.1 System aktualisieren
In Ubuntu unter WSL:
sudo apt update
sudo apt full-upgrade -y
sudo apt autoremove -y
8.2 Basiswerkzeuge installieren
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
whoami
id
sudo -v
Dein Benutzer muss sudo nutzen können.
8.4 Zeitzone setzen
timedatectl
sudo timedatectl set-timezone Europe/Berlin
Falls timedatectl noch nicht funktioniert, aktiviere zuerst systemd gemäß Kapitel 9.
8.5 Git konfigurieren
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:
mkdir -p ~/workshops
cd ~/workshops
Nicht empfohlen für intensive Kubernetes- und Docker-Workflows:
cd /mnt/c/Users/<dein-user>/Documents
Das funktioniert, ist aber bei vielen kleinen Dateien und Bind-Mounts oft deutlich langsamer.
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:
notepad $env:USERPROFILE\.wslconfig
Empfohlener Standard für viele Workshop-Rechner:
[wsl2]
memory=8GB
processors=4
swap=4GB
localhostForwarding=true
dnsTunneling=true
autoProxy=true
[experimental]
autoMemoryReclaim=gradual
sparseVhd=true
Danach WSL vollständig neu starten:
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.
[wsl2]
networkingMode=mirrored
dnsTunneling=true
autoProxy=true
localhostForwarding=true
Danach:
wsl --shutdown
Hinweise:
mirroredist 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=truehäufig ausreichend. - Wenn du
mirroredaktivierst, teste Docker,kind,minikube, DNS und Edge-Zugriff erneut.
9.3 systemd in Ubuntu aktivieren
Öffne in WSL:
sudo nano /etc/wsl.conf
Empfohlene Workshop-Konfiguration:
[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:
wsl --shutdown
wsl -d Ubuntu-24.04
Prüfe in WSL:
ps -p 1 -o comm=
systemctl is-system-running || true
systemctl list-unit-files --type=service | head
Erwartung:
systemd
9.4 Windows-Laufwerke prüfen
ls -ld /mnt/c
ls -l /mnt/c/Windows/System32/drivers/etc/hosts
Wenn /mnt/c fehlt:
mount | grep drvfs || true
Dann wsl.conf prüfen und WSL neu starten.
9.5 Interop prüfen
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.
10. Dateisystem- und Workshop-Layout
10.1 Empfohlenes Layout
/home/<du>/workshops/
├── kubernetes-workshop/
├── clusters/
│ ├── kind/
│ ├── minikube/
│ └── k3d/
├── bin/
└── tmp/
Anlegen:
mkdir -p ~/workshops ~/clusters/{kind,minikube,k3d} ~/bin ~/tmp
~/bin in den Pfad aufnehmen:
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
find ~/workshops/kubernetes-workshop -maxdepth 3 -type f | sort | head -100
10.4 Geheimnisse vermeiden
Vor jeder Änderung:
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.
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:
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:
notepad $env:windir\System32\drivers\etc\hosts
Füge für lokale Ingress-Labs zum Beispiel hinzu:
# 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:
ipconfig /flushdns
11.4 Hosts-Datei aus WSL über PowerShell öffnen
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:
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.exe -NoProfile -ExecutionPolicy Bypass -File C:\Pfad\zum\Repository\scripts\windows\add-k8s-hosts.ps1
Oder aus WSL heraus starten:
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
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.exe -NoProfile -ExecutionPolicy Bypass -File C:\Pfad\zum\Repository\scripts\windows\remove-k8s-hosts.ps1
11.7 Prüfen aus Windows
In PowerShell:
Resolve-DnsName demo.local
Test-NetConnection demo.local -Port 80
Im Browser:
http://demo.local
11.8 Prüfen aus WSL
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:
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: meist127.0.0.1oder 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.
12. Container Runtime und Docker-Strategie
Die meisten empfohlenen WSL-Varianten nutzen Docker:
kindbenötigt Docker, Podman oder eine kompatible Container Runtime.k3dbenötigt Docker.minikubemit 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:
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:
- Settings öffnen.
- Resources auswählen.
- WSL Integration öffnen.
- Integration für deine Ubuntu-Distribution aktivieren.
- Docker Desktop neu starten.
In WSL prüfen:
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:
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:
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 |
13. Basiswerkzeuge installieren
13.1 Kubernetes-Versionen bewusst behandeln
Setze die Kubernetes-Version nicht hart in jedes Skript. Nutze Variablen:
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
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
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
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:
kubectl kustomize --help | head
Optional eigenständiges kustomize:
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
# 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
for cmd in git curl jq yq docker kubectl helm; do
printf '%-12s' "$cmd"
command -v "$cmd" || true
done
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:
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:
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
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:
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:
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:
extraPortMappings:
- containerPort: 80
hostPort: 8080
protocol: TCP
- containerPort: 443
hostPort: 8443
protocol: TCP
Dann verwendest du im Browser:
http://demo.local:8080
https://demo.local:8443
14.7 Ingress-NGINX 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
14.8 Demo-Anwendung bereitstellen
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:
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:
127.0.0.1 demo.local
Test aus WSL:
curl -H 'Host: demo.local' http://127.0.0.1
curl http://demo.local
Test im Edge Browser:
http://demo.local
14.9 kind mit lokaler Registry
Lokale Registry starten:
docker run -d --restart=always -p 127.0.0.1:5001:5000 --name kind-registry registry:2
kind-Konfiguration mit Registry-Mirror:
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:
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:
docker build -t localhost:5001/demo-app:0.1.0 .
docker push localhost:5001/demo-app:0.1.0
Im Manifest:
image: localhost:5001/demo-app:0.1.0
14.10 kind-Cluster löschen
kind delete cluster --name workshop
docker rm -f kind-registry || true
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 addonsverwenden willst,- schnell
metrics-server, Dashboard, Ingress oder Registry aktivieren möchtest, - Übungen mit Service-Zugriff über
minikube servicemachen willst.
15.2 minikube installieren
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
minikube start \
--driver=docker \
--cpus=4 \
--memory=8192 \
--disk-size=30g
Prüfen:
kubectl config current-context
kubectl get nodes -o wide
minikube status
15.4 Kubernetes-Version setzen
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:
minikube start --driver=docker --kubernetes-version=v1.36.1
Passe die Patchversion vor dem Workshop an.
15.5 Add-ons aktivieren
minikube addons list
minikube addons enable ingress
minikube addons enable metrics-server
Prüfen:
kubectl get pods -A
kubectl top nodes || true
15.6 Demo-Anwendung
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:
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:
kubectl port-forward -n demo --address 0.0.0.0 svc/web 8080:80
Dann in Edge:
http://localhost:8080
Oder mit Hostname:
Windows-Hosts-Datei:
127.0.0.1 demo.local
Browser:
http://demo.local:8080
15.8 Ingress mit minikube
Ingress aktivieren:
minikube addons enable ingress
kubectl wait -n ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=180s
Ingress-Objekt:
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:
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.
minikube tunnel
In einem zweiten Terminal:
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
minikube delete
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
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
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:
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.
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:
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:
127.0.0.1 demo.local
Test:
curl http://demo.local
Browser:
http://demo.local
16.5 k3d ohne Traefik und mit Ingress-NGINX
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:
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
k3d cluster delete workshop
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:
- Settings öffnen.
- Kubernetes auswählen.
- Enable Kubernetes aktivieren.
- Anwenden und warten.
Prüfen in WSL:
kubectl config get-contexts
kubectl config use-context docker-desktop
kubectl get nodes -o wide
17.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
kubectl port-forward -n demo --address 0.0.0.0 svc/web 8080:80
Browser:
http://localhost:8080
17.4 Grenzen
Docker Desktop Kubernetes ist praktisch, aber:
- weniger transparent als
kind,minikubeoderkubeadm, - 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.
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
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:
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
sudo systemctl enable containerd
Prüfen:
systemctl status containerd --no-pager
sudo ctr version
18.3 Kernel- und Netzwerkparameter
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
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
swapon --show || true
free -h
Falls Swap aktiv ist und kubelet damit nicht umgehen soll:
sudo swapoff -a
WSL-Swap wird über .wslconfig gesteuert. Für echte kubeadm-Labs solltest du das Verhalten bewusst festlegen.
18.6 kubeadm-Konfiguration
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
sudo kubeadm init --config clusters/kubeadm/init.yaml
kubectl konfigurieren:
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:
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
Warten:
kubectl get pods -A -w
18.9 Single-Node Scheduling erlauben
kubectl taint nodes --all node-role.kubernetes.io/control-plane- || true
kubectl get nodes
18.10 Demo testen
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:
http://localhost:8080
18.11 kubeadm zurückbauen
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:
kubeadmin 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
kindmeist sinnvoller.
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
k3dmöchtest.
19.2 Installation
curl -sfL https://get.k3s.io | \
INSTALL_K3S_EXEC="--write-kubeconfig-mode=644" \
sh -
Prüfen:
sudo systemctl status k3s --no-pager
kubectl --kubeconfig /etc/rancher/k3s/k3s.yaml get nodes
Kubeconfig übernehmen:
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
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:
http://localhost:8080
19.4 Rückbau
sudo /usr/local/bin/k3s-uninstall.sh
rm -rf ~/.kube/config
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.
21. Remote-Cluster aus WSL verwalten
WSL eignet sich sehr gut als Linux-CLI-Umgebung für Remote-Cluster.
21.1 kubeconfig ablegen
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
kubectl config get-contexts
kubectl config current-context
kubectl cluster-info
kubectl get nodes -o wide
21.3 Mehrere kubeconfigs nutzen
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.
22. Ingress-, Gateway- und Browser-Zugriff
22.1 Grundregel
Damit Edge einen Kubernetes-Endpunkt erreicht, müssen drei Dinge stimmen:
- Der Hostname muss in Windows auflösbar sein.
- Der Zielport muss auf Windows erreichbar sein.
- Der Cluster muss den Hostnamen routen können.
22.2 Standard für kind
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
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:
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:
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.
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
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:
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:
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:
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.
24. Registry, Images und Build-Flows
24.1 Bild direkt in kind laden
docker build -t demo-app:0.1.0 .
kind load docker-image demo-app:0.1.0 --name workshop
Manifest:
image: demo-app:0.1.0
imagePullPolicy: IfNotPresent
24.2 Bild direkt in minikube bauen
eval "$(minikube docker-env)"
docker build -t demo-app:0.1.0 .
Danach Deployment im Cluster:
image: demo-app:0.1.0
imagePullPolicy: IfNotPresent
Zurück zum normalen Docker:
eval "$(minikube docker-env -u)"
24.3 k3d-Image importieren
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.
docker run -d --restart=always \
--name local-registry \
-p 127.0.0.1:5001:5000 \
registry:2
Image:
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
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: Alwaystrotz nur lokal geladenem Image.
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.
kubectl get storageclass
kubectl get pv,pvc -A
PVC-Test:
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
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:
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
~/tmpoder~/clusters, - keine produktiven Secrets,
- Cluster jederzeit löschbar halten,
- wichtige Notizen außerhalb des Cluster-Storage sichern.
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:
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:
Get-NetTCPConnection -LocalPort 80 -ErrorAction SilentlyContinue
Get-Process -Id (Get-NetTCPConnection -LocalPort 80).OwningProcess
WSL:
sudo ss -tulpn | grep -E ':80|:443|:8080|:8443' || true
26.5 DNS-Fehler unterscheiden
Windows:
Resolve-DnsName demo.local
WSL:
getent hosts demo.local
nslookup demo.local || true
Cluster:
kubectl run dns-debug --rm -it --restart=Never --image=busybox:1.36 -- nslookup kubernetes.default.svc.cluster.local
26.6 Ingress-Fehler unterscheiden
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
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:
./scripts/provision.sh --dry-run
Für eine WSL-kind-Variante könnte ein Ziel so aussehen:
./scripts/provision.sh --target wsl-kind --dry-run
./scripts/provision.sh --target wsl-kind
Für minikube:
./scripts/provision.sh --target wsl-minikube --dry-run
./scripts/provision.sh --target wsl-minikube
Für k3d:
./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
.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
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:
./scripts/wsl/preflight.sh
28. Validierung
28.1 WSL-Basis
uname -a
cat /etc/os-release
ps -p 1 -o comm=
mount | grep drvfs || true
Erwartung:
- Ubuntu LTS,
- WSL2-Kernel,
systemdals PID 1,/mnt/ceingebunden.
28.2 Docker
docker version
docker info --format '{{.ServerVersion}}'
docker run --rm hello-world
28.3 Kubernetes-CLI
kubectl version --client
kubectl config get-contexts
kubectl config current-context || true
28.4 Cluster
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
kubectl run dns-test --rm -it --restart=Never --image=busybox:1.36 -- \
nslookup kubernetes.default.svc.cluster.local
28.6 Service und Ingress
kubectl get svc -A
kubectl get ingress -A
curl -v http://localhost || true
curl -v http://demo.local || true
28.7 Windows-Browser
PowerShell:
Resolve-DnsName demo.local
Test-NetConnection demo.local -Port 80
Edge:
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. |
29. Troubleshooting
29.1 Docker ist in WSL nicht erreichbar
Symptom:
Cannot connect to the Docker daemon
Prüfen:
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.
wsl --shutdown
Lösung native Docker Engine:
sudo systemctl status docker --no-pager
sudo systemctl restart docker
sudo usermod -aG docker "$USER"
newgrp docker
29.2 systemctl funktioniert nicht
Symptom:
System has not been booted with systemd
Lösung:
sudo tee /etc/wsl.conf <<'EOF'
[boot]
systemd=true
EOF
PowerShell:
wsl --shutdown
Danach WSL neu starten und prüfen:
ps -p 1 -o comm=
29.3 Edge erreicht demo.local nicht
Prüfen:
Resolve-DnsName demo.local
Test-NetConnection demo.local -Port 80
Wenn DNS falsch ist:
- Windows-Hosts-Datei prüfen,
ipconfig /flushdnsausführen,- Browser neu laden.
Wenn Port nicht erreichbar ist:
kind/k3dPort-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/hostsin WSL wurde geändert. - Windows-Hosts-Datei fehlt.
Lösung:
notepad $env:windir\System32\drivers\etc\hosts
ipconfig /flushdns
Eintrag:
127.0.0.1 demo.local
29.5 Edge funktioniert, aber curl in WSL nicht
Mögliche Ursachen:
- WSL
/etc/hostshat keinen Eintrag, - DNS-Generierung überschreibt Einträge,
- Proxy oder VPN beeinflusst WSL.
Prüfen:
getent hosts demo.local
cat /etc/hosts | tail -50
Für WSL-internen Test kannst du direkt setzen:
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:
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
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
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
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
kubectl describe pod <pod> -n <namespace>
kubectl get events -n <namespace> --sort-by=.lastTimestamp
Lösung je nach Ursache:
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:
Get-NetTCPConnection -LocalPort 80 -ErrorAction SilentlyContinue
WSL:
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:
cat /etc/resolv.conf
nslookup github.com || true
curl -I https://kubernetes.io || true
Mögliche Lösungen:
- WSL aktualisieren,
dnsTunneling=truesetzen,autoProxy=truesetzen,- Unternehmens-Proxy korrekt konfigurieren,
- WSL neu starten.
30. Rückbau
30.1 kind
kind get clusters
kind delete cluster --name workshop
30.2 minikube
minikube delete
rm -rf ~/.minikube
30.3 k3d
k3d cluster list
k3d cluster delete workshop
30.4 Docker Desktop Kubernetes
In Docker Desktop:
- Kubernetes deaktivieren oder Reset verwenden.
CLI-Prüfung:
kubectl config delete-context docker-desktop || true
30.5 kubeadm
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
sudo /usr/local/bin/k3s-uninstall.sh || true
30.7 Windows-Hosts-Einträge entfernen
Administrative 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.
docker ps -a
docker network ls
docker volume ls
docker container prune
docker network prune
docker image prune
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:
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:
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:
kubectl get nodes
kubectl get pods -A
curl -H 'Host: demo.local' http://127.0.0.1
Browser:
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:
Resolve-DnsName demo.local
ipconfig /displaydns | Select-String demo.local
31.5 Lab 5: minikube mit Add-ons
Ziel:
- Du startest
minikubemit Docker-Treiber. - Du aktivierst Ingress und Metrics Server.
- Du testest
kubectl top.
Abnahme:
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:
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,minikubeoderk3d.
Abnahme:
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:
kubectl get events -A --sort-by=.lastTimestamp | tail -50
kubectl describe ingress -A
kubectl get svc,endpoints,pods -n demo -o wide
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
chmod 700 ~/.kube
chmod 600 ~/.kube/config
32.3 Secrets prüfen
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.
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 |
34. Referenzkommandos
34.1 WSL-Kommandos in 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
notepad $env:windir\System32\drivers\etc\hosts
ipconfig /flushdns
Resolve-DnsName demo.local
Test-NetConnection demo.local -Port 80
34.3 WSL-Systemprüfung
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
docker version
docker info
docker ps
docker network ls
docker volume ls
docker run --rm hello-world
34.5 kubectl
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
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
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
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
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
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
35. Quellen und weiterführende Links
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
.wslconfigundwsl.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
Anhang A: Minimaler kind-End-to-End-Quickstart
# 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:
127.0.0.1 demo.local
Edge:
http://demo.local
Anhang B: Minimaler minikube-End-to-End-Quickstart
# 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:
http://localhost:8080
Anhang C: Minimaler k3d-End-to-End-Quickstart
# 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:
127.0.0.1 demo.local
Edge:
http://demo.local
Anhang D: Empfohlene Workshop-Standardentscheidung
Für die meisten Gruppen verwendest du:
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.