Intro

Neu in der Cloud? Endlich kann es losgehen in der Konsole – also das Portal, wo du Ressourcen deines Cloud-Anbieters anlegen, bearbeiten oder löschen kannst. Der erste Impuls: Klick, klick, klick. Super, der Server steht. “Super” denkt sich deine Kollegin. Im Team brauchen wir jetzt noch ein paar Server. Du bist wieder an der Reihe: Klick, klick, kl-äh wie was noch mal die Einstellung? Was hatte ich da vorher ausgewählt? Klick, Klick, klick, mist – die falsche Größe. Wieder zurück, klick, klick … You get it.

In meinem aktuellen Projekt arbeiten wir mit verschiedenen Kunden zusammen. Sie alle haben ihre eigene Infrastruktur, welche aber immer gleich aufgebaut ist. Mit gecodeter Infrastruktur können wir wesentlich einfacher und flexibler ein neues Setup live nehmen. Und das Beste: Ich muss mir nicht merken, was ich zuvor bei den Kunden eingerichtet habe. Es ist ja alles gescriptet. Kein “Klicki-Bunti”-Dilemma. 😎

Was ist IaC?

Infrastructure as Code (IaC) ist ein Werkzeug um das Setup deiner Infrastruktur nachhaltig und später auch automatisiert bereitzustellen. Dabei codest du deine Infrastruktur. Je nachdem welches Tool du wählst, unterscheidet sich, wie du deine Infrastruktur coden musst. Bei manchen verwendest du eine eigene Sprache. Andere Tools bauen auf YAML auf oder arbeiten mit gängigen Programmiersprachen wie Python oder Typescript. Aus deinem Code interpretiert dann das gewählte Tool die anzulegenden Ressourcen für den Provider. Ein Provider bezeichnet dabei z.B. einen Cloud-Anbieter (AWS, Azure, Google usw.), Kubernetes, MySQL oder auch Github usw.

Der IaC Workflow - viele Tools führen zum Ziel

Wenn du deine Infrastruktur codest, ist der Aufbau eindeutig beschrieben und kann somit auch in einen Deployment-Prozess eingebunden werden. Damit ist es ein Leichtes das Deployment deiner Infrastruktur zu automatisieren. Weitere Vorteile von IaC sind ein geringerer Wartungsaufwand und dadurch verbundene geringere Kosten sowie weniger Zeit, die in den Aufbau einer Infrastruktur gesteckt werden müssen (only code once).

In diesem Artikel zeige ich dir, wie du mit Terraform deine Infrastruktur in AWS coden kannst.

Was ist Terraform?

Terraform ist ein Produkt von HashiCorp, welches 2014 veröffentlicht wurde. Terraform ist Open Source und wird unter der Mozilla Public License v2.0 auf Github veröffentlicht. Terraform nutzt die Konfigurationssprache HCL (HashiCorp Configuration Language) - eine von HashiCorp entwickelte Skript-Sprache.

Installation

Um Terraform zu nutzen, installiere die Terraform CLI.

# manual installation (WSL/Linux)
# get latest terraform binaries for your system https://www.terraform.io/downloads.html
wget https://releases.hashicorp.com/terraform/0.14.4/terraform_0.14.4_linux_amd64.zip
unzip terraform_0.14.4_linux_amd64.zip
# move terraform to an existing dir included in PATH 
# (or add current dir to PATH)
mv terraform /usr/local/bin/

Eine Manuelle Installation kann von Vorteil sein, wenn man nicht mit der aktuellen Version von Terraform arbeiten kann. Ältere Versionen findet man unter: https://releases.hashicorp.com/terraform/

💡 Neben der manuellen Installation kann man die Terraform CLI auch über homebrew (MacOS), chocolatey (Windows) und z.B. apt-get oder yum (Linux) installieren. Mehr dazu findest du in HashiCorp’s Starter Guide.

Keywords

