adesso Blog

Eine Vorlage für komplexe Terraform-Projekte

Das Schreiben von Terraform-Code ist einfach. Der Umgang damit kann jedoch knifflig sein.

So würde ich meine Erfahrungen mit Terraform zusammenfassen, nachdem ich es drei Jahre lang beruflich genutzt habe. Ehrlich gesagt, kann das Schreiben von gutem Terraform-Code auch schwierig sein. Die größere Herausforderung besteht meiner Meinung nach jedoch darin, den Code so zu organisieren, dass er sauber, zugänglich und wartbar ist.

Dies gilt insbesondere für sogenannte Enterprise-Projekte. Dabei handelt es sich um große Projekte, die mehrere Konten, Regionen, Dienste und sogar Clouds umfassen. Solche Projekte werden schnell umfangreich und komplex. Im Enterprise-Kontext ist es wichtig, sorgfältig über die Struktur Ihres Terraform-Projekts nachzudenken.


Infrastructure-as-code-Projekte können schnell zu einer komplexen Verwaltung werden, Quelle: Unsplash.com

In diesem Blog-Beitrag möchte ich einige Erfahrungen beschreiben, die ich in mehreren Enterprise-Projekten gesammelt habe. Im Folgenden stelle ich eine Terraform-Projektstruktur vor, die sich als Ausgangspunkt für die Organisation von Code und Konfigurationsdateien bewährt hat. Damit möchte ich Entwicklern eine Orientierung bieten, die ihren Terraform-Code professionalisieren wollen, insbesondere denjenigen, die Infrastructure as Code gerade erst entdecken.

Eine Strukturierungsmöglichkeit für Terraform-Projekte

Module

Der erste Schritt zur Entwicklung sauberer, zugänglicher und wartbarer Terraform-Projekte ist die Verwendung von Modulen.

Module sind wiederverwendbare Konfigurationen von Terraform-Code. Diese Module bilden Einheiten der Infrastruktur, wie Server, Datenbanken oder verwaltete Dienste. Um sie bestmöglich nutzen zu können, sollten die Module so allgemein sein wie möglich. Module entsprechen oft einem bestimmten Dienst wie GCP BigQuery oder Azure SQL Server.

In unserem Beispiel-Repository gibt es einen Ordner namens modules, der nach Cloud-Anbietern unterteilt ist - in unserem Fall azure und gcp. In diesen Unterordnern findet ihr die generischen Terraform-Module für jeden Provider.


Ein Baumdiagramm des Modulordners

Jedes Modul besteht aus genau drei Dateien: main.tf, variables.tf und outputs.tf. Ich empfehle, bei dieser Konvention zu bleiben, auch wenn euer Modul zum Beispiel keine Outputs hat. In diesem Fall fügt einfach eine leere Datei ein.

Module sind deshalb so wichtig, weil sie dabei helfen, unsere Infrastrukturkonfiguration in standardisierte Bausteine zu unterteilen, die wir über verschiedene Projekte oder Implementierungen hinweg wiederverwenden können. Darüber hinaus können sie den komplexen Aufbau von Infrastrukturen enorm vereinfachen. Unabhängig davon, ob ihr Module für euer eigenes Team oder für andere erstellt, könnt ihr sie genau auf die Bedürfnisse der Modulnutzenden abstimmen.

Im Grunde möchte ich damit sagen: Wenn ihr beim Schreiben von Terraform-Code einen konsistenten modularen Ansatz verfolgt, ist es leichter, saubere Terraform-Projekte zu erstellen, da ihr Code-Duplikation vermeidet und Code über verschiedene Anforderungen abstrahiert.

YAML-Dateien

Ein weiterer Schritt zum Aufbau sauberer, zugänglicher und wartbarer Terraform-Projekte ist die Modulkonfiguration.

Es gibt viele Möglichkeiten, Terraform-Module zu konfigurieren. Ihr könnt die Konfigurationswerte direkt im Terraform-Code codieren oder sie in tfvar-, YAML- oder JSON-Dateien organisieren. Ich empfehle YAML-Dateien, weil sie drei große Vorteile bieten:

  • Sie sind leicht zu lesen, sodass auch Teammitglieder, die mit Terraform nicht vertraut sind, sie schnell verstehen und aktualisieren können.
  • Sie bündeln alle relevanten Konfigurationen an einem einzigen, festen Ort. Das bedeutet, dass ihr nicht im Terraform-Code nach Informationen suchen müsst. Außerdem könnt ihr, anders als bei JSON-Dateien, Kommentare und Anweisungen einfügen.
  • Terraform erkennt alle Änderungen, die ihr an den Dateien vornehmt. Ihr möchtet einen weiteren Datensatz, User oder eine weitere Bezeichnung hinzufügen? Dazu müsst ihr nur einen weiteren Block zu Ihrer YAML hinzufügen. Jeder kann es und es geht schnell. Terraform übernimmt die Änderungen, ohne dass der zugrunde liegende Code bearbeitet werden muss.

