#tailnet

Das Lab wird multi-cluster — wiederholbar föderiert und evaluiert

Aus einem handverdrahteten Cluster plus Wegwerf-Test wurde ein wiederholbares Muster: ein Cluster pro Befehl, Apps im cluster-scope, Flux-Tenants, eine aufgeräumte Headscale-Domain — und Föderation statt Node-Mesh. Inklusive der Vorgeschichte (warum ClusterMesh rausflog), einer nüchternen Stabilitäts-Bewertung und dem, was als Nächstes fällig ist: Monitoring, Alerting, Backup und HA für die Föderations-Wurzel.

Die letzten Tage im Lab waren ein Strukturschnitt. Lange gab es genau einen ernsthaften Cluster — hydra, bare-metal — und daneben einen Wegwerf-Test, von dem die ClusterMesh-Episode erzählte. Inzwischen ist daraus ein wiederholbares Muster geworden: ein Cluster pro Befehl, Anwendungen im cluster-scope, Flux-Tenants, eine aufgeräumte Tailnet-Domain — und eine Föderation, die bewusst kein Pod-Mesh ist. Dieser Beitrag fasst die Änderungen zusammen, spricht ehrlich über die Probleme dahinter und bewertet, wie produktionstauglich das Ganze wirklich ist.

Cilium ClusterMesh durchs Tailnet — und warum ich es wieder rausgerissen habe

Zwei Talos-Cluster mit Cilium ClusterMesh über das Headscale-Tailnet verbinden — eine Sammlung der Fallstricke, der Erkenntnis, die die Datenebene zu retten schien, und des Outages, der mich am Ende zur Föderation ohne Node-Mesh zurückbrachte.

Im vorigen Beitrag habe ich das tailnet-gateway gebaut — die kleine Brücke, die API, Talos und DNS eines Clusters ins Headscale-Tailnet bringt. Das hier ist die Fortsetzung. Mein Lab hat inzwischen einen zweiten Cluster (cosmos bei Hetzner, neben dem bare-metal hydra), und beide sollten föderiert werden: Pods und Services clusterübergreifend, mit Cilium ClusterMesh .

Die offizielle Anleitung sagt: clustermesh-apiserver per LoadBalancer exponieren, dafür sorgen, dass sich die Knoten beider Cluster direkt sehen, fertig. Genau das wollte ich nicht. Ich habe schon ein verschlüsseltes WireGuard-Fabric über Headscale — die Föderation soll da durch, nicht über öffentliche IPs. Diese eine Entscheidung hat mich durch ein halbes Dutzend Fallstricke geführt. Hier sind sie.

Geo-redundantes S3 über die Föderation — Garage in zwei Phasen

Ceph RGW war pro Cluster — ein Standort-Ausfall, und der Bucket ist weg. Garage löst das: Phase 1 läuft heute single-cluster auf hydra mit Replication-Factor 3 und übersteht den Verlust eines Workers. Phase 2 macht jeden Cluster zu einer Zone und übersteht den Verlust eines ganzen Standorts — über dieselbe Tailnet-Föderation, gated auf denselben L4-Router.
Stand: zweiphasig. Phase 1 (Single-Cluster auf hydra, drei Knoten) läuft und hat das frühere Ceph RGW bereits abgelöst. Phase 2 (cross-cluster, eine Zone pro Cluster) ist Roadmap — Issue 6d3a0eb — und wartet auf eine Voraussetzung, die sich am Ende mit der Headscale-HA-Arbeit trifft.

Objektspeicher ist im Lab unspektakulär, aber überall: Restic-/VolSync-Backup-Targets, Artefakte, kleine statische Sites. Lange lieferte das Ceph RGW — pro Cluster. Genau das ist das Problem: Fällt der Standort aus, ist der Bucket weg. Seit die ClusterMesh-Episode eine Föderation über das Tailnet etabliert hat, wird ein echter Multi-Site-Store möglich. Die Antwort heißt Garage .

Headscale aus dem Single Point of Failure holen

Headscale ist die Kontrollebene der ganzen Föderation — und heute bewusst eine Single-Replica auf SQLite. Der geplante Weg zu HA: das Image festnageln, SQLite gegen CloudNativePG tauschen, den öffentlichen Endpunkt failover-fähig machen und das gebündelte tailnet-gateway entflechten.
Stand: Design/Roadmap. Das hier ist der geplante Weg, kein Live-Setup. Heute läuft Headscale im Lab bewusst als Single-Replica; die einzelnen Schritte leben als Issues im Backlog (rad issue list: b404b7a , 5f36156 , 231c25c , 8b9e4e1 , fa3985f ). Ich schreibe das auf, bevor ich es baue — die Reihenfolge ist der eigentliche Inhalt.

Im tailnet-gateway-Beitrag habe ich Headscale zur Kontrollebene des Labs gemacht: ein selbst gehosteter Coordination-Server, über den jeder Cluster ins Tailnet kommt. Die ClusterMesh-Episode hat denselben Strang weitergesponnen. Was beide stillschweigend voraussetzen: Es gibt genau eine Headscale-Instanz, auf hydra, und wenn die wegfällt, hat die Föderation kein Gehirn mehr. Genau diesen Single Point of Failure will ich auflösen — und der Weg dahin ist überraschend gestuft.

Den Tailscale-Operator für Headscale nachbauen: Das tailnet-gateway

Warum der offizielle Tailscale-Kubernetes-Operator nicht zu meinem selbstgehosteten Headscale passt — und wie ich die Teile, die ich brauche, als ein einziges StatefulSet nachgebaut habe

Mein Lab hängt an einem selbstgehosteten Headscale — einer quelloffenen Reimplementierung der Tailscale-Control-Plane. Das funktioniert wunderbar für Menschen und für die Talos-Knoten. Sobald ich aber wollte, dass auch die Cluster-Dienste sauber im Tailnet auftauchen — die Kubernetes-API, die Talos-API, die clusterinterne Namensauflösung —, stieß ich auf eine Lücke: Der offizielle Tailscale-Kubernetes-Operator ist für die Tailscale-SaaS gebaut, nicht für Headscale. Also habe ich die Teile, die ich tatsächlich brauche, selbst nachgebaut. Das Ergebnis ist ein einziges, gut lesbares StatefulSet: das tailnet-gateway.