Zum Inhalt springen

Dein eigener Gardener

paasbox garden up macht aus einem Hetzner-Cloud-Projekt in etwa 40 Minuten eine funktionierende Gardener-Landschaft: ein k3s-Laufzeitcluster (Gardener nennt ihn den Soil), Gardeners virtuellen Garden, einen Seed auf demselben Cluster und das Gardener Dashboard. Von dort aus erstellst du Cluster, Gardener nennt sie Shoots, über das Dashboard, mit kubectl oder mit dem CLI, und Gardener betreibt sie: Control Planes als Pods auf dem Seed, Worker als Hetzner-Server, Upgrades, Backups, Zertifikate, DNS.

Es ist keine Hülle um einen gehosteten Dienst. Alles läuft in deinem Projekt, mit deinem Token, und paasbox garden teardown entfernt alles wieder. Der Quellcode liegt auf GitHub unter Apache-2.0.

  1. Ein Hetzner-Cloud-Projekt und einen API-Token mit Schreibrechten. Das ist die eine Voraussetzung, die nichts wegnehmen kann. Alles andere erzeugt das CLI selbst oder kommt ohne aus.
  2. Ein paar Werkzeuge auf deinem Rechner: kubectl, helm, hcloud, flux, git, ssh und Python 3.11 oder neuer. paasbox doctor nennt jedes fehlende mit dem Installationsbefehl für macOS und Debian oder Ubuntu.
  3. Optional eine DNS-Zone, einen S3-Bucket und einen OIDC-Issuer. Nichts davon am ersten Tag.
Terminal-Fenster
curl -fsSL https://raw.githubusercontent.com/paasbox-cloud/paasbox-cli/main/install.sh | sh
paasbox doctor # was fehlt, und wie man es installiert
paasbox garden init my-garden # schreibt my-garden/values.yaml
$EDITOR my-garden/values.yaml # Name, Standort, DNS-Modus, Backup-Schalter
export HCLOUD_TOKEN=# das einzige Geheimnis, das die einfachste Form braucht
paasbox garden up my-garden # check → up → flux → garden → images → status

values.yaml ist die gesamte Konfiguration:

profile: solo # solo | ha
name: my-garden
location: nbg1 # nbg1 | fsn1 | hel1
os: debian-13 # debian-13 | ubuntu-26.04
dns:
mode: my-paasbox # my-paasbox | zone
backup:
enabled: false
dashboard: true
oidc:
mode: "off"
versions: {} # leer = die Versionen des Release

Jeder Befehl schreibt sein Stufenprotokoll nach my-garden/out/<stage>.log und gibt eine Zeile pro Stufe aus. Wenn up fertig ist, hast du eine Kubeconfig für den Garden und einen Beispiel-Shoot zum Anwenden:

Terminal-Fenster
export KUBECONFIG=my-garden/out/my-garden.virtual-garden.kubeconfig
kubectl apply -f my-garden/examples/first-shoot.yaml

Oder dasselbe mit dem CLI:

Terminal-Fenster
paasbox garden shoot create my-garden first --machine cpx32 --k8s 1.36
paasbox garden shoot list my-garden
paasbox garden shoot kubeconfig my-garden first --out first.kubeconfig
paasbox garden shoot delete my-garden first

Die Admin-Zugangsdaten eines Shoots sind kein Objekt, das du lesen kannst. Der Garden stellt sie auf Anfrage aus, und sie sind absichtlich kurzlebig; frag also erneut, wenn sie abgelaufen sind. Der erste Shoot ist etwa neun Minuten nach dem Erstellen bereit.

Gardener braucht Namen: für die Garden-API, für das Dashboard, für den Ingress des Seeds und für den API-Server jedes Shoots. Es gibt drei Wege, sie zu bekommen.

dns.modeWas es dich kostetWas du bekommstWann
sslipnichtsGarden, Dashboard und Seed-Ingress funktionieren, aber Shoots bekommen kein externes DNS, weil es keine Zone gibt, in die Records geschrieben werden könntenzum Ausprobieren (entworfen, noch nicht gebaut; up lehnt es heute ab)
my-paasboxein paasbox-Konto und eine Anmeldung im Browser<team>.paasbox.app, kostenlos, mit TXT-Records, damit Let’s Encrypt funktioniertdu hast keine Domain und willst eine echte Landschaft
zoneeine Domain, etwa 10 € im Jahr, und eine Hetzner-DNS-Zone mit ihrem Token in $DNS_TOKENdeine eigenen Namen, mit niemandem geteiltalles, was einen Versuch überdauert

Später wechseln sind zwei Zeilen in values.yaml und ein weiteres paasbox garden up.

