Skip to content

Migration — rein und raus

Kein Lock-in ist nur dann ein Versprechen, wenn du es tatsächlich einlösen kannst. Diese Seite dokumentiert das Handover (das Verschieben eines Clusters zwischen der gehosteten Control Plane von kubehz und deiner eigenen Infrastruktur) in beide Richtungen, genau so, wie es heute funktioniert.

Was heute live ist

Hosted → Self-Hosted (Eject) ist live. Du kannst deine gehostete Control Plane auf deine eigene Hetzner-Infrastruktur verschieben und behältst dabei die kryptografische Identität des Clusters: Deine Worker, Kubeconfigs und Secrets funktionieren weiter.

Self-Hosted → Hosted (Adopt) ist live als Recreation. kubehz stellt eine frische gehostete Control Plane bereit und du ziehst deine Workloads darauf um. Der Cluster bekommt eine neue Identität. Ein identitätserhaltendes Adopt ist geplant; bis es ausgeliefert ist, sagt diese Seite das offen, statt etwas anderes vorzutäuschen.

Die Konzepte dahinter (warum die Identität das ist, was umzieht, und warum nichts ohne deine Zustimmung gelöscht wird) findest du unter So funktioniert Handover.

Die zwei Richtungen

RichtungWas passiertStatus
Eject: Hosted → deine InfrastrukturDeine gehostete Control Plane wird auf deinen eigenen Maschinen wiederhergestellt, mit derselben Identität. Worker bleiben.Live
Adopt: dein Cluster → Hostedkubehz erstellt eine frische gehostete Control Plane; du ziehst Workloads darauf um. Neue Identität.Live (Recreation)

Eject ist für den Moment, in dem du volle Eigentümerschaft willst: Compliance-Anforderungen, Kostenkontrolle im großen Maßstab oder einfach, weil du es kannst. Die Ausgangstür ist der Beweis, dass Hosted eine Wahl ist und keine Falle.

Adopt ist für den Moment, in dem du keine Control Plane mehr selbst betreiben willst und nur noch Worker auf deinem Konto behältst.

Zuerst kommt das Assessment

Nichts bewegt sich, bevor du den Plan gesehen hast. Die Plattform sammelt kontinuierlich ein rein lesendes Assessment deines Clusters (Kubernetes-Version, Datastore, Storage-Klassen, Load Balancer, CAPI-Verwaltung) und leitet daraus einen Machbarkeitspfad plus einen Übersetzungsbericht ab, die Liste der Dinge, die nicht automatisch mitwandern und deine Aufmerksamkeit brauchen:

  • Provider-gekoppelte Storage-Klassen: Volumes, die vom CSI-Treiber eines Providers bereitgestellt wurden, folgen der Control Plane nicht zu einem anderen.
  • LoadBalancer-Services: Cloud-Load-Balancer sind an den Provider gebunden, der sie erstellt hat.
  • CAPI-verwaltete Cluster: ein Cluster, dessen Lebenszyklus von Cluster API gesteuert wird, braucht eine pausierte Verwaltung, bevor ein Handover sinnvoll ist.

Jederzeit einsehbar über die CLI (sie liest die Registry deines Tenants und braucht deshalb KUBEHZ_TOKEN):

bash
lo kubehz assess

Das Dashboard zeigt dasselbe Assessment samt Machbarkeit auf der Cluster-Seite. Der Machbarkeitspfad ist einer von:

PfadBedeutung
restoreUmzug per Snapshot + Identitäts-Seed. Was Eject heute nutzt.
recreationEine frische Control Plane; Workloads ziehen per Re-Apply um. Was Adopt heute nutzt.
graftEin Live-Transfer an Ort und Stelle. Wird bewertet und ausgewiesen, ist aber noch nicht ausführbar; er steht auf der Roadmap.

Hosted → Self-Hosted (Eject)

