IaC - Kubernetes fully automated with Terraform

Einleitung

Dieser Artikel bietet technisch Interessierten einen Einstieg in die Thematik IaC (Infrastructure as Code) und veranschaulicht den Mehrwert anhand eines einfachen Beispiels.

Die verwendeten Komponenten:

Ziel: deklarative Beschreibung einer Kubernetes-Umgebung, welche automatisiert bereitgestellt werden kann und damit die Eigenschaften der “Immutability” und “Reproducibility” gewährleistet.

Buzzwords

Da sich der Artikel auch explizit an alle Einsteiger in der Thematik IaC richtet, wollen wir mit den grundlegenden Begrifflichkeiten beginnen.

IaC

Inrfastruktur as Code beschreibt im Wesentlichen das Definieren seiner Umgebung in Form von Programmiercode. Bis Dato erfolgte dieser Teil vorwiegend imperativ, also ein System-Engineer erzeugt die Umgebung durch das Absetzen von Befehlen in chronologischer Reihenfolge. Also: Installiere Server A, vergib ihm Adresse 1, Installiere Software Z, usw. - Das ist zum einen schlecht reproduzierbar und fehleranfällig und zum anderen zeitaufwendig und wenig flexibel. IaC entgegnet diesem mit einer deklarativen Beschreibung. Das Beduetet wir führen keine Befehle in gewisser Reihenfolge durch, sondern beschreiben den Zustand der erreicht werden soll. Das kann zB. so aussehen:

Umgebung:
  Server A:
    - Adresse: 1
    - Software: Z

So weit so gut, nur von alleine wird diese “Beschreibung”, der IaC Code nicht angewandt. An dieser Stelle kommt Terraform ins Spiel.

Terraform

Nein, dabei handelt es sich um keinen terrestrischen Planeten! Wie zuvor angedeutet ist Terraform jene Software, welche die deklarativ beschriebene Umgebung für uns am ausgewähltem Ziel erstellt. Je nach Zielplattform gibt es unterschiedliche Erweiterungen und Module, welche eingesetzt werden können. Neben Terraform gibt es auch alternative Möglichkeiten wie beispielsweise Chef, Puppet, Vagrant, Ansible und viele weitere. Aktuell im Trend und für unseren Usecase gut geeignet ist jedoch Terraform.

Github

Dabei handelt es sich um Web-Anwendung welche eine Versionverwaltung für Softwareprojekte bereitstellt Quelle Wikipedia . Es dient als Speicherplatz für unseren IaC Code und ermöglicht es Teams gemeinsam an dem Projekt zu arbeiten. Auch können damit Änderungen verfolgt und im Bedarfsfall rückgängig gemacht werden.

Hetzner

Unsere Zielplatform! Hetzner basiert auf Openstack, ist eine Public Cloud und aufgrund der geringen Kosten vor allem für private Projekte hervorragend geeignet.

Big Picture

Nachdem wir die Hauptkomponente kennengelernat haben werfen wir einen Blick auf das Zusammenspiel dieser. Eine Grafik dient dabei exzelennt einen schnellen Überblick zu gewinnen.

terraform ablauf

Architektur

Im weiteren konzentriere ich mich ein wenig mehr auf die technischen Details.

Wieso Terraform Cloud?

Entscheidend für den Aufbau ist der Einsatz von Terraform Cloud, welcher zum einen die eigentlich Aufgaben, welche aus der deklarativen Beschreibung resultieren anwendet und zum anderen den tatsächlichen Zustand der Umgebung sichert. Vor allem das Sichern des Zustandes an einem zentralen Ort ist wesentlich. Nur dadurch können Teams gemeinsam an einem Projekt arbeiten. Würde man hingegen die Terraform CLI anwenden, wird der Status (.tfstate) lokal am PC gesichert und kann nur mehr von diesem einzelnen PC verarbeitet werden.

Angemerkt sei, dass neben der Terraform Cloud auch alternative Produkte eingesetzt werden, welche teilw. auf Open-Source basieren bzw. selbst gehostet werden können. Terraform Cloud jedoch bietet eine einfache Oberfläche und erleichtert die Einrichtung erheblich.

Welche Teil übernimmt “Kube-Hetzner”? Kube-Hetzner ist ein Modul bzw. Erweiterung, welche den Funktionsumfang von Terraform erweitert. Es handelt sich dabei um ein Community-Projekt, welches als Open-Source verfügbar ist und das Erstellen von Kubernetes-Clustern ermöglicht.