Wenn ihr einen Blick in den Ordner config werft, werdet ihr feststellen, dass er nach Cloud-Anbieter und Modul unterteilt ist. Genau wie der Ordner modules! Jedes generische Terraform-Modul hat also einen entsprechenden Satz von Konfigurationsdateien für verschiedene Clouds und Umgebungen. Das Terraform-Modul cloud-storage hat beispielsweise eine entsprechende Konfigurationsdatei cloud-storage im Konfigurationsordner gcp. Dies ist darauf zurückzuführen, dass Module die zentrale Organisationseinheit sind.


Ein Baumdiagramm der Module und des Konfigurationsordners

So könnte eine typische YAML-Datei aussehen. Dieser Rollout umfasst zwei Ressourcengruppen in unserer Azure-Produktionsumgebung:


Der Inhalt einer typischen YAML-Konfigurationsdatei

Durch die Verwendung von YAML-Dateien anstelle von tfvar-Dateien oder hartkodierten Werten tut man sich selbst und anderen einen großen Gefallen, da man Terraform-Projekte erstellt, die sowohl für technische als auch für nicht-technische Mitarbeitende leichter zugänglich sind.

Terragrunt

Schauen wir uns den letzten Schritt zur Erstellung sauberer, zugänglicher und wartbarer Terraform-Projekte an: Terragrunt. Laut Website ist Terragrunt ein Wrapper, der zusätzliche Tools bereitstellt, um eine sich weniger wiederholende Konfiguration der Infrastruktur zu ermöglichen (DRY), mit mehreren Terraform-Modulen zu arbeiten und den Remote-Status zu verwalten.

In unserem Fall hilft Terragrunt bei der Erstellung schlankerer Terraform-Projekte, da die Anzahl der zu verwaltenden Dateien drastisch reduziert wird. Dadurch wird nicht nur die Unübersichtlichkeit reduziert, sondern auch das Risiko von Konfigurationsabweichungen, wenn nicht alle Terraform-Dateien auf konsistente Weise aktualisiert werden. Terragrunt ist kostenlos, quelloffen und gut dokumentiert.

Das Tool bietet unter anderem folgende Vorteile:

  • Dynamische Generierung einer Backend-Konfiguration
  • Dynamische Generierung einer Anbieterkonfiguration
  • Automatische Vervollständigung der Terraform CLI-Argumente
  • Einmalige Definition eines Moduls und vielseitige Wiederverwendbarkeit ohne Duplizierung von Code

Wenn ihr drei Buckets und eine VM verwaltet, könnt ihr auf Terragrunt verzichten. Aber wenn ihr nach und nach immer mehr Module (Cloud-Dienste) zu eurem Stack hinzufügt, kann sich Terragrunt durchaus lohnen. Es zahlt sich vor allem dann aus, wenn euer Terraform-Code mehrere Umgebungen, Regionen oder Clouds umfasst.

Es gibt drei Arten von Terragrunt-Dateien, die ich in dieser Projektstruktur verwende. Mit „Arten“ meine ich, dass diese Terragrunt-Dateien auf verschiedenen Ebenen der Ordnerhierarchie liegen und somit unterschiedliche Zwecke erfüllen. Zusammen ersparen sie euch eine Menge doppelten Code und helfen, die Konfiguration, Bereitstellung und Verwaltung eurer Infrastruktur zu optimieren.


Der Inhalt der Datei terragrunt.hcl auf Modulebene

Die Terragrunt-Stammdatei

Am wichtigsten ist die Datei terragrunt.hcl im Cloud-Provider-Ordner oder die Terragrunt-Stammdatei. Darin könnt ihr die Terraform-Anbieter, die ihr verwenden möchtet, deren Versionen und euer Remote-Backend zentral festlegen. Jedes Mal, wenn ihr ein Modul bereitstellt, erstellt Terragrunt dynamisch die entsprechenden Terraform-Dateien und legt sie in dem Verzeichnis ab, in dem ihr den Code ausführt. Das erspart euch die lästige und fehleranfällige Aufgabe, diese Standarddateien immer wieder neu zu erstellen.

