Terraform – Infrastruktur als Code
Was sich hinter den Begriffen IaC, DevOps und Cloud Computing verbirgt, welche Möglichkeiten Continuous Integration bietet und wie ihr ganz einfach eure eigene Cloud Infrastruktur mit Terraform aufsetzen könnt, erklären wir im folgenden Blogartikel.
Statische Infrastruktur erschwert oftmals das flexible Arbeiten innerhalb der eigenen Softwarelösung und reagiert nur langsam auf wechselnde Anforderungen. Mit der Software Terraform liefert die Firma HashiCorp jedoch eine nachhaltige und zuverlässige Lösung, die dabei hilft das Ressourcenmanagement so weit wie möglich zu automatisieren.
Der Weg in die Cloud
Wie in unserem vorherigen Blogpost beschrieben, handelt es sich bei Cloud Computing einfach gesagt um das Konzept eigene Anwendungen oder Dienste auf fremder Hardware laufen zu lassen. Es gibt viele Dienstleister, die virtuelle Server oder sogar komplett fertige Web Services anbieten. Sie arbeiten nach den Prinzipien Click-to-Deploy. Die Infrastruktur lässt sich schnell und unkompliziert aufsetzen und ist schon nach wenigen Minuten einsatzbereit. Wartung und Sicherheit liegen in der Verantwortung des Anbieters.
Dadurch fällt ein bislang wichtiger Teil der klassischen IT weg. Unternehmen können sich auf ihre Kernkompetenz konzentrieren und müssen keine Ressourcen abzweigen, um ihre Infrastruktur am laufen zu halten. Für Softwareunternehmen hat das eine wichtige Implikation: Wurde zuvor die eigene Software von einem spezialisierten Operations Team gemeinsam mit der IT Infrastruktur betreut, fällt diese Aufgabe nun den Entwicklern zu. Man spricht von DevOps.
Fortlaufend und Vorhersehbar
Neben dem Abwandern in die Cloud gab es in den letzten Jahren einen weiteren wichtigen Trend in der IT: Agile Softwareentwicklung. Im Kern geht es bei agiler Produktentwicklung um iteratives Vorgehen. Jede Iteration sollte möglichst kurz gehalten werden, um schnell auf Änderungen bei den Anforderungen oder auftretende Probleme reagieren zu können.
Ein wichtiges Werkzeug bei agiler Entwicklung ist das Automatisieren von Prozessen. Dazu gehört neben dem fortlaufenden Bauen und Testen neuer Softwareversionen auch deren Deployment. Dies ermöglicht schnellere Releasezyklen und engere Interaktion mit dem Kunden. Tools wie Jenkins oder GitLab CI/CD (Continuous Integration/Continuous Delivery) sind dabei eine große Hilfe.
Anwendungen müssen in der Regel in verschiedenen Kontexten (Test, Staging, Produktion, …) bereitgestellt werden. Um die Vergleichbarkeit und Aussagekraft dieser Umgebungen gewährleisten zu können, muss das Aufsetzen des Systems stets zum gleichen Ergebnis führen. Bei DevOps ergibt sich hier ein Problem: Nicht nur die Anwendung selbst muss gebaut, getestet und releast werden, sondern auch die Infrastruktur. Hier kommt Infrastructure as Code (IaC) ins Spiel. Anstatt die Infrastruktur im Webinterface des Cloudanbieters zusammenzuklicken, kann diese mit IaC in Konfigurationsdateien beschrieben und von einem speziellen Tool per API an den Hoster übergeben werden. Das macht das Deployen der Infrastruktur automatisierbar und reproduzierbar.
Terraform
Eines der verbreitetsten Tools zum Aufsetzen von Cloudumgebungen ist Terraform von HashiCorp. Es unterstützt offiziell neben den Marktführern Amazon, Google und Microsoft auch „kleinere“ Cloud Dienstleister wie Oracle oder sogar self-hosted Lösungen wie Kubernetes. Hinzu kommen eine Vielzahl von Community-entwickelten Providern. Sogar noch größer ist die Anzahl der von der Community bereitgestellten Module. Dabei handelt es sich um fertige Konfigurationstemplates zu verbreiteten Anwendungsfällen, wie das Hosten einer statischen Website oder das Deployen einer Serverless REST API.
Um Terraform lokal oder in einer Build Pipeline benutzen zu können, wird das Terraform CLI benötigt. Dieser Interpreter dient als Schnittstelle zwischen den Konfigurationsdateien des Entwicklers und der API des Cloudproviders. Der erste Schritt in einem neuen Projekt ist die Entscheidung, welcher Provider verwendet werden soll. Wir bei Codeatelier setzen ausschließlich auf Amazon Web Services (AWS). Aber es ist auch möglich mehr als nur einen Provider in einem Projekt zu verwenden. Um einen Provider zu konfigurieren sind zwei Codeblöcke nötig:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 2.70"
}
}
}
provider "aws" {
region = "eu-central-1"
}
Der terraform
Block gibt an, welcher Provider und welche Version geladen werden soll. Im provider
Block lässt sich der Provider selbst konfigurieren. Bei AWS muss hier zum Beispiel angegeben werden, welche Rechenzentren (Region) verwendet werden sollen.
Terrafrom Konfig Files haben immer die Dateiendung „.tf“
. Der Dateiname spielt dabei keine Rolle. Alle tf-
Dateien im Arbeitsverzeichnis werden evaluiert. Allerdings gibt es die Konvention Inputvariablen in einer variables.tf
, Outputvariablen in einer outputs.tf
und alle benötigten Provider in einer versions.tf
zu sammeln. Die Cloud Infrastruktur wird in der main.tf
definiert. Will man das Projekt in Modulen strukturieren, wird pro Modul ein Unterordner verwendet, wobei innerhalb der Unterordner dieselbe Konvention gilt.
module "module-name" {
source = "./sub-folder"
param1 = 5
param2 = "test"
}
Ist der Provider im Code definiert, kann das Terrafrom Projekt zum ersten Mal initialisiert werden. Dafür navigiert man in einer Shell in das Projektverzeichnis und führt den Befehl „terraform init“
aus. Terraform lädt nun den Code für alle verwendeten Provider und externen Module herunter und cachet diese lokal. Sollten sich die verwendeten Module oder Provider im Laufe des Projekts ändern, muss ebenfalls wieder „terrafrom init“
aufgerufen werden.
Im nächsten Schritt können nun die benötigten Ressourcen definiert werden. Je nach Cloud Anbieter unterscheidet sich die Liste der verfügbaren Ressourcen, sowie deren Konfiguration. Um einen virtuellen Server bei AWS zu deployen reicht folgender Codeblock:
resource "aws_instance" "server" {
ami = "ami-0a6dc7529cd559185"
instance_type = "t2.micro"
}
Der Parameter ami
gibt dabei an, welches Betriebssystemimage verwendet werden soll und instance_type
die Hardware. Natürlich handelt es sich hierbei um die Standardkonfiguration. Die Ressource vom Typ aws_instance
bietet noch viele weitere Parameter, welche alle in der Provider Dokumentation beschrieben sind. Jede Ressource muss einen, innerhalb ihres Moduls, einzigartigen Namen haben. In diesem Beispiel ist der Name „server“.
Wie bereits erwähnt gibt es in Terrafrom die Möglichkeit Variablen zu definieren. Dabei muss zwischen drei verschiedenen Arten unterschieden werden: Input, Output und Local. Die Codeblöcke von Input Variablen haben das Schlüsselwort variable
vorangestellt. Sie werden, wie zu vermuten ist, zum Übergeben von Daten aus übergeordneten Modulen oder als Kommandozeilenparameter beim Deployen verwendet. Neben einem Datentyp kann bei diesen Variablen ein Standardwert und eine Beschreibung angegeben werden. All diese Parameter sind optional. Fehlt beispielsweise der Default, muss der Wert der Variable beim Deployen anderweitig übergeben werden.
variable "image_id" {
type = string
default = "ami-0a6dc7529cd559185"
description = "ID of the AWS AMI Image"
}
Output Variablen werden im Gegensatz dazu verwendet, um Daten an übergeordnete Module zu übergeben. Auch Ressourcen haben Outputs.
output "ip_address" {
value = aws_instance.server.private_ip
description = "The private IP address of the virtual server."
}
Der dritte Variablentyp sind Locals. Wie bei einer klassischen Programmiersprache können dort Werte zwischengespeichert werden, die öfter benötigt werden.
locals {
service_name = "example"
environment = "production"
}
Neben Ressourcen und Variablen gibt es noch einen weiteren häufig genutzten Blocktyp: data. Hiermit lassen sich Informationen aus externen Quellen ziehen. Seien es lokale Dateien oder Cloud Ressourcen, die nicht im aktuellen Terraform Projekt verwaltet werden.
data "local_file" "foo" {
filename = "${path.module}/foo.bar"
}
Sind alle benötigten Ressourcen definiert, ist der nächste Schritt einen „Bauplan“ zu erstellen. Mit „terraform plan“
werden alle tf-
Dateien im Arbeitsverzeichnis validiert und alle notwendigen Änderungen geplant. Das CLI zieht hierbei das sogenannte Terraform State File (terraform.tfstate
) zu Rate, das beim Deploy automatisch generiert wird. Es beschreibt den aktuellen Zustand der im Projekt verwalteten Infrastruktur. So kann unterschieden werden, welche Ressourcen neu erstellt, modifiziert oder entfernt werden müssen. Fehlt der State, wird geplant alle Ressourcen neu zu erstellen. Damit es beim Deployen nicht zu Namenskonflikten oder dem mehrfachen Erzeugen derselben Ressource kommt, ist es wichtig das tfstate-File
in einer Versionsverwaltung oder einem zentralisierten Statemanagement Service zu sichern.
Ist der Befehl erfolgreich durchgelaufen, kann der „Plan“ optional als Datei abgespeichert werden. Diese ist vor allem für die Dokumentation bei automatisierten Deployments mit CI/CD sinnvoll. Abschließend können die Änderungen mit „terraform apply“
deployt werden. Wird kein zuvor erstellter Plan übergeben, werden nochmal alle Änderungen aufgelistet und müssen einmalig manuell bestätigt werden.
Weiterlesen
https://learn.hashicorp.com/collections/terraform/aws-get-started
https://spacelift.io/blog/terraform-tutorial
https://spacelift.io/blog/cloud-deployment-models