Einführung
Hetzner Cloud ist eine beliebte Wahl für Kubernetes-Bereitstellungen in Europa. Die Preisgestaltung ist übersichtlich – Server mit gemeinsam genutzten vCPUs sind bereits ab wenigen Euro pro Monat erhältlich – und die Infrastruktur ist zuverlässig. Für Teams, die auf die Komplexität (oder die Kosten) von AWS, GCP oder Azure verzichten können, bietet Hetzner alles, was man für den Betrieb von Kubernetes-Clustern in der Produktion benötigt, und das zu einem Bruchteil des Preises.
KubeOne bietet erstklassige Unterstützung für die Hetzner Cloud. Die offiziellen Terraform-Beispiele übernehmen die gesamte Bereitstellung der Infrastruktur – Server, Netzwerke, Load Balancer, Firewalls und SSH-Schlüssel –, sodass Sie nichts davon manuell konfigurieren müssen. Sie geben lediglich einen Clusternamen und ein API-Token an, und KubeOne kümmert sich um den Rest.
In diesem Tutorial richten Sie mithilfe von KubeOne und Terraform einen hochverfügbaren Kubernetes-Cluster mit drei Knoten auf der Hetzner Cloud ein. Am Ende verfügen Sie über einen produktionsreifen Cluster mit einem externen Load Balancer, privatem Netzwerk, automatischer Bereitstellung von Worker-Knoten über den Machine-Controller und einem klaren Upgrade-Pfad für zukünftige Kubernetes-Versionen.
Was Sie lernen werden:
- So konfigurieren Sie den Cloud-Anbieter Hetzner für KubeOne
- So nutzen Sie die offiziellen Terraform-Beispiele zur Bereitstellung von Infrastruktur
- So erstellen und wenden Sie ein KubeOneCluster-Manifest für Hetzner an
- So überprüfen Sie Ihren Cluster und fügen Worker-Knoten hinzu
- So schätzen und optimieren Sie Kosten
Schritt 1: Erstellen Sie ein Hetzner Cloud-API-Token
Sowohl KubeOne als auch Terraform benötigen ein API-Token, um mit der Hetzner Cloud zu kommunizieren. Melden Sie sich bei der Hetzner Cloud Console an, wählen Sie Ihr Projekt aus und navigieren Sie zu „Sicherheit > API-Token“.
Erstellen Sie ein neues Token mit Lese- und Schreibberechtigungen. Kopieren Sie das Token sofort – Hetzner zeigt es nur einmal an.
Exportieren Sie das Token als Umgebungsvariable. Sowohl Terraform als auch KubeOne lesen diese Variable automatisch aus:
Exportieren HCLOUD_TOKEN="Ihr-API-Token-hier"
Tipp: In Produktionsumgebungen sollten Sie das Token in einem Secrets-Manager oder einem
.envDatei, die von der Versionskontrolle ausgeschlossen ist. Committe keine API-Token in dein Repository.
Überprüfen Sie, ob das Token funktioniert, indem Sie Ihre vorhandenen Server auflisten (die Liste ist leer, wenn es sich um ein neues Projekt handelt):
curl -s -H "Authorization: Bearer $HCLOUD_TOKEN" https://api.hetzner.cloud/v1/servers | jq '.servers | length'
Erwartetes Ergebnis:
0
Schritt 2: Einrichten der Terraform-Konfiguration
KubeOne enthält offizielle, in der Produktion erprobte Terraform-Beispiele für jeden unterstützten Cloud-Anbieter. Anstatt Terraform-Code von Grund auf neu zu schreiben, nutzen Sie das Hetzner-Beispiel als Ausgangspunkt.
Laden Sie die KubeOne-Version herunter und entpacken Sie die Terraform-Beispiele:
# Die neueste Version von KubeOne herunterladen
curl -sfL https://get.kubeone.io | sh
# Die Beispiele sind im Release enthalten
# Kopiere das Hetzner-Beispiel in dein Projektverzeichnis
mkdir kubeone-hetzner && cd kubeone-hetzner
cp -r /usr/local/share/kubeone/examples/terraform/hetzner/* .
Falls sich die Beispiele nicht unter diesem Pfad befinden, klone sie bitte von GitHub:
mkdir kubeone-hetzner && cd kubeone-hetzner
git clone --depth 1 https://github.com/kubermatic/kubeone.git /tmp/kubeone-repo
cp -r /tmp/kubeone-repo/examples/terraform/hetzner/* .
rm -rf /tmp/kubeone-repo
Ihr Verzeichnis sollte nun Folgendes enthalten:
kubeone-hetzner/
├── main.tf
├── output.tf
├── variables.tf
└── versions.tf
Diese Dateien definieren die gesamte Infrastruktur: Control-Plane-Server, privates Netzwerk, Subnetz, Load Balancer, Firewall-Regeln, SSH-Schlüssel und Platzierungsgruppen für die Serververteilung.
Schritt 3: Terraform-Variablen konfigurieren
Erstellen Sie eine terraform.tfvars Datei mit Ihren Cluster-Einstellungen:
cluster_name = "production"
# Servertypen – siehe https://www.hetzner.com/cloud für aktuelle Preise
control_plane_type = "cpx21" # 3 vCPU, 4 GB RAM, 80 GB SSD
worker_type = "cpx31" # 4 vCPU, 8 GB RAM, 160 GB SSD
# Standort des Rechenzentrums
Rechenzentrum = „nbg1“ # Nürnberg. Alternativen: fsn1 (Falkenstein), hel1 (Helsinki)
# Von machine-controller verwaltete Worker-Knoten
initial_machinedeployment_replicas = 2
# SSH-Schlüssel für den Knotenzugriff
ssh_public_key_file = "~/.ssh/id_rsa.pub"
Auswahl der Servertypen
Hetzner Cloud bietet Server mit gemeinsam genutzten vCPUs (CX/CPX-Serie) und dedizierten vCPUs (CCX-Serie) an. Für Kubernetes:
| Rolle | Empfohlener Typ | Technische Daten | Ungefähre monatliche Kosten |
|---|---|---|---|
| Steuerungsebene | cpx21 | 3 vCPU, 4 GB RAM, 80 GB | ~5 EUR |
| Arbeitnehmer (allgemein) | cpx31 | 4 vCPU, 8 GB RAM, 160 GB | ~10 EUR |
| Arbeiter (Informatik) | cpx41 | 8 vCPU, 16 GB RAM, 240 GB | ~19 EUR |
| Arbeitnehmer (engagiert) | ccx13 | 2 vCPU, 8 GB RAM, 80 GB | ~14 EUR |
| Lastenausgleich | lb11 | 25 Ziele, 5 Dienstleistungen | ~6 EUR |
Hinweis: Hetzner aktualisiert regelmäßig seine Servertypen und Preise. Informieren Sie sich vor der Bereitstellung auf der Hetzner Cloud-Preisseite über die aktuellen Preise.
Verfügbare Terraform-Variablen
Das Hetzner-Terraform-Beispiel unterstützt folgende Variablen:
| Variable | Standard | Beschreibung |
|---|---|---|
Clustername | (erforderlich) | Bezeichnung für alle Ressourcen |
Anzahl der Control-Plane-VMs | 3 | Anzahl der Knoten der Steuerungsebene |
Steuerungsebene-Typ | cx23 | Hetzner-Servertyp für die Steuerungsebene |
Arbeitnehmertyp | cx23 | Hetzner-Servertyp für Worker |
lb_type | lb11 | Hetzner-Load-Balancer-Typ |
Rechenzentrum | nbg1 | Hetzner-Rechenzentrum |
os | Ubuntu | Betriebssystem (Ubuntu oder flatcar) |
ssh_public_key_file | ~/.ssh/id_rsa.pub | Pfad zum öffentlichen SSH-Schlüssel |
ssh_port | 22 | SSH-Port |
Anzahl der Replikate bei der ersten Maschinenbereitstellung | 2 | Anzahl der Worker-Knoten |
disable_kubeapi_loadbalancer | falsch | Auf „true“ setzen, um die Erstellung von LB zu überspringen |
Schritt 4: Bereitstellung der Infrastruktur
Terraform initialisieren, den Plan überprüfen und anwenden:
terraform init
terraform plan
Überprüfen Sie die Planausgabe. Es sollten Ressourcen für folgende Bereiche erstellt worden sein:
- 3 Control-Plane-Server (
hcloud_server.control_plane) - 1 privates Netzwerk mit einem Subnetz (
hcloud_network.net,hcloud_network_subnet.kubeone) - 1 Load Balancer für den API-Server (
hcloud_load_balancer.load_balancer) - 1 Firewall mit den für Kubernetes erforderlichen Ports (
hcloud_firewall.cluster) - 1 SSH-Schlüssel (
hcloud_ssh_key.kubeone) - 1 Zuordnungsgruppe zur Verteilung der Server auf die Hosts
Wenn alles korrekt aussieht, klicke auf:
terraform apply
Typ ja wenn Sie dazu aufgefordert werden. Terraform erstellt alle Ressourcen in etwa 1–2 Minuten.
Exportiere die Infrastrukturdaten für KubeOne:
terraform output -json > tf.json
Überprüfen Sie, ob die Ausgabe Ihre Infrastruktur enthält:
cat tf.json | jq '.kubeone_api.value.endpoint'
Erwartetes Ergebnis:
{
"host": "203.0.113.100",
"port": 6443
}
Der Host ist die öffentliche IP-Adresse des Hetzner-Load-Balancers, der vor Ihren API-Servern steht.
Schritt 5: Erstellen Sie das KubeOneCluster-Manifest
Erstellen kubeone.yaml mit der Hetzner-spezifischen Konfiguration:
apiVersion: kubeone.k8c.io/v1beta2
kind: KubeOneCluster
name: production
versions:
kubernetes: "v1.30.2"
cloudProvider:
hetzner: {}
external: true
containerRuntime:
containerd: {}
clusterNetwork:
cni:
canal: {}
features:
nodeLocalDNS:
deploy: true
Die wichtigen Hetzner-spezifischen Einstellungen:
cloudProvider.hetzner: {} weist KubeOne an, die Hetzner Cloud-Integrationen zu konfigurieren. Dazu gehört der Hetzner Cloud Controller Manager (CCM), der Ereignisse im Lebenszyklus der Knoten verwaltet und Kubernetes Metadaten über die zugrunde liegende Infrastruktur bereitstellt.
cloudProvider.external: true stellt den Cloud Controller Manager als externe Komponente (out-of-tree) bereit. Dies ist der empfohlene Ansatz für alle Cloud-Anbieter in modernen Kubernetes-Umgebungen. Der externe CCM läuft als Deployment im Cluster und ist nicht in das Kubelet integriert.
clusterNetwork.cni.canal: {} nutzt Canal (Calico + Flannel) als CNI-Plugin. Dies ist die Standardeinstellung von KubeOne und funktioniert bei Hetzner einwandfrei. Canal stellt ein VXLAN-Overlay-Netzwerk für die Kommunikation zwischen Pods bereit, während Calico für die Durchsetzung der Netzwerkrichtlinien zuständig ist.
features.nodeLocalDNS setzt auf jedem Knoten einen DNS-Cache ein, um die Latenz und die Auslastung von CoreDNS zu verringern.
Tipp: Sie können auch Cilium anstelle von Canal als CNI verwenden. Ersetzen Sie das
cniAbschnitt mitcilium: {}. Cilium bietet erweiterte Netzwerkfunktionen wie eBPF-basierten Lastausgleich und Netzwerküberwachung, setzt jedoch den Linux-Kernel 5.10 oder höher auf Ihren Knoten voraus (was die Ubuntu-Images von Hetzner bieten).
Schritt 6: Bereitstellung des Kubernetes-Clusters
Sobald Ihre Infrastruktur läuft und das Manifest bereit ist, richten Sie Kubernetes ein:
kubeone apply --manifest kubeone.yaml --tfjson tf.json
KubeOne zeigt Ihnen eine Übersicht über die geplanten Schritte an. Überprüfen Sie die geplanten Aktionen – folgende Punkte sollten aufgeführt sein:
- 3 Control-Plane-Hosts mit ihren Hetzner-IP-Adressen
- Kubernetes-Version v1.30.2
- Kanal CNI
- Hetzner – externer Cloud-Anbieter
Bestätigen Sie, um fortzufahren. KubeOne führt dann Folgendes aus:
- Stellt über SSH eine Verbindung zu jedem Knoten der Steuerungsebene her
- Installiert die Pakete „containerd“ und „Kubernetes“
- Den ersten Knoten der Steuerungsebene mit kubeadm initialisieren
- Verbindet den zweiten und dritten Knoten zu einem HA-Cluster
- Konfiguriert etcd auf allen drei Knoten
- Stellt den Hetzner Cloud Controller Manager bereit
- Stellt Canal CNI, den Metrics-Server und das lokale DNS bereit
- Stellt eine Maschinensteuerung für die Verwaltung der Worker-Knoten bereit
- Erstellt MachineDeployments für Worker-Knoten (basierend auf
Anzahl der Replikate bei der ersten Maschinenbereitstellung)
Der Vorgang dauert 5 bis 8 Minuten. Bitte unterbrechen Sie ihn nicht.
Erwartete Ausgabe (letzte Zeilen):
INFO[00:05:32] Kubeconfig wird heruntergeladen...
INFO[00:05:32] MachineDeployments sicherstellen...
INFO[00:05:33] Fertig!
Schritt 7: Auf den Cluster zugreifen und ihn überprüfen
KubeOne erstellt eine kubeconfig-Datei in Ihrem aktuellen Verzeichnis:
export KUBECONFIG=$(pwd)/production-kubeconfig
Überprüfen Sie, ob alle Knoten der Steuerungsebene bereit sind:
kubectl get nodes
Erwartetes Ergebnis:
NAME STATUS ROLLEN ALTER VERSION
production-cp-1 Bereit Steuerungsebene 6m v1.30.2
production-cp-2 Bereit Steuerungsebene 5m v1.30.2
production-cp-3 Bereit Steuerungsebene 5m v1.30.2
Worker-Knoten werden vom Machine-Controller asynchron bereitgestellt. Sie sind innerhalb von 2–3 Minuten verfügbar:
kubectl get nodes --watch
Sobald die Arbeiter erscheinen:
NAME STATUS ROLES AGE VERSION
production-cp-1 Ready control-plane 8m v1.30.2
production-cp-2 Ready control-plane 7m v1.30.2
production-cp-3 Ready control-plane 7m v1.30.2
production-worker-1 Ready <none> 2m v1.30.2
production-worker-2 Ready <none> 2m v1.30.2
Überprüfen Sie, ob alle System-Pods ausgeführt werden:
kubectl get pods -A
Du solltest Pods für den API-Server, den Controller-Manager, den Scheduler, etcd, CoreDNS, Canal, das lokale DNS des Knotens, den Machine-Controller und den Hetzner-Cloud-Controller-Manager sehen – alle in Laufen Zustand.
Überprüfen Sie den Hetzner Cloud Controller Manager
Das CCM verwaltet Knoten-Metadaten und Lebenszyklusereignisse. Überprüfen Sie, ob es läuft:
kubectl get pods -n kube-system -l app=hcloud-cloud-controller-manager
Erwartetes Ergebnis:
NAME BEREIT STATUS NEUSTARTE ALTER
hcloud-cloud-controller-manager-xxxxxxxxxx-xxxxx 1/1 Läuft 0 6m
Überprüfen Sie, ob die Knoten Hetzner-spezifische Bezeichnungen haben:
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.node\.kubernetes\.io/instance-type}{"\n"}{end}'
Hier sollte der Hetzner-Servertyp angezeigt werden (z. B. cpx21) für jeden Knoten, um sicherzustellen, dass das CCM die Metadaten der Knoten korrekt meldet.
Schritt 8: Eine Test-Workload bereitstellen
Überprüfen Sie, ob der Cluster voll funktionsfähig ist, indem Sie Nginx bereitstellen:
kubectl create deployment nginx--image=nginx:latest--replicas=4
kubectl get pods -o wide
Die Pods sollten auf Ihre Worker-Knoten verteilt werden. Überprüfen Sie die Netzwerkverbindung zwischen den Pods:
kubectl exec -it $(kubectl get pods -l app=nginx -o jsonpath='{.items[0].metadata.name}') -- curl -s -o /dev/null -w "%{http_code}" http://$(kubectl get pods -l app=nginx -o jsonpath='{.items[1].status.podIP}')
A 200 Die Antwort bestätigt, dass das Overlay-Netzwerk zwischen den Knoten ordnungsgemäß funktioniert.
Die Testumgebung bereinigen:
kubectl delete deployment nginx
Schritt 9: Skalierung der Worker-Knoten
Einer der Vorteile von KubeOne bei Hetzner besteht darin, dass die Skalierung der Worker-Knoten über den Machine-Controller vollständig automatisiert ist. Sie müssen keine Server manuell bereitstellen.
Bestehende Mitarbeiter skalieren
Um die Anzahl der Worker zu erhöhen, bearbeiten Sie die Datei „MachineDeployment“:
kubectl -n kube-system get machinedeployments
kubectl -n kube-system scale machinedeployment production-worker--replicas=4
Die Maschinensteuerung richtet neue Hetzner-Server automatisch ein, installiert Kubernetes und fügt sie dem Cluster hinzu. Neue Knoten sind innerhalb von 2–3 Minuten verfügbar.
Einen weiteren Mitarbeiterpool hinzufügen
Um Worker mit unterschiedlichen Servertypen hinzuzufügen (z. B. für rechenintensive Workloads), erstellen Sie ein neues „MachineDeployment“. Sehen Sie sich zunächst das vorhandene an, um es als Vorlage zu verwenden:
kubectl -n kube-system get machinedeployment production-worker -o yaml > worker-pool.yaml
Bearbeiten worker-pool.yaml: Ändern Sie den Namen und passen Sie den Servertyp an cloudProviderSpecund aktualisieren Sie die Replikanzahl. Wenden Sie das neue MachineDeployment an:
kubectl apply -f worker-pool.yaml
Schritt 10: Die Kostenaufschlüsselung verstehen
Bei der Standardkonfiguration (3x cpx21-Steuerungsebene, 2x cpx31-Worker, 1x lb11-Lastverteiler) belaufen sich Ihre geschätzten monatlichen Kosten auf:
| Ressource | Typ | Anzahl | Ungefähre Stückkosten | Insgesamt |
|---|---|---|---|---|
| Steuerungsebene | cpx21 | 3 | ~5 EUR | ~15 EUR |
| Arbeitnehmer | cpx31 | 2 | ~10 EUR | ~20 EUR |
| Lastenausgleich | lb11 | 1 | ~6 EUR | ~6 EUR |
| Privates Netzwerk | — | 1 | Kostenlos | 0 EUR |
| Insgesamt | ca. 41 EUR/Monat |
Hinweis: Die Preise sind Richtwerte und variieren je nach Rechenzentrum. Die aktuellen Preise finden Sie in der Hetzner Cloud-Preisliste. Der Datenverkehr innerhalb des privaten Netzwerks ist kostenlos. Der ausgehende öffentliche Datenverkehr ist bei den meisten Servertypen bis zu 20 TB/Monat inbegriffen.
Tipps zur Kostenoptimierung
- Verwenden Sie für Control-Plane-Knoten die CX-Serie anstelle der CPX-Serie, wenn Sie keine AMD EPYC-Prozessoren benötigen. Die CX-Serie (Intel) ist etwas günstiger.
- Beginnen Sie mit zwei Arbeitern und erweitern Sie die Kapazität nach Bedarf. Dank der Maschinensteuerung ist die Skalierung mit einem einzigen Befehl erledigt.
- Verwenden Sie Hetzner-Volumes für storage dauerhaften storage größere Servertypen für Speicherplatz bereitzustellen.
- Richten Sie die automatische Skalierung mit dem Kubernetes Cluster Autoscaler und dem Cloud-Anbieter Hetzner ein, um die Anzahl der Worker je nach Bedarf anzupassen.
Fehlerbehebung
Terraform schlägt mit der Fehlermeldung „Unauthorized“ fehl
Das API-Token fehlt oder ist ungültig. Überprüfen Sie, ob es festgelegt ist:
echo $HCLOUD_TOKEN
Wenn die Variable leer ist, exportiere sie erneut. Wenn sie gesetzt ist, Terraform aber dennoch fehlschlägt, generiere ein neues Token in der Hetzner Cloud Console – das alte wurde möglicherweise widerrufen.
Worker-Knoten werden nicht angezeigt
Wenn die Knoten der Steuerungsebene bereit sind, aber nach 5 Minuten noch keine Worker-Knoten erscheinen:
- Status der Maschinenbereitstellung prüfen:
kubectl -n kube-system get-machinedeployments
kubectl -n kube-system get machines
- Überprüfen Sie die Protokolle der Maschinensteuerung:
kubectl -n kube-system logs -l app=machine-controller-f
Häufige Ursachen: die HCLOUD_TOKEN Das Secret fehlt im Cluster, das Token verfügt nicht über Schreibrechte oder das Hetzner-API-Ratenlimit wurde erreicht.
- Überprüfen Sie, ob das Cloud-init-Geheimnis vorhanden ist:
kubectl -n kube-system get secrets | grep cloud-init
Knoten, die im Status „NotReady“ hängen geblieben sind
Wenn Knoten erscheinen, aber in Nicht bereit Zustand:
- Überprüfen Sie die Kubelet-Protokolle auf dem betroffenen Knoten:
ssh root@<node-ip> journalctl -u kubelet -f
- Überprüfen Sie, ob die Canal-Pods auf allen Knoten laufen:
kubectl get pods -n kube-system -l k8s-app=canal-o wide
Falls Canal-Pods vorhanden sind CrashLoopBackOffMöglicherweise ist das private Netzwerk nicht korrekt konfiguriert. Überprüfen Sie in der Hetzner Cloud Console, ob das private Netzwerk von Hetzner vorhanden ist und alle Server damit verbunden sind.
API-Server nicht erreichbar
Falls kubectl nach der Bereitstellung keine Verbindung herstellen kann:
- Überprüfen Sie in der Hetzner Cloud Console, ob der Load Balancer ordnungsgemäß funktioniert. Alle drei Control-Plane-Ziele sollten den Status „healthy“ anzeigen.
- Stellen Sie sicher, dass Port 6443 nicht durch eine lokale Firewall oder das Unternehmensnetzwerk blockiert wird.
- Überprüfen Sie, ob die kubeconfig auf die richtige IP-Adresse des Load Balancers verweist:
grep server production-kubeconfig
Nächste Schritte
Ihr Hetzner Cloud-Cluster ist nun in Betrieb und bereit für Workloads. Hier sind einige Möglichkeiten, wie Sie nun vorgehen können:
- Was ist KubeOne? – Falls Sie die Übersicht über die Konzepte übersprungen haben, lesen Sie diese jetzt, um ein tieferes Verständnis der Architektur von KubeOne zu erlangen
- Bare-Metal-Kubernetes mit KubeOne und Terraform – Vergleichen Sie den Hetzner-Workflow mit der Bare-Metal-Bereitstellung, um die Unterschiede zu verstehen
- KubeOne vs. kOps – Erfahren Sie, wie sich KubeOne im Vergleich zu anderen Cluster-Management-Tools schlägt
- Migration von Ingress-Nginx zu Gateway API mit KubeLB – Fügen Sie Ihrem Cluster einen auf Gateway API basierenden Lastausgleich hinzu
Zusammenfassung
Sie haben mithilfe von KubeOne und Terraform einen hochverfügbaren Kubernetes-Cluster auf der Hetzner Cloud bereitgestellt. Der Cluster umfasst drei Control-Plane-Knoten mit verteiltem etcd, zwei von machine-controller verwaltete Worker-Knoten sowie einen Hetzner-Load-Balancer, der den API-Server frontendet. Der Hetzner Cloud Controller Manager stellt Kubernetes Funktionen zur Verwaltung des Knotenlebenszyklus sowie Infrastruktur-Metadaten bereit. Die gesamte Konfiguration kostet etwa 41 EUR pro Monat und kann mit einem einzigen Befehl aktualisiert, skaliert oder repariert werden. kubeone apply Befehl.