dns.mode: my-paasbox braucht einen Token für die Namen deines Teams. Es gibt nichts aus einer Webseite zu kopieren: das CLI holt ihn selbst, und paasbox garden up startet die Anmeldung, wenn es ihn zum ersten Mal braucht.

$ paasbox garden up my-garden
dns.mode my-paasbox and no $DNS_TOKEN — signing in to console.paasbox.com
open https://console.paasbox.com/device (opening your browser…)
code FTQK-2X7M (expires in 10 minutes)
waiting… ✓ signed in — team Acme GmbH → acme.paasbox.app
### check — preflight …

Das ist der OAuth-2.0-Device-Grant, der Ablauf, den auch gh auth login und docker login benutzen. Er funktioniert über SSH und auf einer Maschine ohne Browser: --no-browser gibt die URL aus, und du bestätigst sie auf dem Telefon. Die Adresse des Portals ist einkompiliert und wird nie aus einer Antwort übernommen; eine Antwort, die woandershin zeigt, bricht die Anmeldung ab.

Terminal-Fenster
paasbox auth login # einen Team-Token holen (--team acme, --no-browser)
paasbox auth status # wer du bist, gegen das Portal geprüft
paasbox auth token # nur der Token, für ein Skript
paasbox auth logout # hier vergessen; widerrufen wird im Portal

Die Zugangsdaten liegen in ~/.config/paasbox/credentials.json mit Modus 0600 und werden nie in ein Landschaftsverzeichnis geschrieben. Ein Token, den du selbst exportierst oder in der .env der Landschaft hältst, hat immer Vorrang. sslip und zone reden nie mit dem Portal.

Der Team-Token kann Records unter dem Namen deines Teams schreiben und sonst nichts. Der Zonen-Apex und die Namen aller anderen Teams werden abgelehnt, und Lesezugriffe sind so gefiltert, dass der Rest der Zone für dich unsichtbar bleibt.

ProfilServerTrägtListenpreis, netto
solo1 × cpx62 (16 vCPU, 32 GB)Garden, Seed und einige Shootsetwa 130 € im Monat
ha3 × cpx42 (8 vCPU, 16 GB)Garden, Seed und etwa zwölf Shoots; überlebt einen Nodeetwa 208 € im Monat

Prüf die aktuelle Hetzner-Preisliste; das sind Listenpreise vom Tag, an dem das geschrieben wurde, und jeder Shoot bringt seine eigenen Worker mit. Ein 16-GB-Server kann eine Landschaft gar nicht betreiben: Gardeners eigenes Monitoring fordert etwa 8 GiB an, und auf einem 16-GB-Node bleiben sechs Pods für immer Pending. Das wurde gemessen, nicht geschätzt, und deshalb ist solo ein 32-GB-Server.

Die Control Plane jedes Shoots braucht im Leerlauf etwa 1,5 bis 2 GiB und eine halbe vCPU auf dem Seed; das ist gemeint mit „trägt einige Shoots“. Eine Cloud-Landschaft betreibt ihren Ingress außerdem über zwei Hetzner-Load-Balancer, weil Gardener zwei Istio-Ingress-Gateways betreibt, das des virtuellen Gardens und das des Seeds. Rechne mit etwa 12 € netto im Monat dafür.

Ein server:-Block in values.yaml legt die Landschaft auf einen dedizierten Hetzner-Server, den du schon mietest, statt auf einen Cloud-Server, den das CLI erstellt. Das Preisargument in einem Satz: Eine Solo-Landschaft braucht 32 GB, das kostet als Cloud-Server etwa 130 € im Monat und beginnt als 64-GB-Server aus Hetzners Serverbörse bei etwa 60 € im Monat.

server:
kind: robot # ein dedizierter Hetzner-Server (Robot); heute die einzige Art
number: 1234567 # deine Robot-Servernummer; die Adresse wird ermittelt, nie konfiguriert
login: admin # der Admin-Login pro Server (Robot → der Server → Rescue)
reimage: true # das OS zuerst über das Rescue-System installieren. DIE PLATTE WIRD GELÖSCHT, einmal

up löst dann die Servernummer in eine Adresse auf, geht ins Rescue-System und installiert mit reimage: true Debian 13 und wartet, bis die Maschine zurück ist. Ein zweites up auf einer Maschine, die diese Landschaft schon installiert hat, installiert nichts neu und prüft nur. Ein dedizierter Server hat keinen Cloud-Load-Balancer, also teilt ein haproxy auf dem Node Port 443 nach Servernamen zwischen den zwei Istio-Gateways auf und veröffentlicht beide unter einem Namen. Es wird kein Hetzner-Netzwerk, keine Firewall, kein Volume und kein Load Balancer erstellt.

