← Übersicht  ·  Skripte & Dateien  ·  Heimlabor · Echtes OpenShift auslagern

OKD-Cluster auf Hetzner

Ein vollwertiger, mehrknotiger OpenShift-Cluster (OKD 4, die Community-Edition) auf Hetzner – kompakt mit 3 schedulebaren Control-Plane-Nodes, optional plus Worker. Gesteuert per oc vom Windows-Laptop. Das ist die schwere Variante: echte Ressourcen, echte Kosten, echte Vorbedingungen.

Stand: 29. August 2026 Installationsdauer ~45 Minuten ~420–600 €/Monat

Platzhalter einsetzen – werden in allen Befehlen unten ersetzt, nur im Browser, nichts wird gesendet

Das Prinzip

OKD (OpenShift Kubernetes Distribution) 4 ist der Upstream von OpenShift Container Platform – gleiche Operatoren, Web-Console, Routes, BuildConfigs, ImageStreams. Es laeuft auf Fedora CoreOS. Fuer eine hochverfuegbare Control-Plane braucht es 3 Nodes mit etcd. „Kompakt“ heisst: diese 3 Nodes sind schedulebar und tragen auch deine Workloads – separate Worker sind optional. Ein Load Balancer buendelt API (6443), Machine-Config (22623) und Ingress (80/443).

Dein Laptop oc · hcloud CLI (Command-Line Interface) · ssh
steuert nur
Hetzner: 1 LB + privates Netz 3× Control-Plane (FCOS)
+ Bootstrap (nur bei Install)
+ Bastion (nur bei Install)
Blauer Streifen = auf deinem Laptop (PowerShell) Roter Streifen = auf einem Server (bash, per ssh)

01 Realitaets-Check – bevor du anfaengst

Das ist die schwere Variante

etcd & Festplatten-Latenz: Die OpenShift-Control-Plane reagiert extrem empfindlich auf fsync-Latenz. Auf Hetzners shared cx-Servern scheitert die Installation regelmaessig an etcd-Timeouts. Nimm ccx-Server (dedizierte vCPU) – oder besser Hetzner Robot / Dedicated (AX).

Groesse: kompakt = 3 Nodes, je min. 4 vCPU / 16 GB (offiziell fuer schedulebare Control-Plane eher 8 vCPU / 32 GB). Empfehlung: 3× CCX33. Lab-Minimum: 3× CCX23 – wird eng. Dazu voruebergehend 1 Bootstrap-Node und 1 kleine Bastion.

Kosten: 3× CCX33 ≈ 415 €/Monat + LoadBalancer ~6 € + Traffic. Das ist kein Spar-Setup. Wenn du nur oc ueben willst → nimm die OKD-Single-Node-Anleitung (1 Node CPX42, ~0,10 €/h).

Zeit: ~45 Minuten am Stueck, nicht sinnvoll unterbrechbar.

Kein Red-Hat-Pull-Secret noetig – OKD nimmt ein Fake-Secret.

Wenn das alles ok ist: Hetzner-Konto anlegen, ein Projekt erstellen, unter Security → API Tokens einen Token mit Read & Write erzeugen und sofort kopieren.

02 Voraussetzung: Server-Basis

Konto, API-Token, hcloud CLI, SSH-Key – einmalig, in einer eigenen Anleitung.

Einmal einrichten

Server-Basis durcharbeiten. Zusätzlich fuer OKD: winget install RedHat.OpenShift-Client (oc). Den eigentlichen Installer (openshift-install, nur Linux) laedst du in Schritt 6 auf die Bastion.

03 SSH-Key: der .pub-Inhalt

Der SSH-Key liegt schon bei Hetzner (Server-Basis). OKD braucht zusätzlich den Inhalt des öffentlichen Schlüssels – er kommt in die install-config (fuer den core-User auf FCOS).

Laptop · PowerShell
Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub    # Inhalt merken (fuer Schritt 6)

04 Privates Netz & Load Balancer

