1 Drei Orte, zwei Cluster, ein Deploy-Weg
CRC und SNO sind zwei getrennte OpenShift-Cluster. Git und Jenkins stehen außerhalb beider Cluster und liefern nur Quelltext, Images und Manifeste.
oc, TailscaleDer wichtigste Kontrollpunkt: Vor jedem oc-Befehl musst du wissen, auf welchen API-Server der aktuelle Kontext zeigt. CRC und SNO können dieselben Namespaces und Objektnamen enthalten, ohne denselben Zustand zu teilen.
2 Die Sicherheitsgrenze dieses Labs
Die folgenden Prüfungen starten keinen Cluster, erzeugen keinen Hetzner-Server und führen keinen Deploy aus.
| nur lesen | ändert Zustand oder Kosten |
|---|---|
.\scripts\sno.ps1 status, crc status, tailscale status | sno.ps1 up, sno.ps1 install, crc start |
oc get, oc describe, hcloud server describe | oc apply, helm upgrade, hcloud server create |
podman machine list, podman ps, podman port | podman machine start, podman run, Pipeline-Start |
Nicht ersetzen: Wenn eine Komponente gestoppt ist, notiere den Befund. Starte sie nicht nebenbei. Der ausgeschaltete SNO ist der gewünschte kostensparende Zustand und ein gestartetes CRC reserviert viel Laptop-RAM.
3 Verfügbare Werkzeuge inventarisieren
$names = 'oc','crc','hcloud','tailscale','podman','git','wsl'
$names | ForEach-Object {
$command = Get-Command $_ -ErrorAction SilentlyContinue
[pscustomobject]@{
Werkzeug = $_
Gefunden = [bool]$command
Pfad = if ($command) { $command.Source } else { '-' }
}
} | Format-Table -AutoSizeEin fehlender Befehl bedeutet nur, dass dieser Teil auf dem aktuellen Laptop nicht geprüft werden kann. Es sagt nichts über den Zustand des entfernten Clusters aus.
.\scripts\sno.ps1 status crc status podman machine list tailscale status
scripts/sno.ps1 ist der sichere Einstieg für den Hetzner-SNO. Die Aktion status liest Server-, Snapshot- und Erreichbarkeitszustand, ohne den Server anzulegen.
4 Den aktiven OpenShift-Cluster eindeutig erkennen
Kontext bedeutet die Kombination aus Clusteradresse, Benutzer und Standard-Namespace in der lokalen Kubeconfig.
oc config current-context
oc whoami
oc whoami --show-server
oc get clusterversion version -o custom-columns=VERSION:.status.desired.version,CHANNEL:.spec.channel
oc get infrastructure cluster -o custom-columns=PLATFORM:.status.platformStatus.type,CONTROL-PLANE:.status.controlPlaneTopology,INFRA:.status.infrastructureTopology
oc get ingress.config.openshift.io cluster -o jsonpath='{.spec.domain}{"\n"}'
oc get nodes -o custom-columns=NAME:.metadata.name,ROLES:.metadata.labels,EFFECTIVE-OS:.status.nodeInfo.osImage,KERNEL:.status.nodeInfo.kernelVersionBerechtigung: Die Infrastruktur-, Ingress- und ClusterOperator-Abfragen brauchen clusterweite Leserechte. Ein Forbidden bei einem Entwicklerkonto bedeutet fehlende Sichtbarkeit und nicht automatisch einen defekten Cluster.
| Beobachtung | Einordnung |
|---|---|
API unter api.crc.testing und App-Domain apps-crc.testing | CRC auf diesem Laptop |
API-Name mit sno und nip.io | der Hetzner-SNO dieses Repositorys |
| genau ein Node mit Control-Plane- und Worker-Rolle | Single-Node-Topologie, aber noch kein Beweis für CRC oder Hetzner |
| mehrere Nodes und getrennte Rollen | Multi-Node-Cluster, weder die lokale CRC noch diese SNO |
Wenn mehrere Kontexte vorhanden sind, verwende für Vergleiche oc --context <name> get …. Das ist sicherer als den globalen aktuellen Kontext umzuschalten.
5 Den SNO-Aufbau aus Skript und Ist-Zustand ableiten
Single-Node OpenShift, kurz SNO, vereint Steuerungsebene und Anwendungs-Workloads auf einem Node. Der Hetzner-Weg dieses Repositorys nutzt das Rescue-System als Sprungbrett zu SCOS.
Select-String -LiteralPath .\scripts\sno.ps1 -Pattern 'Rescue|ReservedIP|TailscaleHost|Invoke-Install|wait-for' Select-String -LiteralPath .\scripts\sno-wsl.sh -Pattern 'bootstrap-in-place|wait-for|install-config' Select-String -LiteralPath .\scripts\sno-kexec.sh -Pattern 'kexec|config.ign|initramfs' .\scripts\sno.ps1 status
SCOS bedeutet CentOS Stream CoreOS und ist das unveränderliche Node-Betriebssystem von OKD. Bei OpenShift Container Platform übernimmt RHCOS, Red Hat Enterprise Linux CoreOS, diese Rolle. „Unveränderlich“ bedeutet hier, dass Node-Konfiguration über deklarierte Clustermechanismen statt durch manuelles Paketinstallieren gepflegt wird.
Laufenden SNO zusätzlich im Cluster prüfen
oc whoami --show-server oc get nodes -o custom-columns=NAME:.metadata.name,ROLES:.metadata.labels,OS:.status.nodeInfo.osImage oc get clusterversion version oc get clusteroperator oc get machineconfigpool
6 CRC als lokalen Cluster vermessen
CRC ist das Upstream-Werkzeug hinter Red Hat OpenShift Local. Es stellt einen vollständigen OpenShift-Single-Node in einer lokalen VM für Entwicklung und Lernen bereit.
crc status
crc config view
crc ip
oc config get-contexts
$crcContexts = @(oc config get-contexts -o name | Where-Object { $_ -match 'crc' })
$crcContext = $crcContexts | Where-Object { $_ -match 'admin' } | Select-Object -First 1
if (-not $crcContext) { $crcContext = $crcContexts | Select-Object -First 1 }
if (-not $crcContext) { throw 'Kein CRC-Kontext in der Kubeconfig gefunden.' }
oc --context $crcContext whoami --show-server
oc --context $crcContext get nodes -o wide
oc --context $crcContext get clusteroperatorBash-Variante anzeigen
crc status
crc config view
crc ip
oc config get-contexts
crc_context=$(oc config get-contexts -o name | grep 'crc' | grep 'admin' | head -1)
test -n "$crc_context" || crc_context=$(oc config get-contexts -o name | grep 'crc' | head -1)
test -n "$crc_context" || { printf 'Kein CRC-Kontext gefunden.\n' >&2; exit 1; }
oc --context "$crc_context" whoami --show-server
oc --context "$crc_context" get nodes -o wide
oc --context "$crc_context" get clusteroperatorcrc status unterscheidet VM, OpenShift und Disk-Nutzung. crc config view zeigt die lokal gewählten CPU-, RAM- und Disk-Werte. Wenn CRC gestoppt ist, bleibt diese Konfiguration lesbar, Clusterabfragen schlagen aber erwartbar fehl.
7 Ein-Node-Grenzen am Cluster beweisen
oc get nodes -L node-role.kubernetes.io/master,node-role.kubernetes.io/worker oc get storageclass oc get volumesnapshotclass oc get machineconfigpool oc get clusteroperator monitoring oc get pods -A -o wide
Wenn oc get volumesnapshotclass meldet, dass dieser Ressourcentyp unbekannt ist, ist die Snapshot-API nicht installiert. Eine leere Liste bedeutet dagegen, dass die API existiert, aber keine Klasse angeboten wird.
| Befund | Folgerung | Nicht daraus folgern |
|---|---|---|
| ein Node trägt Steuerungsebene und Workloads | kein Schutz vor Ausfall dieses Nodes | OpenShift-Funktionen seien nur simuliert |
| alle Pods landen auf demselben Node | Anti-Affinity kann keine Hardwareausfälle trennen | Scheduler-Regeln seien grundsätzlich falsch |
| lokaler oder HostPath-Storage | Volume bleibt an diese Maschine gebunden | jedes OpenShift habe nur lokalen Storage |
| kein Verkehr zwischen Nodes | kein realer Geneve-Hop messbar | OVN-Kubernetes oder NetworkPolicy fehle |
CRC gegen SNO: Beide zeigen die OpenShift-API und Operatoren echt. CRC ergänzt die besondere Grenze eines vorgebauten lokalen Bundles. Die Hetzner-SNO ergänzt echte externe Netze, Kosten, Remote-Zugriff und einen persistenten Server-Lebenszyklus.
8 Den Tailscale-Pfad zur SNO prüfen
Tailscale bildet ein privates Overlay-Netz, Tailnet genannt. MagicDNS ordnet seinen Geräten stabile Namen zu. Die OpenShift-API behält trotzdem ihren Zertifikatsnamen.
tailscale status $apiUri = [Uri](oc whoami --show-server) $apiHost = $apiUri.Host "API-Name: $apiHost" Resolve-DnsName $apiHost Test-NetConnection $apiHost -Port 6443 Get-Content -LiteralPath "$env:WINDIR\System32\drivers\etc\hosts" | Select-String -SimpleMatch $apiHost
Der Eintrag in C:\Windows\System32\drivers\etc\hosts ist wichtig, wenn der öffentliche nip.io-Name lokal auf die private Tailscale-IP zeigen soll. Der Name bleibt gleich, damit die Subject Alternative Names, kurz SANs, im API-Zertifikat passen.
Zwei unabhängige Prüfungen: Ein erreichbares Tailscale-Gerät beweist noch nicht, dass Port 6443 lauscht. Ein auflösbarer API-Name beweist noch nicht, dass er auf die gewünschte Tailnet-IP zeigt. Deshalb werden Status, DNS und TCP-Port getrennt geprüft.
9 Den lokalen Jenkins und seine Engine finden
Jenkins läuft hier als Container in der Podman-Maschine. Die Maschine stellt Linux auf Windows bereit, der Jenkins-Container orchestriert die Pipeline und die Host-Engine baut die Images.
podman machine list
podman system connection list
podman ps --filter name=shared-jenkins --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
podman port shared-jenkins
podman stats shared-jenkins --no-streamWenn die Podman-Maschine gestoppt ist, kann podman ps keine Container liefern. Das ist ein klarer Schichtfehler vor Jenkins und kein OpenShift-Problem.
Keine Geheimnisse inventarisieren: Verwende dafür weder vollständiges podman inspect noch die Ausgabe aller Jenkins-Umgebungsvariablen. Dort können Zugangsdaten, Tokens und Registry-Passwörter stehen.
10 Das Ergebnis eines Deploys im Cluster verfolgen
Die Pipeline ist erst bewiesen, wenn Commit, Image und laufender Pod zusammenpassen. Diese Abfragen starten keinen Build.
Im Anwendungs-Repository
git remote get-url origin git branch --show-current git rev-parse --short HEAD git status --short
Im Zielcluster
oc whoami --show-server oc get namespace library oc -n library get deployment -o custom-columns=NAME:.metadata.name,READY:.status.readyReplicas,IMAGE:.spec.template.spec.containers[*].image oc -n library get replicaset --sort-by=.metadata.creationTimestamp oc -n library get pod -o wide oc -n library get route oc -n library get serviceaccount pipeline oc get route default-route -n openshift-image-registry
library.Ein laufender Pod beweist nur den letzten Abschnitt. Die Zuordnung zum Commit gelingt über den verwendeten Image-Tag oder besser über Digest und Build-Metadaten. Fehlt diese Verbindung, ist der Rollout technisch erfolgreich, aber nicht vollständig nachvollziehbar.
11 Für jede Frage die kleinste passende Umgebung wählen
| Frage oder Übung | passende Umgebung | Grund |
|---|---|---|
| Web-Konsole, Projects, RBAC, SCC, Routes und OLM lernen | CRC | lokal, schnell wiederholbar und vollständige OpenShift-Oberfläche |
| Remote-Zugriff, öffentliche Routes, Registry und Kostenbetrieb verstehen | Hetzner-SNO | echtes externes Netz und echter Server-Lebenszyklus |
| Node-Ausfall, Anti-Affinity und verteilten Storage testen | Multi-Node-Cluster | eine SNO und CRC besitzen keine zweite Ausfallzone |
| Nur Kubernetes-API und Multi-Node-Scheduling üben | kind oder k3d | kleiner als OpenShift, aber ohne Routes, SCC und Cluster Operators |
| Den vollständigen Bibliothek-Deploy demonstrieren | SNO mit lokalem Jenkins | zeigt reale Build-, Registry-, Tunnel- und Rollout-Grenzen gemeinsam |
12 Dateien und Herkunft sauber trennen
| Datei oder Zustand | Kategorie | Umgang |
|---|---|---|
scripts/sno.ps1, scripts/sno-wsl.sh, scripts/sno-kexec.sh | wichtig | versionierte Automatisierung für Server, SCOS-Sprung und Installation |
install-config.yaml und Ignition-Konfiguration | wird generiert | Installationsartefakte mit sensiblen Daten, nicht veröffentlichen |
~/.kube/okd-sno-hetzner.yaml | wird generiert | Kubeconfig mit Zugangsdaten, nur geschützt lokal aufbewahren |
C:\Windows\System32\drivers\etc\hosts | du legst an | lokale Namensauflösung für den API-Zertifikatsnamen |
| CRC-VM, Bundle und lokale Kubeconfig-Kontexte | wird generiert | durch CRC verwalten, nicht in dessen VM manuell ändern |
Jenkins-Compose, Jenkinsfile und Helm-Chart | wichtig | versionierter Sollzustand in den jeweiligen Projekt-Repositories |
| Build-Container, Images, ReplicaSets und Pods | wird generiert | über Pipeline, Registry und Deployment zurückverfolgen |
13 Fehler zuerst der richtigen Schicht zuordnen
| Fehlerbild | erste Prüfung | Schicht |
|---|---|---|
oc zeigt unerwartete Namespaces | oc whoami --show-server | falscher Kubeconfig-Kontext |
| API-Name löst falsch auf | Resolve-DnsName und hosts | DNS oder lokaler Override |
| Tailscale sieht den Node, Port 6443 bleibt zu | Test-NetConnection | API-Prozess, Zielhost oder Filterregel |
| Jenkins-Webseite fehlt | Podman-Maschine, Container und Port | lokale Container-Laufzeit |
| Build grün, alter Pod läuft weiter | Image-Referenz und ReplicaSet-Alter | Registry-, Helm- oder Rollout-Übergabe |
| CRC ist langsam oder Workloads bleiben pending | crc config view und Node-Ressourcen | Laptop-Kapazität oder Ein-Node-Grenze |
Die Reihenfolge verhindert, dass ein Tunnelproblem im Deployment gesucht oder ein falscher Kontext als fehlgeschlagener Rollout interpretiert wird.
14 Lernkontrolle
- Ich kann CRC und Hetzner-SNO anhand von API-Adresse, Domain und lokalem Status unterscheiden.
- Ich kann erklären, warum Rescue,
kexec, SCOS, Ignition und Bootstrap nacheinander nötig sind. - Ich kann Ein-Node-Grenzen von fehlenden OpenShift-Funktionen unterscheiden.
- Ich kann DNS-Auflösung, Tailscale-Verbindung und API-Port getrennt prüfen.
- Ich kann lokalen Jenkins, Podman-Engine und Zielcluster als drei getrennte Schichten diagnostizieren.
- Ich kann einen laufenden Pod über Image, Deployment und Pipeline bis zu einem Git-Commit zurückverfolgen.
Nichts aufzuräumen: Dieses Labor hat nur lokale Dateien und entfernte Zustände gelesen. Wenn du keine der ausdrücklich abgegrenzten Start- oder Änderungsaktionen ausgeführt hast, wurde nichts erzeugt.