Start / Seminare / Terraform und OpenTofu in der Praxis
Modul
Ressourcen modellieren und Änderungen steuern
Modul 4 von 14 aus dem Seminar Terraform und OpenTofu in der Praxis
6 Kapitel in diesem Modul-Video · Laufzeit
Für Teams
Die Videos zeigen, wie es geht. Die Schulung sorgt dafür, dass Ihr Team es danach tut.
Ein Video kann niemanden fragen, warum es ausgerechnet in Ihrem Repository nicht funktioniert. Es kann kein Team auf eine gemeinsame Konvention bringen. Und es setzt sich niemand freiwillig drei Tage hin. In der Schulung sind am Ende alle auf demselben Stand, gearbeitet wurde am eigenen Code, und die offenen Fragen sind entschieden — in ein paar Tagen statt irgendwann nebenbei.
Vorgespräch am Telefon · Programm nach Maß · ab 1 Tag (8 Unterrichtseinheiten) · Teilnahmezertifikat
Transkript
Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.
Ressourcen modellieren und Änderungen steuern
0:00 Ein Plan, der drei Container ersetzen will, obwohl Sie nur einen Standort gestrichen haben, ist kein Fehler von Terraform. Er ist ein Fehler im Modell. Darum geht es in diesem Modul: Wie beschreibt man Ressourcen so, dass Änderungen klein und vorhersehbar bleiben? Wir sehen uns an, wie Terraform die Reihenfolge bestimmt, wie man viele gleichartige Objekte anlegt, ohne dass sie sich gegenseitig mitreißen, und wie man wertvolle Daten vor dem versehentlichen Löschen schützt.
0:26 Dazu kommen Prüfungen, die Annahmen sichtbar machen, und das Handwerkszeug für den Ausnahmefall. Unser Beispiel bleibt Saatplan, die interne Anwendung der Gärtnerei Lindenhof, die jetzt an mehreren Betriebsstandorten läuft.
Ressourcen modellieren und Änderungen steuern
0:39 Der zweite Tag beginnt mit einer Haltung, die auf dieser Folie in einem Satz steht: Ein guter Plan ersetzt nur, was sich wirklich ändert. Am ersten Tag ging es darum, eine Konfiguration sauber zu schreiben und ihre Eingaben abzusichern. Jetzt geht es um ihr Verhalten über die Zeit, denn Infrastruktur wird nicht einmal angelegt und dann vergessen. Sie wird ständig verändert, erweitert und umgebaut.
1:02 Wer dabei jedes Mal mit klopfendem Herzen auf den Plan schaut, hat ein Modellierungsproblem. In den folgenden Modulen dieses Tages kommen dann Module und der gemeinsame State hinzu.
Abhängigkeitsgraph und depends_on
1:13 Im letzten Modul haben wir gesehen, dass Verweise ganz nebenbei die Reihenfolge festlegen. Es gibt aber auch einen ausdrücklichen Weg, nämlich depends on. Die Frage ist, wann man ihn braucht und was er kostet. Die Saatplan-API braucht die Datenbank. Man könnte das ausdrücklich hinschreiben, mit depends on. Eleganter ist der Weg, den Sie hier sehen: Die API bekommt den Namen des Datenbank-Containers als Umgebungsvariable.
1:39 Damit ist die Abhängigkeit hergestellt, und zwar mit Begründung, denn der Verweis transportiert einen Wert, den die API wirklich braucht. Achten Sie aber auf den Hinweis unten auf der Folie, er ist wichtig. Reihenfolge ist nicht Bereitschaft. Terraform wartet, bis der Datenbank-Container angelegt ist, aber nicht, bis die Datenbank darin auch antwortet. Das ist wie beim Bäcker, der den Ofen einschaltet.
2:04 Eingeschaltet heißt noch lange nicht heiß. depends on wirkt wie eine harmlose Absicherung, ist es aber nicht. Weil Terraform nicht weiß, welches Attribut genau gemeint ist, plant es vorsichtiger. Mehr Werte bleiben bis zum apply unbekannt, und im ungünstigen Fall werden mehr Objekte ersetzt als nötig. Bei Data Sources ist der Effekt besonders spürbar: Sie werden dann erst beim apply gelesen, und der Plan verliert an Aussagekraft.
2:30 Berechtigt ist depends on dort, wo es keinen Verweis gibt, der die Beziehung ausdrückt. In der Cloud ist das typischerweise eine Berechtigung, die stehen muss, bevor ein Server startet. Und eine gute Gewohnheit: Wer depends on setzt, schreibt einen Kommentar dazu, warum kein Verweis genügt hat.
count und for_each
2:48 Saatplan soll jetzt an mehreren Betriebsstandorten laufen, mit je einem eigenen API-Container. Dafür gibt es zwei Werkzeuge, count und for each. Beide erzeugen viele Instanzen aus einem Block. Der Unterschied zeigt sich erst, wenn sich die Liste ändert, dann aber deutlich. Der Block beschreibt einen API-Container, und for each macht daraus einen je Standort. Der Standortname taucht im Containernamen und in einer Umgebungsvariablen auf.
3:16 Entscheidend ist die letzte Zeile, die Adresse. Jede Instanz trägt ihren Standort als Schlüssel im Namen, also etwa api mit dem Schlüssel Sonnhalde. Diese Adresse ist die Identität des Objekts im State. Solange der Schlüssel bleibt, bleibt auch das Objekt. Eine Voraussetzung hat for each allerdings: Es braucht eine Map oder ein Set aus Zeichenketten, und die Schlüssel müssen schon beim Planen bekannt sein.
3:41 Die Variable ist eine Liste, deshalb wandelt toset sie vorher in ein Set um. Hier sehen Sie, warum die Adresse so wichtig ist. Nehmen wir an, der Standort Erlenbruch schließt. Mit count sind die Instanzen durchnummeriert. Fällt das erste Element weg, rücken alle anderen eine Nummer nach. Für Terraform sieht das aus, als hätten sich die Namen der übrigen Container geändert, und weil Docker den Namen eines Containers nicht nachträglich ändern kann, werden sie ersetzt.
4:08 Zwei Ersetzungen und ein Löschen für eine einzige Schließung. Mit for each verschwindet einfach der eine Schlüssel, Sonnhalde und Mühlwiese bleiben unberührt. Das ist wie der Unterschied zwischen einer Warteschlange mit Nummern und einem Garderobenhaken mit Namensschild. Wer geht, nimmt nur seinen eigenen Mantel mit. Manchmal wiederholt sich nicht die ganze Ressource, sondern nur ein Block darin, etwa die Port-Freigaben eines Containers. Dafür gibt es den Dynamic Block.
4:36 Er erzeugt für jeden Eintrag einer Sammlung einen verschachtelten Block mit den passenden Werten für internen und externen Port. Das Prinzip ist dasselbe wie bei for each, nur eine Ebene tiefer. Doch Vorsicht vor Übermut. Die Dokumentation rät ausdrücklich, Dynamic Blocks sparsam einzusetzen, vor allem dort, wo ein wiederverwendbares Modul Details vor seinen Nutzern verbergen soll.
4:57 In einer normalen Konfiguration sind ausgeschriebene Blöcke oft lesbarer, auch wenn sie ein paar Zeilen mehr kosten. Mit Modulen beschäftigen wir uns im nächsten Modul.
Lifecycle-Regeln
5:08 Terraform hat feste Vorstellungen davon, wie es Änderungen umsetzt. Mit den Lifecycle-Regeln können Sie dieses Verhalten beeinflussen. Es sind vier Schalter, jeder senkt ein bestimmtes Risiko, und jeder hat eine Kehrseite, die man kennen muss. Der Datenbank-Container von Saatplan ist das wertvollste Stück der ganzen Konfiguration, denn hier liegen die Daten. Zwei Regeln schützen ihn.
5:31 prevent destroy sorgt dafür, dass Terraform jeden Plan ablehnt, der diesen Container löschen würde. ignore changes auf die Labels erlaubt, dass andere Werkzeuge dort Markierungen setzen, ohne dass Terraform sie bei jedem Lauf wieder zurückdreht. Eine Besonderheit steht unten auf der Folie. Die Werte im lifecycle-Block müssen fest hingeschrieben sein, Variablen oder Ausdrücke sind nicht erlaubt.
5:54 Der Grund ist technisch: Terraform wertet diesen Block vor allem anderen aus. Sie können den Schutz also nicht je Umgebung per Variable ein- und ausschalten. Lesen Sie diese Tabelle von rechts nach links, also zuerst die Kehrseite. Denn die Regeln wirken alle verlockend, ihre Grenzen zeigen sich erst im Betrieb. create before destroy vermeidet einen Ausfall beim Ersetzen, verlangt aber, dass alt und neu kurz gleichzeitig existieren dürfen.
6:21 prevent destroy schützt nur, solange der Block in der Konfiguration steht. Wer die ganze Ressource entfernt, entfernt auch den Schutz. ignore changes hilft gegen Dauerdifferenzen, wirkt aber nur bei Updates. Und replace triggered by sorgt dafür, dass ein Objekt erneuert wird, wenn sich etwas anderes ändert, nimmt dafür aber nur Verweise auf Ressourcen.
6:42 Für Variablen braucht es den Umweg über terraform data. Diese vier Fallen folgen direkt aus der Tabelle. create before destroy auf dem Datenbank-Container scheitert ganz praktisch, weil Docker einen Containernamen nur einmal vergibt. Der neue kann also nicht neben dem alten stehen. ignore changes auf alles friert eine Ressource komplett ein, und dann wundert man sich, warum eine gewollte Änderung einfach nicht ankommt.
7:06 prevent destroy überall zu setzen ist ein Reflex aus Vorsicht, blockiert aber auch jeden geplanten Umbau. Es gehört an Daten, die nicht neu entstehen können, nicht an jeden Container. Und replace triggered by auf ein Attribut, das sich ständig ändert, ersetzt den Container bei jedem einzelnen Lauf.
Preconditions, Postconditions und Checks
7:24 Im letzten Modul haben wir Eingaben validiert. Jetzt gehen wir einen Schritt weiter und prüfen Annahmen und Zusicherungen rund um die Ressourcen selbst. Dafür gibt es drei Mittel, und sie unterscheiden sich vor allem darin, was im Fehlerfall passiert. Die Logik dieser Tabelle steckt in der rechten Spalte. Eine precondition ist wie die Kontrolle vor dem Abflug: Stimmt etwas nicht, wird die Änderung am Objekt gar nicht erst begonnen.
7:50 Eine postcondition prüft nach dem Anlegen oder Lesen, ob das Ergebnis den Erwartungen entspricht. Schlägt sie fehl, stoppt sie die Folgeschritte, macht aber nichts rückgängig. Das Objekt existiert dann bereits. Und ein check meldet nur. Er läuft am Ende von plan und apply, gibt eine Warnung aus und lässt den Lauf weitergehen.
8:09 Dazu kommt, wie unten vermerkt, die validation aus Modul 3, die noch vor dem Plan greift. Vier Zeitpunkte also, und für jeden eine passende Frage. Zwei Beispiele aus Saatplan. Die precondition am API-Container formuliert eine Annahme: Web und API dürfen nicht denselben Port haben. Ist das verletzt, unterbleibt die Änderung, bevor sich zwei Container um denselben Port streiten.
8:32 Die postcondition an der Datenbank formuliert eine Zusicherung: Nach dem Anlegen darf dieser Container keinen Port nach außen veröffentlichen. Die Datenbank soll nur im internen Netz erreichbar sein. Interessant ist das kleine Wort self. Es steht in einer postcondition für das Objekt selbst, so wie es tatsächlich entstanden ist.
8:52 Damit prüfen Sie nicht nur, was Sie hingeschrieben haben, sondern was wirklich angekommen ist. Der check-Block ist das sanfteste der drei Mittel, und genau das ist seine Stärke. Hier fragt er per HTTP bei der Weboberfläche von Saatplan an und erwartet den Statuscode 200. Die Data Source, die diese Anfrage stellt, existiert nur innerhalb des check-Blocks und ist von außen nicht sichtbar.
9:15 Fällt die Prüfung durch, gibt Terraform eine Warnung aus, aber es blockiert nichts. Das passt zu Fragen, auf die eine Konfiguration keinen Einfluss hat, etwa ob ein Dienst gerade antwortet. Ein Rauchmelder schaltet ja auch nicht den Herd ab, er macht nur laut darauf aufmerksam, dass etwas nicht stimmt.
Gezielt eingreifen
9:34 Manchmal passt die Konfiguration, aber die Welt nicht. Ein Container hängt, ein Teil der Infrastruktur muss dringend allein repariert werden. Dafür gibt es Werkzeuge, und die Tagline sagt schon, wie man sie verstehen sollte: als Handwerkszeug für den Ausnahmefall, nicht für den Alltag. Drei Eingriffe, drei Situationen. Im ersten Fall hängt der API-Container am Standort Sonnhalde. Die Konfiguration ist richtig, das Objekt aber kaputt.
10:00 Mit der Option replace erzwingen Sie, dass genau dieser Container neu erzeugt wird. Der Plan wird dabei gespeichert und anschließend genau so angewendet, damit nichts anderes dazwischenrutscht. Im zweiten Fall grenzen Sie den Plan mit target auf ein einzelnes Objekt ein, hier das Netz. Das ist ausdrücklich als Notfallwerkzeug markiert.
10:21 Den dritten Fall gibt es nur in OpenTofu: Mit exclude nehmen Sie eine Adresse aus und planen alles andere. Hier zeigt sich einer der kleinen Unterschiede zwischen den beiden Werkzeugen. Diese Tabelle sortiert die Eingriffe nach ihrem Preis. replace kostet praktisch nichts, denn der Plan zeigt den Austausch offen, und alles andere wird wie gewohnt geprüft.
10:43 Bei target und exclude ist das anders. Was ausgeklammert ist, bleibt ungeplant, und eine Abweichung zwischen Konfiguration und Wirklichkeit fällt dort nicht auf. Wer das zur Gewohnheit macht, verliert den Überblick. Ganz unten stehen die Provisioner, der letzte Ausweg. Terraform kann ihr Verhalten nicht im Plan abbilden, sie sind also ein blinder Fleck.
11:04 Meist gibt es bessere Wege: Dateien per upload-Block, Software direkt ins Image, und die Bereitschaft eines Containers über Healthcheck und Warten.
Übung
11:13 Zeit, das Ganze selbst zu erleben. Ein Standort schließt, zwei laufen weiter. Diese Übung macht den Unterschied zwischen count und for each greifbar, und zwar direkt im Plan. In dieser Übung geht es um eine Fähigkeit, die man im Alltag ständig braucht: einen Plan lesen und darin einen Modellierungsfehler erkennen, bevor er Schaden anrichtet.
11:34 Und dann das Modell so wählen, dass eine Änderung nur das betrifft, was wirklich betroffen ist. Woran erkennen Sie den Erfolg? Wenn Sie den Standort Erlenbruch streichen, zeigt der Plan genau ein Löschen für diesen einen Container und keine Ersetzung für Sonnhalde oder Mühlwiese. Wer schneller fertig ist, kann die Standorte als Map führen, mit eigenem Port je Standort, und die Port-Freigaben über einen Dynamic Block erzeugen.
11:58 Der Weg führt bewusst über den Fehler. Sie legen die drei Standorte zuerst mit count an und streichen dann Erlenbruch. Der Plan, den Sie dann sehen, ist das eigentliche Lernmaterial, denn darin stehen die Ersetzungen, die niemand wollte. Danach nehmen Sie die Streichung zurück und stellen auf for each um. Damit die vorhandenen Container dabei nicht neu gebaut werden, kommen moved-Blöcke dazu.
12:20 Der vierte Schritt ist die Probe: Ohne inhaltliche Änderung darf der Plan keinen Container ersetzen. Erst dann streichen Sie Erlenbruch noch einmal und sehen den Unterschied. Zum Schluss das Werkzeug, das die Umstellung schmerzfrei macht. Ein moved-Block sagt Terraform: Das Objekt, das bisher unter dieser Adresse lag, liegt jetzt unter jener.
12:41 Statt einen Container zu löschen und neu anzulegen, wird er im State einfach umbenannt. Hier ziehen die nummerierten Instanzen auf ihre Standortnamen um, ein Block je Index, für Mühlwiese folgt ein dritter. Das ist ein bisschen wie ein Nachsendeauftrag bei der Post: Die Wohnung bleibt dieselbe, nur die Adresse ändert sich.
13:00 Vertieft wird das Thema in Modul 9, wenn wir bestehende Infrastruktur übernehmen und refaktorieren. Als Nächstes geht es um Module, die Bausteine für wiederverwendbare Konfigurationen.
Dieses Modul als Schulung für Ihr Team
Das Video zeigt den Stoff. In der Schulung arbeitet Ihr Team damit — an Ihrem eigenen Code, mit Übungen und mit den Fragen, die ein Video nicht beantwortet. Sie wählen die Module aus Terraform und OpenTofu in der Praxis, wir bauen daraus ein Programm.
5 Tage·ab 900 EUR netto pro Tag (bis 3 Teilnehmende) ·Termin nach Vereinbarung