Eject verschiebt deine gehostete Control Plane auf Infrastruktur, die dir gehört, und behält die Identität des Clusters: die Zertifizierungsstelle (CA), die Service-Account-Signaturschlüssel, den Verschlüsselungsschlüssel für Secrets und jedes Objekt im Cluster (per etcd-Snapshot). Weil die Identität erhalten bleibt:

  • Deine Worker funktionieren weiter: Sie vertrauen bereits der CA des Clusters und verbinden sich nach dem Cutover mit demselben logischen Cluster.
  • Bestehende Kubeconfigs und Service-Account-Tokens bleiben gültig.
  • Secrets lassen sich entschlüsseln: Der Verschlüsselungsschlüssel reist mit dem Cluster.

Der Ablauf

  1. Assessment: lo kubehz assess (oder das Dashboard). Bestätige, dass der Pfad restore ist, und lies den Übersetzungsbericht.

  2. Handover starten: über den Handover-Tab des Clusters im Dashboard (oder per API). Du wählst den Ziel-Treiber (kubeadm oder kubeone) und ob der Endpoint erhalten bleibt oder rotiert wird.

  3. Die Plattform exportiert: Sie stellt das Export-Bundle zusammen (die PKI des Clusters, Service-Account-Schlüssel und Verschlüsselungsschlüssel) und erstellt einen frischen etcd-Snapshot.

  4. Bundle herunterladen: Der Download erfordert eine erneute Authentifizierung, ist einmalig und wird audit-protokolliert. Das Bundle ist die Root-Identität deines Clusters: Behandle es wie ein Root-Credential und lösche deine lokale Kopie, sobald das Handover abgeschlossen ist.

  5. Ziel vorbereiten: eine Maschine (oder Maschinen) in deinem Besitz, erreichbar für deine Worker. Konkret:

    • Auf 6443 erreichbar von jedem Worker: Das ist der API-Endpunkt, den lok8s konfiguriert. Ein Ziel hinter NAT ohne eingehenden 6443 ist die übliche Ursache dafür, dass ein Restore scheinbar gelingt und die Worker danach hängen bleiben.
    • Oberhalb der Reservierungen dimensionieren, nicht auf ihnen. Auf einem Control-Plane-Node reserviert lok8s 400m CPU und 1 GiB Arbeitsspeicher für System und kubelet, bevor irgendeine Workload läuft; das kubelet verdrängt Pods, sobald weniger als 500 MiB verfügbar sind. 2 GB sind damit die Untergrenze, keine Arbeitsgröße. Unsere eigenen Referenzkonfigurationen nutzen cx33 für Control Planes. Siehe den KubeOne-Leitfaden.
    • Ein oder drei Nodes, niemals zwei: etcd braucht eine ungerade Anzahl für das Quorum.
    • Ein Node führt höchstens 110 Pods aus. Dafür ist das Control-Plane-kubelet konfiguriert.
    • lok8s auf dem Ziel installiert, mit ausreichenden Rechten. receive läuft auf dieser Maschine, nicht auf deiner Workstation: Es schreibt /etc/kubernetes und /var/lib/etcd und ruft kubeadm auf.
    • Das Bundle auf dem Ziel. Schritt 4 lädt es dort herunter, wo du ihn ausgeführt hast; übertrage es über einen vertrauenswürdigen Kanal und lösche beide Kopien, sobald Schritt 7 bestätigt ist. Es ist die Root-Identität deines Clusters während der Übertragung.
    • Ein sauberer Knoten. receive verweigert eine Maschine, die bereits Kubernetes-Zustand trägt; führe auf einem zuvor genutzten Knoten zuerst selbst kubeadm reset aus.
  6. Restore auf dem Ziel:

    bash
    # kubeadm-Treiber: direkt auf dem Ziel-Node ausführen
    lo kubehz handover receive --bundle ./bundle.tar.gz
    
    # kubeone-Treiber: Identität vorab einspielen, dann wie gewohnt provisionieren
    lo kubehz handover preseed --bundle ./bundle.tar.gz --node "<node-ip>"
    lo provision

    receive kennt --snapshot <file>, um einen separat heruntergeladenen etcd-Snapshot wiederherzustellen, --single-node für eine Control Plane mit einem Node und --force, um einen Node zu überschreiben, der bereits Kubernetes-Zustand trägt (statt des kubeadm reset oben). preseed erreicht den Node per SSH: --user (Standard root), --port (Standard 22) und --ssh-key legen fest, wie.

    receive spielt die exportierte Identität ein, stellt den etcd-Snapshot wieder her und startet eine Control Plane, die dein Cluster ist: dieselbe CA, dieselben Schlüssel, dieselben Objekte.

  7. Cutover: Richte den Endpoint-DNS des Clusters auf deine neue Control Plane. Worker verbinden sich von selbst neu; auf ihnen ändert sich nichts. Dann bestätige den Cutover: Die Plattform wartet auf deine ausdrückliche Bestätigung und tut davor nichts Destruktives.

  8. Decommission: Die alte gehostete Control Plane wird erst entfernt, wenn zwei Dinge zutreffen. Die Plattform hat deine neue Control Plane lebendig gesehen (Heartbeats), und du hast das Decommissioning ausdrücklich bestätigt. Bis dahin bleibt die alte Control Plane als dein Fallback intakt.

