Terraform in der Praxis: LAMP-Stack in der Cloud
Mit Terraform lässt sich Infrastruktur für Anwendungen in der Cloud automatisiert erstellen und verwalten. Das Tool nimmt Administratoren und Entwicklern viel Routinearbeit ab, erfordert aber eine gewisse Einarbeitung.
![Terraform in der Praxis: LAMP-Stack in der Cloud](https://heise.cloudimg.io/width/610/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/2/3/6/5/4/8/7/admin-7a8cb4fafe93c0da.jpeg)
- Daniel Günther
- Jan-Christoph Küster
Während die Infrastruktur mit Bestandteilen wie Firewalls, Load Balancer und Server im klassischen Rechenzentrum statisch ist, entsteht und verändert sie sich im Cloud-Umfeld dynamisch. Anbieter von Infrastructure as a Service (IaaS) stellen dafür APIs bereit, über die Kunden benötigte Infrastruktur per Software zusammenstellen können. Das bietet die gewünschte Flexibilität, um Anwendungen in kurzer Zeit zu skalieren. Der Freiheitsgrad bringt jedoch auch Verwaltungsaufwand mit sich.
Dabei kommt das Infrastructure-as-Code-Werkzeug (IaC) Terraform unterstützend ins Spiel: Entwickler müssen nicht in einer API denken, sondern können in einer Konfigurationssprache, der HashiCorp Language (HCL), die geplante Zielinfrastruktur vollständig beschreiben, woraufhin Terraform sie bei einem der unterstützten Cloud-Anbieter erstellt. Dabei ermittelt das Tool Abhängigkeiten zwischen Teilen der Infrastruktur selbstständig und erstellt sie in korrekter Reihenfolge. Außerdem begleitet Terraform den kompletten Lebenszyklus einer Anwendung: Es speichert, welche Infrastruktur es bereits angelegt hat, um sie später verändern, erweitern oder wieder entfernen zu können.
Am Beispiel eines LAMP-Stacks [1] zeigt der Artikel auf, wie ein Terraform-Projekt aufgebaut ist und sich übersichtlich organisieren lässt. Der Quellcode steht zum Ausprobieren zur Verfügung.
Infrastruktur des LAMP-Stacks
Als Plattform zum Erstellen der Infrastruktur des LAMP-Stacks dient in diesem Artikel Amazon Web Services (AWS). Für Projekte lassen sich ebenso gut andere Cloud-Anbieter nutzen, da Terraform anbieteragnostisch ist.
Abbildung 1 zeigt die Architektur des LAMP-Stacks in der AWS-eigenen Notation. Jede Anwendung läuft bei AWS in ihrem eigenen, isolierten Bereich, der Virtual Private Cloud (VPC). Er hat einen privaten IP-Adressbereich (im Beispiel 10.0.0.0 – 10.0.255.255), in dem sich alle Komponenten des LAMP-Stacks befinden: Load Balancer, Webserver und Datenbanken. Um Ausfallsicherheit zu gewährleisten, lässt sich der Adressbereich jedes VPC in kleinere Subnetze unterteilen, die in vollständig unabhängigen Rechenzentren liegen. Diese heißen bei Amazon Availability Zones (AZ) und sind in der Abbildung orange gestrichelt gekennzeichnet.
Die Datenhaltungsschicht verwendet Amazon RDS mit MySQL Engine und greift damit auf einen von AWS bereitgestellten Service zurück. Die Dienste lassen sich ebenfalls mit Terraform erstellen und konfigurieren. RDS ist so konfiguriert, dass eine Replik des Master-Datenbank-Servers (blaue Box, rechts unten) in einer zweiten AZ bereitsteht, sollte der erste ausfallen.
Zwei EC2-Instanzen, die als Webserver fungieren (orangene Boxen) bilden die Webschicht des LAMP-Stacks. Das Werkzeug Chef dient zur Installation von PHP und Apache2 auf den Instanzen. Um je nach Bedarf zusätzliche Webserver automatisch hochfahren zu können, befinden sie sich in einer Auto-Scaling-Gruppe. Vor die Webserver ist ein Load Balancer (ebenfalls ein AWS Service) geschaltet, der Anfragen entgegennimmt und verteilt. Über die Adresse des Load Balancer können Nutzer die Testwebseite des LAMP-Stacks im Browser aufrufen.
Rote Linien markieren sogenannte Security Groups. Sie verhalten sich wie Firewalls und kontrollieren den eingehenden und ausgehenden Datenverkehr eines Servers. Beispielsweise gehen an die Webserver nur Anfragen vom Load Balancer auf Port 80 durch.
Grundbausteine eines Terraform-Projekts
Nun erfolgt die Beschreibung der vorgestellten Infrastruktur in der HCL, um sie auf Knopfdruck mit Terraform erstellen zu können. Die HCL hat HashiCorp eigens für diesen Zweck entwickelt, und sie hat den Vorteil für Mensch und Maschine (sie ist vollständig JSON-kompatibel) gleichermaßen gut lesbar zu sein. So ist die HCL kompakter als JSON, indem sie beispielsweise auf unübersichtliche Schachtelungen von Klammern und das Komma am Ende jeder Zeile verzichtet. Sie erlaubt Kommentare und ist intuitiver strukturiert als YAML. Die folgenden Codebeispiele verwenden alle die HCL.
Ein Terraform-Projekt setzt sich aus zahlreichen Codeblöcke zusammen, die jeweils mit Schlüsselwörtern wie provider, resource, variable, output beginnen.
provider "aws" {
region = "eu-central-1"
# Standardmäßig in ~/.aws/credentials
profile = "${var.profile}"
}
variable "profile" {
type = "string"
description = "AWS Account"
default = "testing"
}
Entwickler müssen zunächst über einen provider-Block festlegen, welchen Cloud-Anbieter sie nutzen wollen – im Beispiel AWS. Neben der für die Infrastruktur zu verwendenden Region müssen sie zudem Rechte für den Zugriff auf die API von AWS bereitstellen – in Form eines Zugriffstokens für den eigenen Account. Aus Sicherheitsgründen sollten sie ihn nicht im provider-Block direkt angeben und damit im Projekt versionieren. Stattdessen ist es ratsam, den Token als AWS-Profil in ~/.aws/credentials zu speichern und dann über den Profilnamen zu referenzieren.
Sinnvollerweise sollte der Profilname ein Parameter des Projekts sein. Somit können Entwickler eine Anwendung über unterschiedliche Profile beispielsweise zuerst in einem Test- und danach in einem Produktionsaccount erstellen. Dazu dient in Terraform der variable-Block. Jeder Block definiert genau eine Variable. Über den eindeutigen Namen des Blocks lässt sich ihr Wert mit ${var.profile} überall im Projekt verwenden. Variablen können eine Beschreibung und einen Standardwert haben. Gültige Datentypen sind Strings, Listen und Maps.
Beim Erzeugen der Infrastruktur mit dem Befehl terraform apply -var profile=production können Nutzer den Standardwert der Variable überschreiben, um beispielsweise die Infrastruktur im Produktionsaccount statt standardmäßig im Testaccount zu erstellen. Bei der gleichzeitigen Übergabe mehrerer Werte für Variablen kann es übersichtlicher sein, sie mit terraform apply -var-file=lamp.tfvars gebündelt in einer Datei zu übergeben.
Für eine AWS-Anwendung in Deutschland ist es sinnvoll, die Region Frankfurt zu verwenden (eu-central-1), um die Latenz für die Nutzer gering zu halten. Grundsätzlich lassen sich mehrere Provider-Blöcke angeben, um eine Anwendung in mehreren Regionen zu erstellen.
Die meisten Blöcke eines Terraform-Projekts sind resource-Blöcke. Ein einzelner beschreibt genau eine Infrastrukturkomponente, die in der Cloud erstellt werden soll:
resource "aws_vpc" "lamp" {
cidr_block = "10.0.0.0/16"
tags {
Name = "LAMP"
}
}
resource "aws_subnet" "webserver" {
vpc_id = "${aws_vpc.lamp.id}"
cidr_block = "10.0.1.0/24"
availability_zone = "eu-central-1a"
tags {
Name = "LAMP: Webserver"
}
}
Die beiden gezeigten resource-Blöcke erstellen das VPC und ein darin befindliches Subnetz. Insgesamt verwendet der LAMP-Stack 16 Ressourcenarten. Sinnvoll ist zudem, die Ressourcen mit dem Tag "LAMP" zu annotieren. Dadurch ist später leicht nachvollziehbar, zu welcher Anwendung Ressourcen gehören, wenn mehrere Anwendungen im selben Account laufen.
Beim Erstellen eines Subnetzes müssen Entwickler angeben, zu welchem VPC es gehört. Dazu verwenden sie den eindeutigen Bezeichner, den jede Ressource hat. Auf die Art können sie Attribute von Ressourcen referenzieren, im Beispiel über ${aws_vpc.lamp.id}.
Der output-Block dient der Ausgabe von Informationen über erstellte Ressourcen:
output "elb_dns_name" {
value = "${aws_elb.webserver.dns_name}"
}
Die Informationen lassen sich mit terraform output anzeigen. Beispielsweise können Entwickler sich komfortabel den DNS-Eintrag des Load Balancer anzeigen lassen, um die Testwebseite des LAMP-Stacks aufzurufen. Auf diese Weise können sie zudem vereinfacht Attribute der Infrastruktur in Shell-Skripte einbinden.