Was ist Terraform und warum solltest du es dir einmal anschauen?
Terraform ist ein Tool, welches dir die Arbeit mit Ressourcen in deiner Infrastruktur erleichtert, deine Arbeit wiederholbarer und nachvollziehbarer macht und dir zusätzlich die Arbeit mit mehreren unterschiedlichen Hostern vereinfacht.
Es kann “Infrastructure as code” auf unterschiedliche Hoster ausliefern. Das heißt einfach nur, dass es eine standardisierte Art bietet, um verschiedene Ressourcen in einer Infrastruktur als Code zu beschreiben. Terraform übersetzt diese Struktur dann und setzt die Anforderungen über die API des Hosters um.
Falls du also mehr über Terraform wissen möchtest, dann zeigen wir dir in diesem Artikel unterschiedliche Beispiele, wie du es nutzen kannst und erzählen dir von unseren Erfahrungen.
Unsere Erfahrungen mit Terraform
Damit du so besser einschätzen kannst, ob Terraform etwas ist, was dich oder dein Team weiterbringen kann, möchten wir dir als Einstieg eine Übersicht geben, wie wir Terraform nutzen und welche Erfahrungen wir damit gemacht haben.
Wie setzen wir Terraform ein?
Aktuell können wir unsere Einsatzgebiete grob in zwei verschiedene Bereiche aufteilen. Einerseits geht es um das Erstellen, Anpassen und Löschen von Ressourcen für unsere Infrastruktur und andererseits um die Automatisierung von Prozessen, welche Änderungen an der Infrastruktur vornehmen.
Zum ersten Bereich gehören zum Beispiel das Erstellen neuer Server oder das Ändern des Servertypen, zum Zweiten das Umstellen von aktiven Servern in einem Loadbalancer während eines Deployments oder das Aktualisieren der Zertifikate, welche von unseren Loadbalancern genutzt werden.
Wo setzen wir Terraform ein?
Da es uns die Arbeit enorm erleichtert, versuchen wir Terraform überall dort zu nutzen, wo es möglich und sinnvoll ist. Aktuell nutzen wir Terraform bereits zur Verwaltung verschiedener Infrastrukturen in der Open Telekom Cloud, bei Digital Ocean, aber auch bei Amazon Web Services.
Das sind nicht nur komplette Netzinfrastrukturen, also virtuelle Netzwerke, öffentliche IP-Adressen und Loadbalancer, sondern auch die meisten unserer Server, sowie vom Provider bereitgestellte Ressourcen, wie Datenbanken und Caches.
Dadurch, dass Ergebnisse und Rückmeldungen aus Terraform an anderer Stelle verwendet werden können, ergeben sich viele Möglichkeiten zur Automatisierung und Kombination von Terraform mit anderen Technologien.
Welche Vorteile sehen wir für uns?
- Es ist keine Anmeldung und Navigation über Webinterfaces ist nötig
- Falls wir bestehenden Vorlagen haben ist eine sehr schnelle Erstellung und Konfiguration möglich
- Vorbereitung von Konfiguration
- Konfigurationen können bereits im Vorfeld erstellt werden
- Bestehende Konfigurationen können in der Regel schneller durchgeführt werden, als es uns über ein Webinterface möglich ist
- Ermöglicht es die Downtime gering zu halten oder zeitkritische Änderungen punktgenau durchzuführen
- Konfigurationen können Informationen von bestehenden Ressourcen nutzen
- Gemeinsames Hochfahren von zusammenhängende Ressourcen
- Vorherige Kontrolle von Konfigurationen durch Dritte mit Reviews
- Vermeidung von Fehlern und Minimierung von Fehlkonfigurationen
Was sollte dringend beachtet werden?
- „States“ (also bekannte „Zustände“) sind ein wichtiges Werkzeug bei der Nutzung von Terraform, aber es gibt ein paar Dinge zu beachten, da Terraform nur mit den im Code beschriebenen Ressourcen arbeitet und zusätzlich nur die Ressourcen kennt, welche in den “States” bekannt sind. Es wird also nicht die komplette Infrastruktur gescannt und abgeglichen. Die “States” werden über den zuvor genutzten Code oder importierte Ressourcen gefüllt.
- Viele Ressourcen können einfach als “Data Source” gesucht und referenziert werden. Welche “Data Sources” zur Verfügung stehen, hängt vom Provider ab und es kann nicht immer nach allen Ressourcen gesucht werden.
- Bereits bestehende Ressourcen, die im Code als Objekt beschrieben sind, können in der Regel einfach importiert werden. Importierte Ressourcen sind dann Teil der Konfiguration und werden entsprechend der Konfiguration geändert und mit dem Rest der Konfiguration beim Herunterfahren zerstört. Wie bei den Data Sources, werden die Funktionen für Imports durch den jeweiligen Provider bereitgestellt, sodass es nicht für alle Ressourcen eine entsprechende Funktion gibt.
- Falls die gleiche Terraform Konfiguration für verschiedene Umgebungen (Environments), also beispielsweise sowohl für eine “Staging” Umgebung, sowie für eine “Production” Umgebung genutzt wird, sollte enorm darauf geachtet werden, dass der “State” der Infrastruktur der gewünschten Umgebung entspricht. Ist dies nicht der Fall und die “States” sind nicht korrekt oder nicht vorhanden, kann es sein, dass zu viele Ressourcen erstellt werden, oder eine Änderung nicht durchgeführt werden kann, da eine entsprechende Ressource bereits besteht.
- Aus den gleichen Gründen können Probleme oder Fehler auftreten, wenn bestehende Ressourcen mit verschiedenen Quellen geändert werden. Damit gemeint sind unter anderem gleiche Terraform Konfigurationen, die unterschiedlichen “States” nutzen oder Änderungen über Terraform und das Webinterface durchgeführt werden.
Da Terraform häufig die normalen APIs nutzt, werden auch eventuelle Einschränkungen, Fehler oder Probleme dieser APIs übernommen. Es kann daher vorkommen, dass das Webinterface Optionen bereitstellt, die über die jeweilige API (und damit Terraform) noch nicht zur Verfügung stehen.
Wie funktioniert Terraform?
Terraform beschreibt Ressourcen oder Daten im Code als Objekt mit ihren Attributen.
Welche Objekte und Attribute du einsetzen kannst, wird sowohl durch Terraform selbst, aber auch durch den eingesetzten Provider bestimmt. Terraform stellt einige allgemeine Objekte und auch Funktionen bereit, die unabhängig vom Provider gleich sind.
Der Inhalt der Attribute kann wiederum auf Attribute anderer Objekte oder den Inhalt von Variablen verweisen (und diese bei Bedarf transformieren).
Es können sehr einfache Objekte, wie z.B. ein Netzwerk (VPC Ressource in der OTC) sein:
resource "opentelekomcloud_vpc_v1" "default" {
name = "vpc-default"
cidr = "10.0.0.0/8"
shared = true
}
- Es wird eine Ressource des Typs „ opentelekomcloud_vpc_v1“ und dem Namen „default“ erstellt
- Für alle weiteren Schritte kann die Ressource mit diesen beiden Werten referenziert werden
- Diese hat einen Namen und weitere Attribute(damit wird die Ressource beim Hoster erstellt)
Es können allerdings auch etwas komplexere Ressourcen, wie ein Server sein:
resource "opentelekomcloud_compute_instance_v2" "server" {
name = "${var.app_name}_server"
availability_zone = var.az
flavor_name = var.server_flavor
security_groups = ["web_server", "ssh_server"]
block_device {
source_type = "image"
destination_type = "volume"
uuid = "${var.image_uuid}"
volume_size = var.volume_internal
volume_type = "SATA"
delete_on_termination = true
}
}
- Wie zuvor haben haben wir ein Objekt mit den entsprechenden Attributen
- Zusätzlich werden in diesem Beispiel Variablen genutzt um bestimmte Attribute dynamischer definieren zu können
- Die Variablen beginnen alle mit „var.“ gefolgt vom definierten Namen
- Variablen, sowie andere andere Objekte können direkt mit <type>.<name> oder innerhalb eines Strings mit in ${<type>.<name>} referenziert werden
Externe Variablen müssen zuvor allerdings definiert werden. Dafür beschreibst du diese einfach über die Variablen Konfiguration (variables.tf). Du musst dort lediglich einen Namen definieren, hast aber die Möglichkeit diese Variable weiter zu beschreiben oder einzugrenzen. Das kann unter anderem eine Beschreibung sein, du kannst einen Standardwert vergeben oder die zugelassenen Werte eingrenzen.
variable "app_name" {
description = "name of the current app"
default = "MyApp"
type = string
validation {
condition = length(var.app_name) > 3
error_message = “app_name should be longer than 3 characters”
}
sensitive = false
}
- Es muss lediglich der Name der Variable festgelegt werden, alle weiteren Punkte sind optional
- Weitere Optionen sind z.B.
- eine Beschreibung
- ein Standardwert, falls die Variable keinen anderen Wert zugewiesen bekommt
- welche Werte für diese Variable genutzt werden dürfen
- Der Datentyp (z.B. auch ob es eine Liste ist und welcher Typen in der Liste genutzt werden dürfen)
- Eine Validation
- ob es sich um sensible Informationen handelt, die nicht im “State” gespeichert werden dürfen
Was passiert aber, wenn es Regeln dafür gibt, wie die Attribute aussehen dürfen?
Natürlich kannst du für jedes Attribut eine eigene Variable erstellen, welche den entsprechenden Regeln folgt, allerdings kannst du den Inhalt einer Variable auch einfach transformieren.
resource "opentelekomcloud_lb_certificate_v2" "certificate" {
name = "letsencrypt_${replace(replace(var.domain_name, "*.", "all."), ".", "_")}"
description = "certbot / letsencrpypt certificate for ${var.domain_name}"
domain = "${var.domain_name}"
certificate = file("${var.cert_path}/${replace(var.domain_name, "*.", "all.")}/fullchain.pem")
private_key = file("${var.cert_path}/${replace(var.domain_name, "*.", "all.")}/privkey.pem")
}
- Der Name darf hier z.B. keine Leerzeichen (spaces), Sternchen (asterisks) oder Punkte (dots) enthalten
- Die Variable selbst kann keine Leerzeichen enthalten. Da wir allerdings nur eine Variable Nutzen möchten, müssen wird diese so transformieren, dass wir einen validen Namen erhalten
- Wir wenden eine simple “replace” Function auf die Variable an und ersetzen die problematischen Zeichen.
Zusätzlich zur Nutzung von Variablen besteht die Möglichkeit Daten vom Provider oder zuvor erstellten Objekten zu benutzen, sowie mehrere Ressourcen auf einmal zu erstellen:
data "opentelekomcloud_vpc_subnet_v1" "subnet-default" {
name = "subnet-default"
}
resource "opentelekomcloud_lb_member_v2" "server_http" {
count = var.app_quantity
name = "${var.app_name}_${var.env_name}_${count.index}_http"
address = opentelekomcloud_compute_instance_v2.server[count.index].access_ip_v4
protocol_port = 80
pool_id = opentelekomcloud_lb_pool_v2.server_http.id
subnet_id = data.opentelekomcloud_vpc_subnet_v1.subnet-default.subnet_id
}
- Mit dem data Objekt suchen wir nach dem Subnetz mit den angegebenen Attributen und können im Anschluss darüber auf die Ergebnisse zugreifen
- Auf vorherige Ressourcen kann direkt zugegriffen werden
- mit <Ressourcentyp>.<name>
- in diesem Beispiel gehen wir davon aus, dass mehrere Server mit Count erstellt wurden
- Count erstellt die entsprechende Anzahl an Ressourcen
- mit count.index kann auf den Index der aktuellen Ressource zugegriffen werden
Warum spart uns die Nutzung von Terraform denn nun Arbeit?
Terraform ermöglicht uns das Automatisieren von Arbeitsschritten, die mit vergleichsweise viel zeitlichem Aufwand durchgeführt werden müssen oder viel Aufmerksamkeit benötigen und dadurch fehleranfällig sind. Durch bestehende Konfigurationen können wir beim Erstellen von neuen Ressourcen nicht nur den zeitlichen Aufwand, sondern auch Fehler minimieren und haben direkt eine Checkliste aller benötigten Informationen. Wir bemerken bereits Zeiteinsparungen bei der Erstellung von einzelnen neuen Ressourcen. Dies ist nicht nur bei der Nutzung unserer bestehenden Vorlagen erkennbar, sondern auch bei der Erstellung von neuen Konfigurationen der Fall. Das können unter anderem Konfigurationen bei zuvor nicht genutzten Hostern oder neue Ressourcentypen sein.
Allgemein benötigen wir weniger Zeit für das aktive Erstellen und Verwalten von Infrastruktur und können andererseits den Arbeitsaufwand und die Fehlerquote bei wiederholenden Aufgaben minimieren. Auch wenn es ein paar Dinge zu beachten gibt, können wir dir Terraform bei regelmäßigem Arbeiten an Ressourcen deiner Infrastruktur nur empfehlen.
Wobei können wir dich sonst noch unterstützen?
Neues Projekt
Du hast eine Idee für eine digitale Lösung und suchst einen Partner, der dich begleitet?
Verstärkung für dein Projekt
Du hast bereits eine Anwendung und suchst Verstärkung in der Entwicklung?