Die Nodes reden ueber ein privates Netz miteinander (etcd, API). Ein Hetzner Load Balancer ist der einzige oeffentliche Einstieg und verteilt auf die Control-Plane-Nodes.

Laptop · PowerShell
hcloud network create --name okd-net --ip-range 10.128.0.0/16
hcloud network add-subnet okd-net --network-zone eu-central --type cloud --ip-range 10.128.0.0/24

hcloud load-balancer create --name okd-lb --type lb11 --location nbg1 --network-zone eu-central
hcloud load-balancer attach-to-network okd-lb --network okd-net

# Dienste: API, Machine-Config, Ingress
hcloud load-balancer add-service okd-lb --protocol tcp --listen-port 6443  --destination-port 6443
hcloud load-balancer add-service okd-lb --protocol tcp --listen-port 22623 --destination-port 22623
hcloud load-balancer add-service okd-lb --protocol tcp --listen-port 80    --destination-port 80
hcloud load-balancer add-service okd-lb --protocol tcp --listen-port 443   --destination-port 443

hcloud load-balancer describe okd-lb -o 'format={{.PublicNet.IPv4.IP}}'   # -> oben ins Feld "LoadBalancer-IP"
Was die Schalter bedeuten

Vier hcloud-Objekte in einem Block – Netz, Subnetz, Load Balancer, Dienste:

Schaltergehoert zubewirkt
hcloud network create --name okd-net zuerst Ein privates Netz ist ein eigenstaendiges Objekt, das mehrere Server verbindet, ohne dass ihr Verkehr das oeffentliche Internet beruehrt. Server darin erreichen einander ueber Adressen wie 10.128.0.5. Das kostet bei Hetzner nichts extra und ist der Grund, warum die Nodes spaeter ohne oeffentliche IP auskommen.
hcloud load-balancer create --name okd-lb danach Der Load Balancer verteilt eingehende Verbindungen auf mehrere Server und ist hier der einzige oeffentliche Einstieg in den Cluster. Er wird angelegt, ans Netz gehaengt, bekommt Dienste (Port-Weiterleitungen) – und erst in Schritt 8 die eigentlichen Ziele, weil die Nodes jetzt noch nicht existieren.
--ip-range 10.128.0.0/16 network create Der Adressraum des gesamten privaten Netzes. Er muss gross genug fuer alle spaeteren Subnetze sein und darf sich nicht mit den Cluster-internen Bereichen von OpenShift ueberschneiden – sonst laufen Pod- und Node-Adressen ineinander und der SDN-Verkehr bricht auf schwer auffindbare Weise ab.
--ip-range 10.128.0.0/24 network add-subnet Der Ausschnitt, aus dem die Nodes ihre privaten Adressen bekommen – ein /24 reicht fuer 254 Server. Das Netz allein traegt keine Adressen; ohne Subnetz bekommt kein Server eine private IP (Internet Protocol).
--network-zone eu-central Subnetz, LB Die Netzwerkzone, nicht der Standort. Sie umfasst mehrere Rechenzentren (nbg1, fsn1, hel1 …). Load Balancer und Subnetz muessen in derselben Zone liegen wie die Server – sonst schlaegt attach-to-network fehl.
--type lb11 load-balancer create Die kleinste Bauform: 5 Dienste, 25 Targets, 20 TB Traffic. Genau die vier Dienste unten passen hinein – ein fuenfter waere das Limit. Traffic ist bei Hetzner-LBs inklusive.
attach-to-network okd-lb --network okd-net load-balancer Stellt den LB mit einem Bein ins private Netz. Erst danach kann er die Nodes ueber ihre privaten Adressen erreichen; ohne das muesste jeder Node eine oeffentliche IP behalten.
--protocol tcp add-service Reines Durchreichen auf Schicht 4. Wichtig fuer 6443 und 22623, weil dort TLS bis zum Cluster durchlaufen muss – ein HTTP-Modus wuerde die Verbindung aufbrechen und das Zertifikat passt dann nicht mehr. Auch 80 und 443 bleiben deshalb bewusst TCP; die Terminierung macht der OpenShift-Router.
--listen-port 22623 add-service Der Machine-Config-Server. Nur die Nodes selbst brauchen ihn, und nur waehrend der Installation – aber ohne ihn bootet kein Node fertig. Er liefert unauthentifiziert Ignition-Konfiguration aus und gehoert deshalb hinter die Firewall, nicht ins offene Netz.
-o 'format={{.PublicNet.IPv4.IP}}' describe Gibt statt der ganzen Beschreibung nur ein Feld aus – Go-Template-Syntax, dieselbe wie bei docker inspect. Praktisch, weil die IP gleich in ein Skript oder in das Platzhalter-Feld oben wandert. Die einfachen Anfuehrungszeichen sind Pflicht, sonst frisst PowerShell die geschweiften Klammern.

