← Übersicht  ·  Skripte & Dateien  ·  Lokal · Betrieb & Diagnose

OpenShift Local auf Windows

CRC bringt einen vollständigen OpenShift-Single-Node auf den Laptop – in einer Hyper-V-VM, mit echter Registry, echten Routen, echtem oc. Das ist erstaunlich nähe am Original und erstaunlich empfindlich gegenüber drei Dingen: zu wenig Platte, zu langsamer Speicher und zu wenig CPU. Diese Seite sammelt, was beim Betrieb tatsächlich weh tut – unabhängig davon, welches Projekt darauf laufen soll.

Stand: 2. September 2026 CRC 2.63 · OKD 4.22 · Preset okd Windows 10 Pro · Hyper-V

01 Dimensionierung

Die Vorgabewerte reichen für einen leeren Cluster. Sobald etwas darauf laufen soll, nicht mehr.

EinstellungVorgabePraxiswertWoran man merkt, dass es zu wenig ist
memory1075216384Bei 10,5 GB sind 93 % des Node-Speichers schon von OpenShift selbst angefordert. Neue Pods bleiben Pending mit Insufficient memory.
disk-size3145+Node bekommt den Taint disk-pressure, laufende Pods werden verdrängt. Der leere Cluster belegt allein schon rund 23 GB.
cpus46JVM-Kaltstarts dauern Minuten; siehe Diagnose.
Laptop · PowerShell
crc config set memory 16384
crc config set disk-size 45
crc config set cpus 6
crc config view

# Alle drei greifen erst beim naechsten Start:
crc stop; crc start
Die Disk wächst, sie schrumpft nicht

disk-size lässt sich jederzeit erhöhen – CRC vergrößert die VHDX und die Partition beim nächsten Start automatisch. Zurück geht es nicht ohne crc delete. Der Wert ist zugleich das Minimum 31; kleiner lässt CRC nicht zu, weil das Bundle-Image selbst schon so groß ist.

02 Was auf die SSD gehört

Nicht alles unter ~/.crc ist gleich empfindlich.

VerzeichnisGrößeZugriffWohin
~/.crc/machines/~30 GBständig, wahlfrei – hier liegt die VM-DiskSSD
~/.crc/cache/~35 GBnur beim Start und beim Entpacken, sequentiellHDD reicht
~/.crc/bin/< 1 GBseltenegal
Was passiert, wenn die VM-Disk auf einer Festplatte liegt

Gemessen mit der VHDX auf einer 2,5-Zoll-HDD:

VM-Disk auf HDDVM-Disk auf NVMe
iowait beim Start62–74 %0–9 %
Load (6 vCPU)bis 25Spitze 20, dann ~2
crictl images22 s< 1 s
Start bis Running~45 Min, mit Handeingriff~6 Min

Auf der HDD meldet crc start zuverlässig cluster operators are still not stable after 11m, und die Pods hängen reihenweise in ImageInspectError: DeadlineExceeded. Das sieht nach einem kaputten Cluster aus, ist aber nur CRI-O, das seine Zeitfenster nicht einhält, weil die Platte nicht hinterherkommt.

03 Cache auslagern – und die Junction-Falle

Wenn die SSD zu klein ist, kann der Cache auf die große Platte. Aber nicht bedingungslos.

CRC kennt keine Konfiguration für einen abweichenden Cache-Pfad. Der übliche Weg ist deshalb eine Junction – ein Verzeichnis-Verweis auf NTFS-Ebene, den CRC gar nicht bemerkt:

Laptop · cmd oder PowerShell
# Cache auf die grosse Platte verlagern, machines/ bleibt auf der SSD
robocopy "%USERPROFILE%\.crc\cache" "D:\OpenShift-Local\.crc\cache" /E /MOVE
mklink /J "%USERPROFILE%\.crc\cache" "D:\OpenShift-Local\.crc\cache"
Falle: Der Bundle-Download scheitert an genau dieser Junction

Seit CRC 2.63 werden Bundles als OCI-Artefakt geladen, nicht mehr per HTTP. Die dahinterliegende Bibliothek legt ein temporäres Zielverzeichnis im Cache an – und das schlägt in einem Reparse-Point fehl:

level=error msg="invalid destination name C:\Users\...\.crc\cache\tmpBundleImage3964368163:
The system cannot find the path specified."

Lesen und Entpacken durch die Junction funktionieren einwandfrei – nur das Anlegen bricht. Der laufende Betrieb ist also nicht betroffen, sondern ausschließlich der einmalige Bundle-Download. Vorgehen bei einem Versions-Update:

  1. Junction entfernen – rmdir ohne /s löst nur den Verweis, die Daten auf der anderen Platte bleiben
  2. Echtes cache-Verzeichnis auf der SSD anlegen (braucht ~35 GB frei)
  3. crc setup laufen lassen
  4. Cache zurück auf die große Platte kopieren, verifizieren, Quelle löschen
  5. Junction neu setzen
Nie crc cleanup, nie den Uninstaller

Beide arbeiten auf Deinstallations-Ebene und können ~/.crc mitsamt Junction entfernen. Ein anschließendes crc setup legt dann ein echtes Verzeichnis auf der Systemplatte an und zieht rund 35 GB dorthin. crc delete ist dagegen unbedenklich – es läuft durch die Junction und lässt sie stehen. Der MSI-Installer eines Versions-Updates fasst das Verzeichnis ebenfalls nicht an.