Drei Dinge, die du vorher wissen solltest:

  • Welchen Login du ihm gibst. Der Admin-Login pro Server erreicht diesen einen Server und sonst nichts, und ist der, den du bevorzugen solltest. Er braucht sshpass für eine einzige erste Verbindung. Ein Robot-Webservice-Benutzer ist die Alternative; er erreicht jeden Server des Kontos.
  • Der Server hat keine Cloud-Firewall. Filtere selbst, auf der Maschine oder mit Hetzners Robot-Firewall: 22 und 6443 von deinen eigenen Adressen, 80 und 443 von überall, 8443 und 8132 für die Verbindung der Shoots zurück zum Seed.
  • Nichts in paasbox kann einen Server kündigen. Es gibt nirgends einen solchen Aufruf. teardown entfernt die DNS-Records und lässt die Maschine unberührt; teardown --wipe --yes installiert sie neu. Den Vertrag beenden ist etwas, das du von Hand in Robot tust.

Das Hetzner-Cloud-Projekt und den Token brauchst du trotzdem: Die Worker deiner Shoots sind Cloud-Server.

Ad hoc ist der Standard: paasbox garden init my-garden, und Flux auf dem Cluster synchronisiert das öffentliche Kit nur lesend am Release-Tag. Deine Werte gelangen als ConfigMap und Secret in den Cluster. Es gibt kein Repository, das du pflegen musst.

Dauerhaft ist paasbox garden init my-garden --gitops: dieselbe Landschaft plus ein kleines GitOps-Repository von dir, mit einer README, values.yaml und einer Flux-GitRepository und -Kustomization, die auf das öffentliche Kit an einem Tag zeigen. Du pushst es, Flux synchronisiert es, und du legst deine eigenen Manifeste daneben. Wenn ein neues Release kommt, rendert paasbox garden update neu, was die Vorlage besitzt, und lässt deine Änderungen in Ruhe. Das ersetzt das Forken des Kits.

Terminal-Fenster
paasbox garden status my-garden # Garden, Seed, Shoots, Backups
paasbox garden dashboard-token my-garden # ein Login-Token für das Dashboard
paasbox garden images my-garden # die Worker-Image-Snapshots in deinem Projekt
paasbox garden upgrade my-garden # der k3s-Versionsschritt, ein Server nach dem anderen
paasbox garden restore my-garden # an Ort und Stelle, aus dem neuesten etcd-Snapshot in S3
paasbox garden update my-garden # ein neues Release: neu ableiten, neu rendern
paasbox garden teardown my-garden --yes # Server, Volumes, Netzwerk, Firewall, Records

backup.enabled: true schreibt alle zehn Minuten einen etcd-Snapshot nach S3 und hält das Material vor, das eine Wiederherstellung an Ort und Stelle braucht. Aus, verlierst du restore und den Wiederherstellungspunkt von zehn Minuten. Es braucht einen Bucket im selben Projekt, den Hetzner Object Storage mit einem Klick anlegt, sowie $S3_ACCESS_KEY und $S3_SECRET_KEY.

--stub an jedem Befehl lässt die gesamte Abfolge gegen eine Attrappe im Speicher laufen: kein Hetzner, kein SSH, kein Geld. So probt die CI einen Aufbau in einer Sekunde, und so siehst du, was die Befehle tun, bevor du etwas ausgibst.

oidc.mode: "off" ist Token-Login. dex-github betreibt Dex auf dem Soil mit dem GitHub-Connector: Du legst eine GitHub-OAuth-App an, trägst Client-ID und Secret in die Umgebung ein und listest die GitHub-Logins oder die Organisation und das Team, die Garden-Admins werden. external zeigt den Garden auf deinen eigenen Issuer, etwa Zitadel, Keycloak, Entra oder Google.

  • Kein Managed Service. Niemand außer dir schaut auf deine Landschaft. Wenn du Cluster ohne Landschaft willst, kann ich sie für dich betreiben, nach bestem Bemühen.
  • Nicht mandantenfähig. Ein Projekt, ein Garden, ein Seed. Keine Abrechnung, kein Portal, keine Kontingente.
  • Kein Kit zum Forken. Das Kit wird per Tag bezogen; du behältst Werte, keine Kopien.
  • Kein Support. Es ist kostenlos und nach bestem Bemühen: ein Open-Source-Projekt, das einem Team hilft, seinen eigenen Gardener zu betreiben. Issues werden gelesen; versprochen wird nichts. Wenn du es richtig lernen willst, mit mir im Raum, gibt es einen Kurs.

Das CLI wird im gardener-stack-Monorepo entwickelt, neben dem Deployment, das es steuert, und bei jedem Release auf GitHub und PyPI veröffentlicht. Das öffentliche Repository ist ein nur lesbarer Schnappschuss mit offenen Issues; Beiträge kommen als Patches gegen das Monorepo zurück. Lizenziert unter Apache-2.0.