Wir wollen in diesem Artikel ein komplett funktionsfähiges und produktionsfähiges Kubernetes Cluster erstellen, welches in der Hetzner cloud läuft. Dafür verwenden wir einmal das IAC Tool Terraform und das Projekt kube-hetzner. Mittels des kube-hetzner terraform Moduls können wir uns ein kostengünstiges, hochverfügbares und einfach zu betreibendes Kubernetes Cluster hochziehen.
Kube-Hetzner ist ein Open Source Modul für terraform, welches die Erstellung und die Verwaltung von Kubernetes Clustern mittels K3s auf der Hetzner-Cloud automatisiert. Dabei legt das Projekt Wert auf einfache, standardisierte, optimierte und hochverfügbare Cluster, welches Vergleichbar mit einem verwalteten Clustern bei AWS oder GCloud ist.
Eigenschaften sind als Beispiel:
Die Vorraussetzungen für das Projekt wären ein funktionierenden und fertig eingerichteten Hetzner Account. Da wir hier wirklich Server anlegen muss eine Zahlung hinterlegt sein, da wir sonst keine Server oder Loadbalancer erstellen können. Zusätzlich brauchen wir noch folgende Tools installiert:
Klare Vorraussetzungen sind natürlich, dass terraform installiert ist und wir einen funktionierenden Hetzner Account haben.
Wir navigieren zur Hetzner-Cloud Konsole und erstellen ein neues Projekt. Dafür navigieren wir zur Projekt Übersicht und klicken auf neues Projekt hinzufügen.

Hier geben wir einen für uns einmaligen Namen ein und können dann mit Projekt erstellen das Projekt anlegen lassen.

Jetzt wo das Projekt angelegt wurde müssen wir noch mit terraform drauf zugreifen können. Dafür legen wir uns ein API Key an. Wir klicken auf unser Projekt und danach im linken Seitenmenü auf Sicherheit.
Wir navigieren zum Punkt API-Tokens und klicken auf API-Token hinzufügen. Dort wählen wir Lesen & Schreiben aus und vergeben einen Namen.

Nach dem man den Key hinzufügegt hat erscheint ein weiteres Fenster, wo der Key sichtbar gemacht wird und man ihn kopieren kann. Wichtig ist hierbei, dass dies eine Einmal Ansicht darstellt und man nachdem den Key nicht mehr zu sehen bekommt. Man muss ihn also selber irgendwo erstmal speichern.
Jetzt wo der Key hinzugeüfgt wurde sieht man ihn auch in der Übersicht mit dem Namen, einem Prefix vom Schlüssel und die Berechtigungen.