04 Der Pod, der die Platte frisst

Ein Defekt in dieser OKD-Version, der reproduzierbar den ganzen Cluster lahmlegt.

openshift-console/downloads schreibt fortlaufend Temporärdateien in sein emptyDir und räumt sie nie auf. Gemessen: 17 GB in 3,5 Stunden, verteilt auf mehrere Dateien zu je 3,1 GB – also rund 5 GB pro Stunde. Irgendwann greift DiskPressure, der Node bekommt einen NoSchedule-Taint, und laufende Pods werden verdrängt.

Das Symptom sieht völlig anders aus als die Ursache: Pods, die eben noch liefen, stehen plötzlich auf Pending mit node(s) had untolerated taint(s).

Laptop · bash · Verursacher finden
# Groesstes emptyDir in der VM aufspueren
ssh -i ~/.crc/machines/crc/id_ed25519 -p 2222 core@127.0.0.1 \
  "sudo du -xh --max-depth=1 /var/lib/kubelet/pods | sort -rh | head -5"

# Pod-UID aus dem Pfad einem Namen zuordnen
oc get pods -A -o jsonpath='{range .items[*]}{.metadata.uid}{"  "}{.metadata.namespace}{"/"}{.metadata.name}{"\n"}{end}' \
  | grep <uid>
Laptop · bash · dauerhaft stilllegen
# Ohne Unmanaged skaliert der Console-Operator das Deployment sofort zurueck
oc patch console.operator.openshift.io/cluster --type=merge \
  -p '{"spec":{"managementState":"Unmanaged"}}'
oc scale deploy/downloads -n openshift-console --replicas=0
Was das kostet

Der Pod liefert in der Web-Konsole nur die Downloadseite für oc, kubectl und verwandte Werkzeuge. Auf einem lokalen Entwicklungscluster kostet sein Abschalten nichts – und es gibt sofort 17 GB zurück. Die Web-Konsole selbst läuft weiter.

05 Diagnose: Load richtig lesen

Dieselbe Kennzahl, zwei völlig verschiedene Ursachen.

Der Load Average unter Linux zählt Prozesse, die laufen, auf einen Kern warten – oder in ununterbrechbarem Warten stecken, praktisch immer auf Platten-I/O. Genau deshalb sagt die Zahl allein noch nicht, woran es klemmt. Der Bezugspunkt ist die Kernzahl: Bei 6 vCPUs bedeutet Load 6 volle Auslastung ohne Warteschlange.

Laptop · bash · in die VM schauen
# CRC 2.6x hat kein "crc ssh" - direkt ueber den Bundle-Schluessel
ssh -i ~/.crc/machines/crc/id_ed25519 -p 2222 \
    -o StrictHostKeyChecking=no core@127.0.0.1 \
    "cat /proc/loadavg; vmstat 1 2 | tail -1; df -h /var | tail -1"

Entscheidend sind die letzten Spalten von vmstat:

BeobachtungLoadvmstatUrsacheWas hilft
Start dauert ewig, VM-Disk auf HDD20+ wa=74  us=6 Platten-I/OVM-Disk auf SSD
Viele JVMs starten gleichzeitig157 wa=0  us=64  sy=35  id=0 CPU-Sättigunggestaffelt starten
Wenn der Cluster nicht mehr von allein zurückkommt

Bei anhaltender CPU-Sättigung verhungert der kube-apiserver (TLS handshake timeout). Dann schlagen die Probes fehl, Liveness tötet Pods, jeder Neustart erzeugt einen weiteren Kaltstart – eine Rückkopplung, die sich selbst nährt. In diesem Zustand läuft sogar crictl stop in Timeouts.

Ausweg: crc stop, crc start, und während der Cluster hochfährt die Anwendungs-Deployments auf 0 skalieren, sobald die API antwortet. Danach einzeln hochfahren.

06 Auslastung protokollieren

Weil die interessanten Zustände meist dann auftreten, wenn man nicht hinschaut.

Nützlich sind Host- und VM-Werte nebeneinander – und in der VM ausdrücklich iowait, weil erst das die beiden Fälle aus Abschnitt 05 trennt. Ein PowerShell-Skript, das im Minutentakt eine CSV schreibt, reicht dafür völlig.

SpalteWoherWozu
Host-CPU, Host-RAMWMIMerkt man, wenn Windows selbst knapp wird
freier Platz je LaufwerkGet-PSDriveVHDX-Wachstum im Blick behalten
VM-CPU, zugewiesenes RAMGet-VMWas Hyper-V der VM tatsächlich gibt
Load, us/sy/id/wa, /varSSH in die VMDer eigentliche Diagnosewert
fehlerhafte Pods und OperatorenocWirkung auf den Cluster
Zwei Stolpersteine beim Auslesen

vmstat darf man nicht über feste Spaltenpositionen auswerten: Neuere procps-ng-Versionen hängen hinter st noch eine Spalte gu an, wodurch alle Indizes verrutschen. Die Spalten über die Kopfzeile auflösen.

Und der Hyper-V-Speicher der VM taucht auf dem Host nicht als Prozess auf – ihn liefert nur Get-VM, nicht Get-Process.