Um die einzelnen Features von Terraform besser zu verstehen, habe ich dir hier die wichtigsten Keywords zusammengefasst:

  • provider: Anbieter, dessen Ressourcen du mit Terraform anlegen kannst, z.B. AWS, Github oder auch Azure. Übersicht zu allen Providern: https://registry.terraform.io/browse/providers

  • resource: Eine Ressource deines Providers. Das kann z.B. ein Server, ein User, eine Datenbank usw. sein. Ressourcen werden in .tf Dateien definiert.

  • variables: Um Werte dynamisch oder auch mehrfach zu verwenden, kannst du Variablen einsetzen. Wertezuweisungen der Variablen werden in .tfvars Dateien implementiert.

  • outputs: Attribute einer Ressource, die man ausgeben oder für weitere Schritte verfügbar machen kann.

  • state: Der Stand deiner Infrastruktur. Der State dient zum Vergleich der aktuell vorhandenen Ressourcen und der neuen oder zu verändernden Ressourcen. Lokal gespeichert in der terraform.state Datei.

  • remote state: Ein Terraform State der zentral gespeichert wird, z.B. in einem AWS S3 Bucket oder auch in der Terraform Cloud. Das ist vor allem nützlich, wenn mehrere Entwickler*innen am Setup arbeiten.

  • Module: Terraform bietet von Haus aus die Möglichkeit wiederkehrende Ressoucen in Module auszulagern. Hashicorp bietet zusätzlich für viele Provider eigenen Modulbibliotheken.

  • Terraform Registry: Hier findest du für jeden Provider die verwendbaren Ressourcen im Bereich Documentation, z.B. für AWS.

  • Terraform CLI: Das Terraform Command Line Interface. Terraform steuerst du von deiner Konsole aus.

Mit den wichtigsten Keywords im Gepäck kann es auch schon losgehen mit dem Coden. 💪

Terraform in Action mit AWS

In Terraform durchläuft man mehrere Stationen. Wir gehen mit unserem Code Beispiel jeden durch.

Der Terraform Workflow

Code Beispiel

Wir bauen uns im Folgenden gemeinsam einen AWS S3 Bucket, der mit einer index.html zum Website-Hosting genutzt werden kann. Das ganze Code-Beispiel findest du auch in meinem Github Repo

Für unsere Webseite benötigen wir einen öffentlich erreichbaren S3 Bucket und fügen unsere index.html als S3 Object hinzu.

AWS Setup

Um den Namen des S3 Buckets nicht immer wieder eintippen zu müssen, verwenden wir die Variable s3_bucket_name (Zeile 12). Man kann die Variable mit var.s3_bucket_name (Zeile 20) referenzieren. Am Ende lassen wir uns die URL unserer Webseite über den Output s3_bucket_website_url ausgeben (Zeile 56).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# main.tf - define your resources

# set provider
# the starting point to connect to AWS
provider "aws" {
  profile = "test"      # the profile you configured via AWS CLI 
  region  = "us-east-1" # the region you want to deploy to 
}


# set variables
variable "s3_bucket_name" {
  description = "the s3 bucket name"
  type        = string
}

# set resources
# s3 bucket
resource "aws_s3_bucket" "website" {
  bucket = var.s3_bucket_name
  acl    = "public-read"
  policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid": "PublicReadGetObject",
          "Effect": "Allow",
          "Principal": "*",
          "Action": [
              "s3:GetObject"
          ],
          "Resource": [
              "arn:aws:s3:::${var.s3_bucket_name}/*"
          ]
      }
  ]
}
POLICY

  website {
    index_document = "index.html"
  }
}

# s3 object "index.html"
resource "aws_s3_bucket_object" "website" {
  bucket       = aws_s3_bucket.website.id
  key          = "index.html"          # how your file will be named in the S3 Bucket (we need an index.html)
  source       = "index.html"          # set the path to your "index.html" (here it lies in the same directory) 
  content_type = "text/html"           # use the respective MIME type for your object
  etag         = filemd5("index.html") # same path as in source 
}

# set output
output "s3_bucket_website_url" {
  value = aws_s3_bucket.website.website_endpoint
}
1
2
3
# variables.tfvars
# set the values for your variables
s3_bucket_name = "test" # add your unique bucket name

Terraform interpretiert die Ressourcen und deren Abhängigkeiten automatisch aus allen Dateien mit .tf Endung. Daher ist die Aufteilung deiner Ressourcen dir überlassen. Bei größeren Setups kann es Sinn machen eine logische Trennung durch mehrere Dateien aufzubauen, z.B. mit:

  • server.tf
  • website.tf
  • variables.tf
  • output.tf usw.

Wie deine Dateien heißen, spielt dabei keine Rolle. Der Kreativität sind keine Grenzen gesetzt.

Vorbereitung

💡 Für das Deployment zu AWS wird ein AWS Account vorausgesetzt. Außerdem muss der programatic access für deinen Nutzer freigeschalten sein.

Installation der AWS CLI:

wget "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
aws --version
# aws-cli/2.1.1 Python/3.7.4 Linux/4.14.133-113.105.amzn2.x86_64 botocore/2.0.0

👉 https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html

💡Für andere Anbieter wie Azure oder Google Cloud gibt es analoge Möglichkeiten, z.B. mit der Azure CLI oder der Google Cloud Shell

Einrichten deiner AWS Zugänge (Credentials):

