terraforming Hetzner, Pt 4

HA–Cluster mit mehreren Nodes aufbauen

Nach dem letzten Artikel läuft kubernetes ja schonmal. Um einen High Availability Cluster mit mehreren Nodes aufzubauen müssen wir tatsächlich nur noch wenige Dinge anpassen. In der Hauptsache holen wir das Beispiel mit den drei Webservern wieder hervor um mehrere VMs gleichzeitig anzulegen, und danach geben wir dem rke–Provider diese Liste mit.

Neue Variablen

variables.tf:

variable "ip_range" {
  default = "10.0.82.0/24"
}
variable "control_count" {
  default = 3
}
variable "worker_count" {
  default = 3
}

Die IP–Range kennen wir schon aus Part 2, die Variable instance_count von dort teile ich hier auf control_count und worker_count auf — um bei Bedarf mehr worker–Nodes dazustellen zu können.

Das interne Netzwerk

network.tf:

resource "hcloud_network" "k8s-nodes" {
  name     = "k8s-nodes"
  ip_range = var.ip_range
}

resource "hcloud_network_subnet" "k8s-node-subnet" {
  network_id   = hcloud_network.k8s-nodes.id
  type         = "cloud"
  network_zone = "eu-central"
  ip_range     = var.ip_range
}

resource "hcloud_server_network" "k8s-control-network" {
  count     = length(hcloud_server.k8s-control)
  server_id = hcloud_server.k8s-control[count.index].id
  subnet_id = hcloud_network_subnet.k8s-node-subnet.id
}

resource "hcloud_server_network" "k8s-worker-network" {
  count     = length(hcloud_server.k8s-worker)
  server_id = hcloud_server.k8s-worker[count.index].id
  subnet_id = hcloud_network_subnet.k8s-node-subnet.id
}

Das interne Netzwerk hat sich gegenüber Part 2 leicht verändert — da die control– und die worker–Nodes getrennt aufgesetzt werden doppelt sich hier der Block der die Nodes dem Netzwerk hinzufügt.

Neue Server

server.tf:

resource "hcloud_server" "k8s-control" {
  count       = var.control_count
  name        = "k8s-control-${count.index}"
  ...
  labels      = {
    type = "control"
  }
  ...
  network {
    network_id = hcloud_network.k8s-nodes.id
  }
  ...
}

count und das Looping kennen wir auch schon, neu ist der network–Block, der aus Server–Richtung nochmal angibt zu welchem Netzwerk die VM gehört. Das brauchen wir gleich, um im rke–Provider an die IP aus dem internen Netz zu kommen. Finde ich nicht so schön, habe aber keinen anderen Weg gefunden… Der ganze Block kommt nochmal für die worker–Nodes, die ungekürzte Datei liegt im Git–Repo.

Der große Cluster

cluster.tf:

resource "rke_cluster" "cluster" {
  kubernetes_version = var.kubernetes_version
  cluster_name = "hcloud_test"

  dynamic nodes {
    for_each = hcloud_server.k8s-control
    iterator = node
    content {
      hostname_override = node.value.name
      address = node.value.ipv4_address
      internal_address = node.value.network.*.ip[0]
      user    = "ansible"
      role    = ["controlplane", "etcd"]
      ssh_key = "${file("../ssh-terraform-hetzner")}"
    }
  }

  dynamic nodes {
    ...
  }
}

Im dynamic–Block für die nodes iterieren wir über die VM–Liste und erzeugen dabei die Node–Einträge, iterator legt den Variablennamen fest der in content dann nutzbar ist. Damit die k8s–nodes nicht einfach nach der IP heissen überschreibt hostname_override diese mit dem Namen, internal_address setzt die Kommunikation zwischen den Nodes ins interne Netz. Daher müssen wir auch in der firewall nichts freigeben. :)

Der Block folgt nochmal fast genauso für die worker–Nodes, mit entsprechend angepasstem for_each, und der role "worker".

terraform apply dauert jetzt schon etwas länger, am Ende steht dann aber wirklich ein ausgewachsener Cluster da.

Alle Dateien liegen im git–Repository, wie gewohnt.