Was du beim Cutover tust

Die eine Aktion, die allein dir gehört: den Endpoint-DNS des Clusters auf die neue Control Plane richten. Alles davor ist umkehrbar; die Plattform ändert deinen DNS niemals für dich. Wenn etwas falsch aussieht, bestätige nicht: Ein angehaltenes Handover behält den gesamten Zustand auf beiden Seiten.

Self-Hosted → Hosted (Adopt)

Adopt übergibt den Betrieb der Control Plane an kubehz: Du behältst nur Worker auf deinem Hetzner-Konto. Heute funktioniert Adopt per Recreation, und das sagen wir offen:

  • kubehz erstellt eine frische gehostete Control Plane mit einer neuen Identität (neue CA, neue Schlüssel). Auf der Plattform ist es ein neuer Cluster.
  • Deine Workloads ziehen per Re-Apply um (aus deinem GitOps-Repo oder deinen Manifesten) auf den neuen Cluster. Das ist der Moment, in dem sich ein deklaratives Setup auszahlt.
  • Persistente Daten ziehen nicht automatisch um. Stelle sie aus deinen eigenen Backups wieder her oder provisioniere sie neu. Einen automatisierten Data Mover gibt es noch nicht, also tun wir nicht so.
  • Nodes treten frisch bei: Worker starten gegen die neue Control Plane über Worker-Pools; alte Kubeconfigs und Tokens gelten nicht weiter.

Assessment und Übersetzungsbericht laufen zuerst, genau wie beim Eject. Du weißt also über provider-gekoppelten Storage, Load Balancer und CAPI-Verwaltung Bescheid, bevor irgendetwas erstellt wird.

Warum Recreation? Der verwaltete Control-Plane-Stack prägt die Identität eines Clusters bei der Erstellung. Deine bestehende Identität zuverlässig hineinzubringen erfordert einen Schritt „pausiert erstellen, dann seeden“, der entworfen und geplant ist. Sobald er ausgeliefert wird, erhält Adopt die Identität so, wie Eject es heute schon tut. Bis dahin bedeutet Adopt: frische Control Plane, Workloads neu angewendet.

Kein Lock-in: mit oder ohne Migration

Handover ist die starke Form des Versprechens, aber gebunden warst du nie:

  • lok8s ist Open Source und stellt deinen Cluster auf deinem Hetzner-Konto bereit.
  • Die Dashboard-Integration ist optional und nur ausgehend; kubehz hält keine eingehenden Zugangsdaten für deinen Cluster.
  • kubehz von einem Self-Hosted-Cluster zu entfernen sind zwei Befehle: lo kubehz deregister meldet ihn ab (braucht KUBEHZ_TOKEN), und das Löschen des kubehz-system-Namespace entfernt den clusterinternen Agenten. Das clusterweite RBAC des Agents (seine ClusterRole und ClusterRoleBinding sowie eine Role in kube-system) überlebt den Namespace; lösche auch diese Objekte, wenn du einen sauberen Cluster willst. Dein Cluster läuft genau wie zuvor weiter.

Nächste Schritte


Doku-Status

AspektDetail
ZustandEject live (restore-basiert); Adopt live als Recreation; identitätserhaltendes Adopt geplant
Zuletzt geprüft2026-09-05