Du kannst mit aws configure deine AWS credentials einrichten. Mehr dazu gibt es hier: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html.

Initialisierung und Planning

Dein erster Terraform Code ist geschrieben. Die AWS CLI eingerichtet. Wir können also starten. Juppieh! Starte von deinem Ordner aus, in dem sich deine .tf Datein befinden.

Initialisierung:

# initalisation of terraform and the chosen provider
terraform intit
# output
Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "aws" (hashicorp/aws) 3.25.0...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.aws: version = "~> 3.25"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Planning:

Mit terraform plan prüfst du, was dein Code ergeben wird. Wenn du schon einen State (local oder remote) hast, wird in dem Schritt gegen die vorhandenen Ressourcen gerpüft. Da Variablen verwenden werden, bindet man diese mit -var-file=variables.tfvars ein. Der Output des Plannings zeigt dir, wie viele Ressourcen hinzugefügt, aktualisiert und gelöscht werden.

# see a plan of what you want to create
terraform plan -var-file=variables.tfvars
# output
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_s3_bucket.website will be created
  + resource "aws_s3_bucket" "website" { ... }      
    ...
Plan: 2 to add, 0 to change, 0 to destroy.

Schauen wir uns den Output an:

  • + create (grün): die Ressource oder das Attribut zu einer Ressource wird neu hinzugefügt
  • ~ update in place (gelb): die Ressource wird automatisch aktualisiert
  • - delete (rot): die Ressource wird gelöscht
  • -/+ replace (rot): die Ressource wird gelöscht und neuangelegt

Für jeden geplanten Zustand wird dir auch angezeigt, welches Attribut für die Änderungen verantwortlich ist. update in place

Let’s Deploy!

Der Plan passt? Wenn du mit dem Output zufrieden bist, kannst du dein Deployment in die Cloud mit terraform apply starten. Es wird noch einmal ein Planning durchgeführt und nach deiner Zustimmung (yes) erfolgt der Apply. Mit dem flag -auto-approve wird der Apply sofort durchgeführt. Da wir über Terraform einen Output definiert haben, wird uns der Wert zu s3_bucket_website_url angezeigt.

terraform apply -var-file=variables.tfvars
# output
...
...
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

s3_bucket_website_url = ...

Let’s Delete!

Du möchtest dein Setup wieder offline nehmen? Mit terraform destroy kannst du alle definierten Ressourcen löschen:

terraform destroy -var-file=variables.tfvars

Mit dem flag -auto-approve kannst du den Job automatisch durchlaufen lassen.

Die einzelnen Schritte des Deployment bieteten noch weitere Einstellungsmöglichkeiten (z.B. ein no-color Output oder die Definition einzelner Variablen). Mehr dazu z.B. hier für plan, apply oder destroy

Da war noch was: Hilfsfunktionen

Terraform bietet neben dem Planning auch noch weitere tolle Features. Zwei möchte ich dir hier noch mitgeben:

Formatierung deines Codes:

terraform fmt formatiert deinen Code entsprechend des Terraform Code Styleguide

Validierung deines Codes:

terraform validate ist ein wichtiges Feature, um Syntaxfehler im Code vor dem Planning Step zu finden und zu beheben. Oft passierte es mir, dass ein Planning oder Apply nach langer Laufzeit abbrach, weil ich eine Klammer vergessen oder eine Referenz falsch geschrieben habe. Mach es dir einfacher und bau die Validierung in deine Terraform-Routine ein.

Terraform Routine:

Ich empfehle dir folgende Reihenfolge beim Ausführend von Terraform

# terraform command recomondation
terraform fmt
terraform init
terraform validate
terraform plan -var-file=variables.tfvars
terraform apply -var-file=variables.tf.vars

Herzlichen Glückwunsch! Du bist nun Terraform approved. Let&rsquo;s code some Terraform

Vorteile und Herausforderungen

Terraform ist toll. Aber jede Medaille hat zwei Seiten, wie man so schön sagt. Ich möchte dir abschließend noch

Vorteile von Terraform sind:

  • leichter Einstieg und steile Lernkurve: HCL ist leicht verständlich und die Dokumentation von Terraform ist hervorragend, daher findet man als Entwickler*in schnell in das Thema ein.

  • viele Provider: Terraform bietet durch sein breites Angebot an Providern ein breites Spektrum darüber, was eingebaut werden kann. Somit sind nicht nur die großen Player dabei, sondern auch kleinere Anbieter. Außerdem kann man selbst Provider über die sogenannten Private Registries erweitern.

  • Multi-Cloud implementierbar: Mit Terraform kann man gleichzeitig mehrere Cloud-Hoster implementieren.

  • Community driven & up-to-date: Terraform ist open source und wird regelmäßig aktualisiert. Stand heute arbeiten die Entwickler*innen an v15. Auf Github sieht man die aktuellen Enticklungen. Viele Provider arbeiten mittlerweile auch aktiv mit HashiCorp/Terraform zusammen, sodass die Implementierung neuer Ressourcen mittlerweile deutlich schneller geht als noch vor 3-4 Jahren.