Die LB-Targets (die Nodes) haengen wir in Schritt 8 an, sobald sie existieren. lb11 reicht fuer ein Lab. Traffic ist bei Hetzner-LBs inklusive.

05 DNS ohne eigenen Server: nip.io

OpenShift verlangt, dass api.<cluster>.<domain> und *.apps.<cluster>.<domain> aufloesen. nip.io loest jede Subdomain von <ip>.nip.io auf genau diese IP (Internet Protocol) auf – also zeigt automatisch alles auf den Load Balancer.

Deine Cluster-Domain

base-domain = <lb-ip>.nip.io
API-URL = https://api.lab.<lb-ip>.nip.io:6443
Apps = *.apps.lab.<lb-ip>.nip.io

nip.io hatte schon längere Ausfälle

Zeigt die API-URL und die App-Hosts auf nip.io, ist der Cluster bei einem nip.io-Ausfall komplett nicht erreichbar. Fuer alles ausser einem kurzen Lab besser sslip.io (gleiche Wildcard-Idee, andere Betreiber – die anderen Guides hier nutzen es) oder gleich die echte Wildcard bei Cloudflare (nächster Absatz).

Fuer echten Betrieb spaeter eine richtige Domain nehmen – z. B. seb4u.com, das schon als Full-Zone bei Cloudflare liegt (siehe Domain zu Cloudflare umziehen). Dort in der bestehenden Zone api.okd als A-Record + *.apps.okd als Wildcard-A-Record auf die LB-IP setzen. Beide Records „DNS only“ (grau) – ein proxied Wildcard braucht Cloudflare Enterprise, und der OKD-Router macht TLS (Transport Layer Security) selbst.

06 Bastion + install-config.yaml

Eine kleine Wegwerf-VM erzeugt die Ignition-Dateien und stellt sie den Nodes bereit.