Die Datei terragrunt.hcl ermöglicht auch das Setzen globaler Variablen, die für alle Umgebungen und Module gültig sind - beispielsweise das Tag managed_by = terraform oder location = westeurope. Das ist ideal, um Variablen einmal zu definieren und sie dann überall zu verwenden.

Die Terragrunt env-Datei

Neben der Stammdatei terragrunt.hcl gibt es eine Datei env.hcl in jedem Umgebungsordner - dev, tst und prd. Hier könnt ihr Variablen setzen, die nur auf der Umgebungsebene gelten und von allen Modulen darin gemeinsam genutzt werden. Sie eignen sich hervorragend für die Festlegung von Projekt- oder Abonnement-IDs, Namenspräfixen oder umgebungsspezifischen Einstellungen wie Computing- und Netzwerkoptionen.

Die Terragrunt-Moduldatei

Schließlich gibt es die Datei terragrunt.hcl innerhalb der einzelnen Module. Diese Datei verbindet die generischen Terraform-Module mit ihren jeweiligen Konfigurationsdateien, um eine reale Instanziierung des Moduls in Ihrer Cloud-Umgebung zu erstellen. Hier ist es hilfreich, sich die Terraform-Module als aufrufbare Funktionen mit unterschiedlichen Argumenten und die Konfigurationsdateien als entsprechende Argumente vorzustellen. Jedes terragrunt.hcl-Modul in dieser Analogie ist der Ort, an dem die Funktion (das generische Modul) mit den Argumentwerten (Konfigurationsdateien) aufgerufen wird, um eine Ausgabe (Infrastruktur) zu erzeugen.


Eine Analogie der Terraform-Module als Funktionen

Ein weiteres herausragendes Merkmal der terragrunt.hcl-Dateien ist, dass sie es ermöglichen, Abhängigkeiten zwischen Modulen zu deklarieren. Dadurch werden nicht nur die Beziehungen zwischen den Modulen transparent – es erleichtert auch die Verbindung von Modulen untereinander.

Terragrunt ist ein leistungsfähiges Werkzeug, mit dem ihr Terraform-Projekte erstellen könnt, die viel einfacher zu warten sind. Das gilt insbesondere, wenn euer Projekt größer und komplexer wird. Die Arbeit mit Terragrunt mag anfangs ungewohnt sein, aber ihr werdet feststellen, dass es euer Infrastructure-as-Code-Projekte in jeder Hinsicht besser und einfacher macht.

Fazit

Mit zunehmendem Umfang werden Terraform-Projekte immer chaotischer. Das liegt daran, dass es immer schwieriger wird, den gesamten Code und seine Konfiguration zu verwalten. Um den Überblick über eure Infrastruktur zu behalten und sie effektiv, flexibel und einheitlich zu verwalten, braucht ihr eine zuverlässige Projektstruktur. Je nach Größe und Komplexität eures Projekts ist dies keine triviale Aufgabe, da ihr womöglich Entscheidungen treffen und Kompromisse eingehen müsst, die sich später rächen können.

Die Projektstruktur, die ich in diesem Artikel skizziert habe, hat mir und meinen Kolleginnen und Kollegen bei der Verwaltung dieser Art von Projekten – häufig Enterprise-Projekte – gute Dienste geleistet. Ich hoffe, ihr könnt aus meinem Blog-Beitrag etwas Hilfreiches mitnehmen und es für euch nutzen, denn jede Projektkonfiguration ist auf ihre Weise einzigartig. Schaut euch auch das Beispiel-Repository unter https://github.com/tilgner/enterprise-terraform an und teilt mir eure Erfahrungen und Vorschläge mit mir! Ihr erreicht mich per E-Mail: manuel.tilgner@adesso.de

Bild Manuel Tilgner

Autor Manuel Tilgner

Manuel ist Cloud Engineer im Bereich Data & Analytics bei adesso. Sein Fokus liegt auf Infrastruktur-Automatisierung sowie Netzwerk- und Sicherheitsthemen. Aktuell arbeitet er mit seinem Team an einem Toolset, mit dem Unternehmen im Handumdrehen Data Analytics Plattformen in der Cloud aufbauen können. Neben der Arbeit interessiert er sich für Rust/Go und Virtualisierungstechnologien.

Diese Seite speichern. Diese Seite entfernen.