Herausforderungen mit Terraform:

  • conditionals: Im Gegensatz zu einer bekannten Programmiersprache ist es in Terraform nicht so einfach Bedingungen abzubilden. Vor allem komplexere Bedingungen sind so manches Mal nicht einfach umzusetzen. Mit jedem Release tut sich aber immer mal wieder etwas in der Richtung. Mit Einführung von v12.x wurde z.B. Bedingungen über dynamics und foreach eingebaut.

  • Multi-Cloud: So toll Multi-Cloud sich anhört, so aufwendig ist die Implementation. Terraform ist Provider-spezifisch. Das bedeutet, es sichtet sich nach den Bezeichnern der einzelnen Provider. Somit ist ein Umstieg z.B. von AWS auf Azure in der Theorie bestimmt einfach, erfordert je nach Größe des Setups aber auch viel Fleißarbeit, da die einzelnen Ressourcen unterschiedlich heißen und somit auch - verständlicherweise - unterschiedliche Konfigurationsmöglichkeiten haben. Hier ist die Erfahrung des Entwicklers gefragt.

  • Fast Delivery: Terraform liefert im Moment sehr schnell. Somit heißt es dranbleiben. Ich sehe das für mich als Herausforderung immer die aktuellen Verbesserung im Blick zu haben, aber auch als Zeichen, dass es ein gutes Tool ist, was sich stetig weiterentwickelt. Einen Überblick über die aktuellen Releases findet sich hier: https://github.com/hashicorp/terraform/releases und im Changelog

Weiterentwicklung und Alternativen

Seine Infrastruktur zu coden macht Spaß. Ich hoffe, das konnte ich dir bereits mitgeben :releaxed: Und es macht immer mehr Entwickler*innen Spaß, denn es tut sich viel im Bereich Infrastructure as Code.

Ich möchte dir noch einen Ausblick geben, was es sonst noch so alles gibt. Du wirst dazu auch bald hier auf diesem Blog Beiträge dazu finden.

AWS Cloud Developement Kit

Auf der Reinvent 2018 kündigte AWS das Cloud Development Kit (AWS CDK). Im Juli 2019 wurde mit TypeScript und Python die ersten generell verfügbare Version bereitgestellt. Seither wurde es stetig erweitert und seit 2020 gibt es auch Terraform CDK. Es bleibt also spannend. ✨

Pulumi

Ähnlich wie das Cloud Development Kit baut man bei Pulumi die Infrastruktur mit einer Programmiersprache, z.B. mit Python. Es gibt neben den gängisten Cloud Anbietern auch weitere Provider wie Kubernetes oder auch MySQL. Ich plane im Moment an einer Demo für einen weiteren Blogbeitrag dazu. Sei also gespannt ☺️

Andere Anbieter

AWS bietet mit CloudFormation einen internen Dienst zum Skripting der Infrastrukur mit JSON oder YAML. Azure setzt soweit ich das aus den Docs entnehmen kann eher auf Terraform. Google Cloud bietet mit dem Cloud Deployment Manager an. Zu den beiden letzteren kann ich im Moment eher weniger sagen, da ich sie bisher nicht aktiv im Einsatz hatte.

Fazit

Du siehst, Infrastructure as Code ist ein sinnvoller Ansatz, um deine Projekte nachhaltig aufzusetzen. Mit Terraform hast du ein starkes Tool zu Hand, mit dem du dein Setup planen und deployen kannst. Am Ende entscheidet aber dein Use Case und deine Präferenzen - vielleicht fällt es dir leichter mit Python oder Typescript ein Setup zu bauen. Was auch immer du wählst: IaC ist immer eine gute Wahl, um dein Infrastruktur-Setup für dich und dein Team nachvollziehbarer und automatisierbar zu gestalten.

Du willst mehr über Terraform lernen? Schaut dir mal meine Tutorial-Sammlung dazu an: https://wolkencode.de/series/terraform/. Ich füge regelmäßig neue Themen hinzu. 👩‍💻


Wie hat dir dieser Beitrag gefallen? Lass es mich doch gerne mit einem Feedback, Like oder Share auf Twitter wissen.

Happy Coding und bis zum nächsten Beitrag!

Nora See ya!