Laptop · PowerShell
hcloud server create --name okd-bastion --type cpx22 --image ubuntu-24.04 `
  --ssh-key laptop --network okd-net
$bastion = (hcloud server ip okd-bastion).Trim()
ssh root@$bastion
Bastion · bash
OKD=$(curl -s https://api.github.com/repos/okd-project/okd/releases/latest | grep -oP '"tag_name": "\K[^"]+')
cd /root
curl -L "https://github.com/okd-project/okd/releases/download/$OKD/openshift-install-linux-$OKD.tar.gz" | tar xz
curl -L "https://github.com/okd-project/okd/releases/download/$OKD/openshift-client-linux-$OKD.tar.gz"  | tar xz
mv oc kubectl openshift-install /usr/local/bin/
mkdir -p /root/okd && cd /root/okd
Bastion · /root/okd/install-config.yaml
apiVersion: v1
baseDomain: <lb-ip>.nip.io
metadata:
  name: lab
controlPlane:
  name: master
  replicas: 3
compute:
- name: worker
  replicas: 0
networking:
  networkType: OVNKubernetes
  machineNetwork:
  - cidr: 10.128.0.0/24
  clusterNetwork:
  - cidr: 10.132.0.0/14
    hostPrefix: 23
  serviceNetwork:
  - 172.30.0.0/16
platform:
  none: {}
pullSecret: '{"auths":{"fake":{"auth":"aWQ6cGFzcwo="}}}'
sshKey: 'ssh-ed25519 AAAA... (Inhalt deiner id_ed25519.pub)'

07 Manifeste & Ignition erzeugen

Aus der install-config werden die Boot-Konfigurationen. Vorher sichernopenshift-install verbraucht die Datei.

Bastion · bash
cd /root/okd
cp install-config.yaml install-config.yaml.bak

# Control-Plane schedulebar machen (kompakter Cluster):
openshift-install create manifests
sed -i 's/mastersSchedulable: false/mastersSchedulable: true/' manifests/cluster-scheduler-02-config.yml

openshift-install create ignition-configs
python3 -m http.server 8080 &      # serviert bootstrap.ign / master.ign

# FCOS-Image-URL passend zum Installer:
openshift-install coreos print-stream-json | grep -oP 'https://[^"]+qemu[^"]+x86_64[^"]+\.xz' | head -1
Ergebnis

bootstrap.ign, master.ign, worker.ign und auth/kubeconfig + auth/kubeadmin-password liegen in /root/okd/. Der HTTP-Server auf :8080 laeuft.

08 Nodes erstellen & FCOS schreiben

1 Bootstrap + 3 Master. Jede VM (virtuelle Maschine) startet im Rescue-Modus, coreos-installer schreibt Fedora CoreOS mit der passenden Ignition auf die Platte, dann Neustart ins fertige System.

Laptop · PowerShell – pro Node
# Beispiel: bootstrap (dann master-0/1/2 mit --type ccx33 und passender .ign)
hcloud server create --name okd-bootstrap --type cpx42 --image ubuntu-24.04 `
  --ssh-key laptop --network okd-net --start-after-create=false
hcloud server enable-rescue okd-bootstrap --ssh-key laptop
hcloud server poweron okd-bootstrap
$n = (hcloud server ip okd-bootstrap).Trim()
Node im Rescue · bash (ssh root@<node>)
FCOS_URL="https://.../fedora-coreos-...-metal.x86_64.raw.xz"   # aus Schritt 7
BASTION_PRIV=10.128.0.2                                        # private IP der Bastion

podman run --privileged --rm --pull=always -v /dev:/dev -v /run/udev:/run/udev \
  quay.io/coreos/coreos-installer:release install /dev/sda \
  --image-url "$FCOS_URL" --insecure \
  --ignition-url "http://$BASTION_PRIV:8080/bootstrap.ign" --insecure-ignition

reboot
Laptop · PowerShell – Node an den LB haengen
hcloud load-balancer add-target okd-lb --server okd-bootstrap --use-private-ip
# spaeter fuer master-0/1/2 dasselbe; Bootstrap nach Schritt 9 wieder entfernen
Wiederholen fuer master-0, master-1, master-2

Gleiche Schritte mit --type ccx33 und --ignition-url http://$BASTION_PRIV:8080/master.ign. Alle drei an den LB haengen.

09 Bootstrap abwarten

Bastion · bash
cd /root/okd
openshift-install wait-for bootstrap-complete --log-level=info
# ~15-25 Min. Wenn "It is now safe to remove the bootstrap resources":
Laptop · PowerShell
hcloud load-balancer remove-target okd-lb --server okd-bootstrap
hcloud server delete okd-bootstrap

10 Installation abschliessen & oc login

Bastion · bash
openshift-install wait-for install-complete
# druckt am Ende Console-URL und das kubeadmin-Passwort
cat /root/okd/auth/kubeadmin-password
Laptop · PowerShell
scp root@$bastion:/root/okd/auth/kubeconfig $env:USERPROFILE\.kube\okd-hetzner.yaml
$env:KUBECONFIG = "$env:USERPROFILE\.kube\okd-hetzner.yaml"
oc get nodes
oc get clusteroperators        # alles "Available=True"?

# Bastion wird nicht mehr gebraucht:
hcloud server delete okd-bastion
Console

https://console-openshift-console.apps.lab.<lb-ip>.nip.io – Login kubeadmin + das Passwort von oben. Port 443 am LB ist schon offen.

11 Projekt, Route, Storage