Sieht kompliziert aus? Gar nicht!

Es muss lediglich eine einzige Datei des Projektes seinen Ansprüchen entsprechend modifiziert werden, siehe Link: Example File

Im Hintergrund setzt Kube-Hetzner auf K3s (eine leichtgewichtige Kubernetes Version) sowie MicroOS von OpenSuse welches speziell für Container-Workloads konzipiert wurde.

Wie sieht die fertige Umgebung aus? Das fertige Konfigurationsfile, welches einen Kubernetes-Cluster mit den folgenden Eigenschaften erstellt, setzt sich wie folgt zusammen.

Eigenschaften:

  • 3 Master-Nodes
    • Lokation: Nürnberg 2x, Falkenstein 1x
    • dedizierter Loadbalancer für Masternodes
    • VM-Size: CPX11
  • 2 Worker-Nodes
    • Lokation: Nürnberg
    • VM-Size: CPX21
    • Pool-Name: Main

Konfiguration

Die tatsächliche Konfiguration sieht wie folgt aus. Achtung, die Variablen gleich zu Beginn wurden adaptiert, da wir diese innerhalb der Terraform Cloud verwalten möchten. Dort können Variablen mit sensitiven Inhalt vor neugierigen Augen versteckt werden.

variable "hcloud_token" {
  type = string
}
variable "ssh_public_key" {
  type = string
}
variable "ssh_private_key" {
  type = string
}

module "kube-hetzner" {
  providers = {
    hcloud = hcloud
  }
  hcloud_token = var.hcloud_token
    control_plane_nodepools = [
    {
      name        = "control-plane-fsn1",
      server_type = "cpx11",
      location    = "fsn1",
      labels      = [],
      taints      = [],
      count       = 1
    },
    {
      name        = "control-plane-nbg1",
      server_type = "cpx11",
      location    = "nbg1",
      labels      = [],
      taints      = [],
      count       = 1
    },
    {
      name        = "control-plane-nbg2",
      server_type = "cpx11",
      location    = "nbg1",
      labels      = [],
      taints      = [],
      count       = 1
    }
  ]

  agent_nodepools = [
    {
      name        = "main",
      server_type = "cpx21",
      location    = "nbg1",
      # Fully optional, just a demo
      labels = [
        "node.kubernetes.io/server-usage=storage"
      ],
      taints = [],
      count = 2
    }
  ]
  load_balancer_type     = "lb11"
  load_balancer_location = "nbg1"
}

provider "hcloud" {
  token = var.hcloud_token
}

terraform {
  required_version = ">= 1.2.0"
  required_providers {
    hcloud = {
      source  = "hetznercloud/hcloud"
      version = ">= 1.35.1"
    }
  }
}

Konfigurations-Link

Wichtig ist noch die zuvor definierten Variablen innerhalb der Terraform Cloud anzulegen: ssh_public_key, ssh_private_key, hcloud_token. Die beiden ersten dienen zum Erstellen der Schlüssel für den SSH zugriff, letztere ist für den eigentlichen Zugriff auf Hetzner erforderlich.

Was bringt`s?

Sein wir uns ehrlich, hätte ich die Umgebung manuell installiert, wüsste ich nach wenigen Tagen nicht mehr den genauen Ablauf. Selbst hätte ich jeden Schritt dokumentiert, wäre die Gefahr doch recht hoch, dass sich Kleinigkeiten geändert haben. Mit dem deklarativen Ansatz welchen Terraform bietet kann die gesamte Umgebung binnen Sekunden neu aufgebaut werden. Das Ergebnis wäre exakt dasselbe. Auch bietet es die Möglichkeit etwaigen Teammitgliedern mitzuwirken und die vorhandene Umghebung einfach zu erweitern ohne Gefahr laufen zu müssen etwas zu zerstören.

Aber auch für den laufenden Betrieb bringt IaC viele Vorteile. Hohe Last am System?

  agent_nodepools = [
    {
      name        = "main",
      server_type = "cpx21",
      location    = "nbg1",
      taints = [],
      count = 3
    }

Kein Problem, eine Zahl wird geändert (Count 3 statt 2) und die neue Version in unseren Github Repository gespeichert. FERTIG! Nach wenigen Minuten ist ein dritter Worker Mitglied unseres Kubernetes Cluster.

IaC, für mich: “Schon lange kein nettes Addon mehr, Must-Have!"