Nun da in Hetzner alles vorbereitet ist können wir uns um die eigentlichen Terraform Dateien kümmern.
Die eigentlichen Dateien und das Aufsetzen dafür wird von kube-hetzner selbst übernommen mit folgendem Befehl können alle Dateien generiert werden. Bevor wir das Script allerdings ausführen hier einmal eine Auflistung was das Script genau tut:
1mkdir /path/to/your/new/folder
2cd /path/to/your/new/folder
3curl -sL https://raw.githubusercontent.com/kube-hetzner/terraform-hcloud-kube-hetzner/master/kube.tf.example -o kube.tf
4curl -sL https://raw.githubusercontent.com/kube-hetzner/terraform-hcloud-kube-hetzner/master/packer-template/hcloud-microos-snapshots.pkr.hcl -o hcloud-microos-snapshots.pkr.hcl
5export HCLOUD_TOKEN="your_hcloud_token"
6packer init hcloud-microos-snapshots.pkr.hcl
7packer build hcloud-microos-snapshots.pkr.hcl
8hcloud context create <project-name>
Nun kann das Script ausgeführt werden. Wir empfehlen das Script in einem leeren Ordner auszuführen. Der Befehl steht hier drunter.
1tmp_script=$(mktemp) && curl -sSL -o "${tmp_script}" https://raw.githubusercontent.com/kube-hetzner/terraform-hcloud-kube-hetzner/master/scripts/create.sh && chmod +x "${tmp_script}" && "${tmp_script}" && rm "${tmp_script}"
Wir werden zuerst gefragt in welchem Ordner wir das Projekt erstellen wollen. Hier können wir den Pfad einfach leer lassen, da wir uns schon im richtigen Verzeichnis dafür befinden. Wir bestätigen also mit enter.
1Enter the name of the folder you want to create (leave empty to use the current directory instead, useful for upgrades):
Als nächstes wird gefragt ob wir die Snapshots erstellen wollen mit packer. Die Snapshots dienen dazu spätere VM´s in Hetzner mit dem Snapshot als Vorlage zu starten. Wir können die in dem Script direkt erstellen lassen oder wir machen das später selber.
1Do you want to create the MicroOS snapshots (we create one for x86 and one for ARM architectures) with packer now? (yes/no):
Uns wurden nun zwei Dateien angelegt. Wenn wir nicht die Snapshots angelegt haben, können wir das mit dem installierten Tool packer nun selbst machen. Wir exportieren also erstmal unser Hetzner API token mittels folgendem Befehl:
1export HCLOUD_TOKEN="Unser HCLOUD TOKEN"
2packer init hcloud-microos-snapshots.pkr.hcl
3packer build hcloud-microos-snapshots.pkr.hcl
Nun ist auch auf der Seite alles vorbereitet und wir können uns dem eigentlichen terraform Modul widmen. Hier finden wir die Datei kube.tf. Diese Datei enthält erstmal sehr viele Zeilen. Wir haben hier einmal ein Beispiel wo alle optionalen Sachen und Kommentare entfernt wurden. Wir können natürlich auch das Skript hier nehmen um unser Cluster erstmal initial aufzusetzen. Wichtig ist, das auch das vollständige Script sofort einsatzfähig ist und uns ein funktionierendes Cluster liefert. Problematisch ist eventuell nur, dass wir zu viele Server damit erstellen und eventuell zu hohe kosten damit verursachen. Führen wir unser minimiertes Script aus haben wir kosten von ca. 9€ pro Monat.
1terraform {
2 required_version = ">= 1.5.0"
3
4 required_providers {
5 hcloud = {
6 source = "hetznercloud/hcloud"
7 version = ">= 1.43.0"
8 }
9 }
10}
11
12provider "hcloud" {
13 token = var.hcloud_token
14}
15
16variable "hcloud_token" {
17 type = string
18}
19
20module "kube-hetzner" {
21 source = "kube-hetzner/kube-hetzner/hcloud"
22 version = "2.18.0"
23
24 hcloud_token = var.hcloud_token
25 ssh_public_key = file("~/.ssh/id_ed25519.pub")
26 ssh_private_key = file("~/.ssh/id_ed25519")
27 network_region = "eu-central"
28
29 control_plane_nodepools = [
30 {
31 name = "control-plane"
32 server_type = "cpx11"
33 location = "fsn1"
34 labels = []
35 taints = []
36 count = 1
37 }
38 ]
39
40 agent_nodepools = [
41 {
42 name = "agents"
43 server_type = "cpx11"
44 location = "fsn1"
45 labels = []
46 taints = []
47 count = 1
48 }
49 ]
50}
Dieses Script legt uns nun einen Control-Plane Server und einen Agent-Pool Server an. Wir können auch den Agent-Node Pool einfach weglassen, indem wir bei count = 0 schreiben. Zusätzlich kann auch hier die Größe der eigentlichen VM´s variiert werden sowie der Standort.
Für ein Privates Image Repository muss die k3s_registries Variable vergeben werden. Als Beispiel sieht das wie folgt aus:
1k3s_registries = <<-EOT
2 mirrors:
3 registry.gitlab.com:
4 endpoint:
5 - "registry.gitlab.com"
6 configs:
7 registry.gitlab.com:
8 auth:
9 username: USERNAME
10 token: MY_GITLAB_TOKEN
11EOT
Wir können auch in dem Cluster die Storage Box verwenden als Samba File Share. Dafür müssen wir den Treiber einschalten und über die Firewall entsprechend den Port für SMB zulassen.
1enable_csi_driver_smb = true
2extra_firewall_rules = [
3 {
4 description = "For SMB"
5 direction = "out"
6 protocol = "tcp"
7 port = "445"
8 source_ips = []
9 destination_ips = ["0.0.0.0/0", "::/0"]
10 }
11]
1ingress_controller = "nginx"
2# Bei vielen Servern sollte auch die Anzahl der Replicas erhöht werden
3ingress_replica_count = 3
Vorallem bei kleineren Cluster kann es sinnvoll sein auch auf den Master Knoten Pods auszuführen. Dafür müssen wir ein Taint entfernen von den Master und können das auch per terraform machen.
1allow_scheduling_on_control_plane = true
Bitt bedenke, dass es bei kleinen Cluster keine automatischen OS Updates geben sollte, da es hier auf jeden Fall zu einer Downtime kommt. Das ganze kann hier abgeschaltet werden:
1automatically_upgrade_os = false
Möchten wir nun das Script ausführen müssen wir zuerst terraform initialiseren um das Modul auch bereit zu stellen. Ein terraform Projekt initialisieren geht mit dem terraform Befehl und dem Parameter init
1terraform init
Danach ist eigentlich schon alles Bereit. Wir können für die Einfachheit am Anfang einfach unser token oben rein kopieren bei den lokals.
1locals {
2 hcloud_token = "TOKEN EINFACH EINFÜGEN"
3}
Nun können wir uns mit terraform plan anschauen was genau geändert wird und mit terraform apply die Server in Auftrag geben.
1# Schreibt einen Plan aller Änderungen auf der Konsole
2terraform plan
3
4# Schreibt ebenfalls einen Plan aller Änderungen und fragt anschließend ob es erstellt werden soll. Bestätigt man das, wird terraform alle Ressourcen anlegen dafür. Ab hier entstehen auch die kosten!
5terraform apply
Auch wenn es einfach ist, dass Script auszuführen würde ich doch empfehlen es innerhalb einer Pipeline mit remote State auszuführen um keine Verluste zu haben bei Verlust des States. Gitlab, Github und Terraform selbst bieten Möglichkeiten an ein Remote state als http bereit zu stellen. Das Secret ist ebenfalls wichtig richtig zu sichern, da es hier bei Fremdnutzung leicht zu erhöhten kosten kommen kann. Daher meine Empfehlung es in Gitlab als Pipeline auszuführen und das Token als CI Variable zu hinterlegen und dort zu schützen, dass es nicht abrufbar ist.
Das Projekt bietet viele Möglichkeiten schnell ein sauberes Cluster hochzuziehen und dabei alle Konfigurationen in dem IAC-Tool zu haben um Änderungen nachzuverfolgen und auch bei Bedarf neue Cluster auf die gleiche Art und Weise bereitzustellen.