Laptop · PowerShell (→ Cluster)
oc new-project demo
oc new-app --image=docker.io/library/nginx --name=web
oc expose deployment/web --port=80
oc expose service/web        # Route auf web-demo.apps.lab.<lb-ip>.nip.io
oc get route
Persistente Volumes

Ein frischer platform: none-Cluster hat keine Default-StorageClass. Fuer echte PVs (PersistentVolumes) den LVM (Logical Volume Manager) Storage Operator (LVMS) aus dem OperatorHub installieren (nutzt freien Platz auf den Node-Platten) – oder fuers Erste mit emptyDir arbeiten. ODF/Ceph ist fuer 3 Nodes zu schwer.

+ Worker hinzufuegen

Mehr Kapazitaet, ohne die Control-Plane zu belasten.

Laptop · PowerShell
# neue VM, Rescue, coreos-installer mit worker.ign (von der Bastion – oder .ign vorher sichern!)
hcloud server create --name okd-worker-1 --type ccx33 --image ubuntu-24.04 `
  --ssh-key laptop --network okd-net --start-after-create=false
# ... Rescue + coreos-installer --ignition-url .../worker.ign + reboot
Laptop · PowerShell – CSR genehmigen
oc get csr -o name | ForEach-Object { oc adm certificate approve ($_ -replace 'certificatesigningrequest.certificates.k8s.io/','') }
oc get nodes        # der neue Worker erscheint nach 1-2 Min als Ready

Die worker.ign zeigt auf den Machine-Config-Server (:22623 ueber den LB) – die muss also erreichbar bleiben. worker.ign aus Schritt 7 vorher wegsichern, da die Bastion geloescht wurde.

+ Kosten: abreissen & neu aufbauen

Preise sind Richtwerte. Hetzner hat 2026 zweimal erhöht (zuletzt 15. Juni: CX/CAX +30–40 %, CPX/CCX über 100 %). Aktuelle Server-Preise, alle Nebenposten, ein Rechner und Beispielrechnungen stehen zentral in Kosten & Budget.

Einen laufenden Cluster kann man nicht „pausieren“ – die 3 Server kosten durchgehend. Realistischer Spar-Weg: komplett loeschen, bei Bedarf in ~45 Min neu installieren (Schritte 6–10). Das Skript raeumt alles ab.

Posten€/Std€/Tag€/Monat (Dauerbetrieb)
3× Control-Plane CCX33 (dediziert, 32 GB)~0,57~13,7~415
Bootstrap CPX42 – nur waehrend Installation (~45 Min)~0,095einmalig ~0,07
Bastion CPX22 – nur waehrend Installation~0,027einmalig ~0,03
Load Balancer lb11~0,010~0,25~7,5
Primary-IPs (3× IPv4)~0,0021~0,05~1,50
Privates Netzwerkgratisgratis0
Cluster im Dauerbetrieb~0,58~14~425

Richtwerte 2026 (CCX33 grob, aktuell: hcloud server-type describe CCX33). .\scripts\cluster.ps1 down loescht Server, LB und Netz – alle Uhren stoppen sofort. Ein vergessenes Wochenende (Fr–Mo) sind ~40 €. Deshalb ist das naechtliche Auto-Teardown hier der wichtigste Schutz.

Laptop · PowerShell
.\scripts\cluster.ps1 status   # was laeuft, ~Kosten
.\scripts\cluster.ps1 down     # alle okd-* Server + LB + Netz loeschen
Datei · scripts/cluster.ps1
#Requires -Version 5.1
param([ValidateSet('down','status')][string]$Action = 'status')
# Kein globales 'Stop': hcloud und ssh schreiben Hinweise ("Server not found",
# Fortschritt) nach stderr - PowerShell 5.1 wertet das unter 'Stop' als Abbruch.
$ErrorActionPreference = 'Continue'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

$Prefix = 'okd-'
# Stundensaetze (EUR): aus scripts/rates.psd1 - eine Quelle wie cloud.ps1 / snapshot.ps1.
$RatesFile = Join-Path $PSScriptRoot 'rates.psd1'
$Rate = if (Test-Path $RatesFile) { Import-PowerShellDataFile $RatesFile }
        else { @{ cpx22 = 0.0267; cpx42 = 0.0952; cpx52 = 0.1377   # Fallback (Stand nach 15.06.2026)
                  ccx13 = 0.0589; ccx23 = 0.1178; ccx33 = 0.1897 } }

function Cluster-Servers {
  hcloud server list -o json | ConvertFrom-Json | Where-Object { $_.name -like "$Prefix*" }
}

function Show-Status {
  $srv = Cluster-Servers
  if (-not $srv) { Write-Host 'AUS - keine okd-* Server.' -ForegroundColor Green; return }
  $sum = 0.0
  foreach ($s in $srv) {
    $age = (Get-Date).ToUniversalTime() - ([datetime]$s.created).ToUniversalTime()
    $r = $Rate[$s.server_type.name]; if ($r) { $sum += $age.TotalHours * $r }
    Write-Host ("  {0,-16} {1,-8} seit {2:0.0} h" -f $s.name, $s.server_type.name, $age.TotalHours)
  }
  $lb = hcloud load-balancer list -o json | ConvertFrom-Json | Where-Object { $_.name -like "$Prefix*" }
  Write-Host ("`n{0} Server + {1} LB   ~{2:N2} EUR bisher (nur Server)" -f $srv.Count, $lb.Count, $sum) -ForegroundColor Yellow
}

function Invoke-Down {
  Cluster-Servers | ForEach-Object { Write-Host "delete $($_.name)"; hcloud server delete $_.name | Out-Null }
  hcloud load-balancer list -o json | ConvertFrom-Json | Where-Object { $_.name -like "$Prefix*" } |
    ForEach-Object { hcloud load-balancer delete $_.name | Out-Null }
  hcloud network list -o json | ConvertFrom-Json | Where-Object { $_.name -like "$Prefix*" } |
    ForEach-Object { hcloud network delete $_.name | Out-Null }
  [Environment]::SetEnvironmentVariable('KUBECONFIG', $null, 'User')
  Write-Host "`nAlles abgerissen. Kosten gestoppt." -ForegroundColor Green
}

switch ($Action) { 'down' { Invoke-Down } 'status' { Show-Status } }
Die Hebel im Skript

Ein Abriss-Skript ist die gefährlichste Sorte Werkzeug. Diese Stellen entscheiden darueber, ob es nur den Cluster erwischt:

KonstruktStellebewirkt
#Requires -Version 5.1 Zeile 1 Keine Kommentarzeile, sondern eine Zusicherung an PowerShell: das Skript weigert sich zu starten, wenn eine aeltere Fassung laeuft. 5.1 ist die, die bei Windows 10 und 11 dabei ist – das Skript kommt also ohne Nachinstallation aus, muss dafuer aber auf die Bequemlichkeiten von PowerShell 7 verzichten (kein ??, kein &&, kein Ternaeroperator).
switch ($Action) { 'down' {…} 'status' {…} } letzte Zeile Die einzige Zeile, die etwas ausloest – alles darueber sind nur Definitionen. PowerShell laeuft die Datei von oben nach unten durch und legt dabei die Funktionen an; aufgerufen wird erst hier. Deshalb darf Invoke-Down weiter oben stehen als der Aufruf.
$Prefix = 'okd-'
Where-Object { $_.name -like "$Prefix*" }
überall Die einzige Sicherung des Skripts. Es löscht nichts, was nicht mit okd- beginnt – andere Server im selben Hetzner-Projekt bleiben unangetastet. -like ist der Vergleich mit Platzhaltern (*), nicht mit regulären Ausdrücken; dafür hiesse der Operator -match und ein Punkt träfe jedes Zeichen. Wer den Cluster anders benennt, muss diese Zeile mitändern – sonst findet down nichts und meldet trotzdem Erfolg.
[ValidateSet('down','status')]
$Action = 'status'
param Zwei bewusste Entscheidungen: ValidateSet lässt PowerShell die Eingabe prüfen, bevor eine Zeile läuft, und der Vorgabewert ist der harmlose. Ein Aufruf ohne Argument zeigt an, statt zu löschen.
$ErrorActionPreference = 'Continue' Kopf Bewusst nicht 'Stop': hcloud und ssh schreiben auch harmlose Hinweise nach stderr, und PowerShell 5.1 wertet das unter Stop als abbrechenden Fehler – das Skript bräche dann mitten im Abriss ab und liesse die Hälfte stehen.
Import-PowerShellDataFile Tarife Liest eine .psd1 als reine Daten ein – im Gegensatz zu Invoke-Expression oder einem gesourcten Skript wird darin kein Code ausgeführt. Das if (Test-Path …) … else … hält das Skript einzeln lauffähig, auch wenn die Datei fehlt.
hcloud … -o json | ConvertFrom-Json Abfragen Macht aus der Textausgabe echte Objekte, sodass $_.name und $_.server_type.name funktionieren. Der zuverlässige Weg – die Tabellenausgabe von hcloud zu zerlegen bricht, sobald sich eine Spaltenbreite ändert.
([datetime]$s.created).ToUniversalTime() Laufzeit Hetzner liefert den Zeitstempel als Text; die eckigen Klammern sind eine Typumwandlung. Beide Seiten der Subtraktion werden auf UTC gebracht – ohne das ist die berechnete Laufzeit im Sommer um zwei Stunden daneben, und die Kostenschätzung mit ihr.
("{0,-16} {1,-8} seit {2:0.0} h" -f …) Ausgabe Der Format-Operator. {0,-16} heisst „Argument 0, 16 Zeichen breit, linksbündig“ (positiv wäre rechtsbündig), {2:0.0} rundet auf eine Nachkommastelle. So stehen die Spalten untereinander, ohne von Hand Leerzeichen zu zählen.
Server → Load Balancer → Netz Invoke-Down Keine Stilfrage, sondern Pflicht: Hetzner verweigert das Löschen eines Netzes, solange noch etwas darin hängt. In umgekehrter Reihenfolge scheitert der letzte Schritt still – und ein Netz kostet zwar nichts, blockiert aber beim nächsten Aufbau seinen eigenen Namen.
| Out-Null Invoke-Down Verwirft die Bestätigungen von hcloud, damit die eigenen Write-Host-Zeilen die Ausgabe bestimmen. Sichtbar bleibt so, was gelöscht wird – bei einem Abriss-Skript der wichtigere Teil.
SetEnvironmentVariable('KUBECONFIG', $null, 'User') Invoke-Down Entfernt die dauerhaft gespeicherte Variable aus der Benutzerumgebung – $null löscht sie, eine leere Zeichenkette liesse sie mit leerem Wert stehen. Ohne das zeigt kubectl in der nächsten Sitzung auf einen Cluster, den es nicht mehr gibt, und hängt in Zeitüberschreitungen. Gilt erst in einer neu geöffneten Konsole, nicht in der laufenden.
Im Repo

Diese Datei liegt als scripts/cluster.ps1 bei (im Repo zusaetzlich mit Ausfuehrungszeit-Ausgabe wie die anderen Skripte) – nicht aus dem Browser abtippen.

Ebene 3 – naechtliches Auto-Teardown

Wie bei den anderen Anleitungen: Windows-Aufgabenplanung ruft scripts\cluster.ps1 down taeglich um 03:00. Bei einem 150-€-Cluster ist das der wichtigste Schutz – ein vergessenes Wochenende = ~15 €.

.\scripts\install-autodown.ps1 -For cluster   # legt die Aufgabe "OKD Auto-Teardown" an

+ Absicherung

  • Nodes ohne oeffentlichen Zugang: nach der Installation die Public-IPs der Master entfernen (hcloud server …) – Egress dann ueber ein NAT-Gateway oder Hetzners --without-ipv4 + IPv6 (Internet Protocol Version 6). Zugang nur noch ueber den LB und die Bastion.
  • LB-Firewall: 6443 und die Console (443) auf deine IP beschraenken, solange nichts oeffentlich sein muss (Hetzner-LB unterstuetzt keine Source-IP-Filter – dafuer eine Cloud-Firewall vor die Nodes, oder haproxy statt LB).
  • kubeadmin abschaffen: nach dem ersten echten OAuth-IdP (htpasswd, GitHub, …) den kubeadmin-Secret loeschen.
  • Updates: oc adm upgrade – OKD zieht neue Releases aus dem eigenen Update-Graphen.
  • etcd-Backup: oc debug node/…/usr/local/bin/cluster-backup.sh regelmaessig laufen lassen.
Fuer den Dauerbetrieb

Grundausstattung-Checkliste – 2FA aufs Hetzner-Konto, Tailscale fuer den Admin-Zugang, etcd-Backup ausser Haus, Monitoring, und der Kostenblick (bei ~425 €/Monat).

+ Kill-Switch

Anders als bei den Ein-Node-Anleitungen gibt es kein Snapshot-und-zurueck: ein Cluster mit geaenderten Node-IPs ist kaputt. Der Kill-Switch hier ist deshalb komplett abreissen (Skript in Schritt 13) plus naechtliches Auto-Teardown. Neu aufbauen = Schritte 6–10, ~45 Minuten.

Realistische Rechnung

3× CCX33 ≈ 0,57 €/Stunde zusammen ≈ 14 €/Tag. Ein Cluster, den du an 6 Abenden im Monat je 3 h nutzt, kostet ≈ 10 € – wenn das Auto-Teardown zuverlaessig laeuft. Vergisst du ihn einen Monat: ~425 €.

Ebene 4 – serverseitig

Ein Self-Destruct-Timer wie in den anderen Anleitungen ist hier heikel (er wuerde einzelne Nodes killen und den Cluster zerlegen, ohne den LB/das Netz aufzuraeumen). Besser: das Auto-Teardown auf dem Laptop und zusaetzlich ein Cron auf einem separaten Mini-Server (anderes Hetzner-Projekt), der einmal am Tag hcloud … delete fuer alle okd-* Ressourcen ausfuehrt.

+ Andere Wege zu echtem OpenShift

WegArtBemerkung
Hetzner Robot / Dedicated (AX41–AX102)self-hostDer richtige Hetzner-Weg fuer OKD: echte NVMe, ISO-Mount, KVM-Konsole. etcd-Latenz kein Problem. ~40–120 €/Monat je Node + Setup.
Assisted Installer (OKD)self-hostWeb-UI erzeugt eine Discovery-ISO, Nodes booten davon, UI (User Interface) installiert. Braucht ISO-Boot (Robot) oder coreos-installer wie hier.
Single Node OpenShift (SNO)self-host1 Node, voller Funktionsumfang, ab ~16 GB RAM (Random Access Memory) – aber keine HA (Hochverfügbarkeit). Fuer „echter Betrieb“ nur bedingt.
bare-metal auf anderen Cloudsself-hostVultr Bare Metal, OVH, Latitude.sh, Equinix – ueberall wo du FCOS (Fedora CoreOS) booten und einen TCP-LB stellen kannst.

Managed OpenShift – jemand betreibt die Control-Plane

DienstWoab ca.Bemerkung
ROSA (Red Hat OpenShift Service on AWS)AWS (Amazon Web Services)~0,03 $/h + WorkerRed Hat OpenShift on AWS. Voll gemanagt, Konsole, Operatoren, Support.
ARO (Azure Red Hat OpenShift)Azure~0,17 $/h + WorkerAzure Red Hat OpenShift. Aehnlich ROSA.
OpenShift DedicatedAWS / GCP (Google Cloud Platform)~1000 $/MonVon Red Hat auf deren Konten gehostet.
Developer SandboxRed HatgratisGeteiltes Projekt, ~30 Tage erneuerbar. Perfekt zum oc-Ueben ohne Cluster – eigene Anleitung.

Reihenfolge der Anleitungen nach Aufwand: Podman/Dockerk3sOKD Single-Nodedieser OKD-Cluster. Fang klein an.