· Sascha Enke
Terraform und Ansible: Wer konfiguriert was?
Wer Infrastructure as Code einführt, landet schnell bei zwei Werkzeugen: Terraform und Ansible. Beide beschreiben Infrastruktur in Textdateien, beide liegen im Git, und beide können vieles, was das andere auch kann. Genau daraus entsteht Streit im Code: Terraform setzt eine Einstellung zurück, die Ansible gerade geändert hat. Hier beschreiben wir, wie wir die Aufgaben trennen und warum.
Die Faustregel
Terraform beschreibt, was existiert. Eine virtuelle Maschine mit drei Kernen, einer 250-GB-Festplatte und einer festen IP-Adresse. Ein DNS-Eintrag. Ein Server bei einem Hoster. Terraform vergleicht diesen Soll-Zustand mit dem, was tatsächlich da ist, und legt an, ändert oder löscht, bis beides übereinstimmt.
Ansible beschreibt, wie es eingerichtet ist. Welche Pakete installiert sind, wie SSH konfiguriert ist, welche Dienste laufen, welche Benutzer Zugang haben. Ansible verbindet sich per SSH mit dem System und bringt es in den beschriebenen Zustand, ohne dass dort vorher ein Agent installiert sein muss.
Eine einfache Prüffrage hilft bei Grenzfällen: Lässt sich das Ding löschen und neu anlegen, ohne dass etwas verloren geht? Dann gehört es zu Terraform. Wird es im laufenden System gepflegt und verändert? Dann gehört es zu Ansible.
Wer bei uns was macht
| Aufgabe | Werkzeug |
|---|---|
| VM auf dem Proxmox-Cluster anlegen (CPU, RAM, Festplatte, Netz, IP) | Terraform |
| Server bei einem Hoster anlegen | Terraform |
| DNS-Einträge bei Cloudflare | Terraform |
| Cloud-Image für neue VMs bereitstellen | Terraform |
| Pakete, Benutzer, SSH, sudo | Ansible |
| Dienste und Container-Stacks einrichten | Ansible |
| Agents für Monitoring und Sicherheitsüberwachung ausrollen | Ansible |
| Updates im Wartungsfenster | Ansible, gestartet aus einer Pipeline |
| Proxmox-Hosts selbst: Netze, Cluster-Verbindungen, Benutzer | Ansible |
| Inventar, Zweck und Verantwortliche | NetBox, Ansible liest daraus |
Die vorletzte Zeile überrascht manchmal: Die Proxmox-Server selbst richten wir mit Ansible ein, die VMs darauf legt Terraform an. Der Hypervisor ist ein laufendes System, das gepflegt wird. Die VMs sind die Ressourcen, die er bereitstellt.
Die Übergabe heißt Cloud-Init
Zwischen Terraform und Ansible gibt es einen Moment, in dem die VM existiert, aber noch niemand sie eingerichtet hat. Damit Ansible sich verbinden kann, braucht sie eine IP-Adresse, einen DNS-Server, einen Benutzer und einen SSH-Schlüssel. Das übergibt Terraform beim Anlegen per Cloud-Init. Alles danach übernimmt Ansible.
Damit beide sich danach nicht in die Quere kommen, sagen wir Terraform ausdrücklich, dass es die Cloud-Init-Einstellungen nach dem Anlegen ignorieren soll. Sonst würde Terraform bei jedem Lauf versuchen, Benutzer oder SSH-Einstellungen auf den Anfangszustand zurückzusetzen, die Ansible inzwischen geändert hat.
Drei Stolpersteine aus der Praxis
1. Eine geänderte IP wird still ignoriert. Die Kehrseite der Regel oben: Stellt sich nach dem Anlegen heraus, dass Gateway oder IP-Adresse falsch waren, reicht es nicht, den Wert im Code zu ändern. Terraform ignoriert die Änderung, ohne zu warnen. Bei einer frischen VM legen wir sie deshalb gezielt neu an. Bei einer VM mit Daten ist das keine Option, dort ändert man die Adresse per Ansible und zieht den Terraform-Code nach.
2. Terraform wartet auf einen Agent, den es nicht gibt. Proxmox kann über den QEMU-Gast-Agent die IP-Adresse einer VM auslesen, und Terraform wartet nach dem Anlegen darauf. Die offiziellen Debian-Cloud-Images bringen diesen Agent aber nicht mit. Ohne Gegenmaßnahme hängt Terraform minutenlang. Wir setzen deshalb ein kurzes Timeout und lassen Ansible den Agent installieren, oder wir schalten ihn für die VM ganz ab, wenn er nicht gebraucht wird. Dann darf Ansible aber auch nicht versuchen, ihn zu starten: Ohne die passende virtuelle Schnittstelle schlägt das fehl.
3. Nie eine Netzwerk-Konvention annehmen. In einem unserer Netze ist das Gateway die letzte Adresse im Subnetz, in einem anderen die erste. Wer beim Schreiben eines neuen Moduls die Konvention aus dem letzten Projekt übernimmt, baut eine VM, die nicht ins Netz kommt. Vor dem ersten Lauf prüfen wir das Gateway deshalb gegen die Dokumentation und danach per Ping.
Ein vierter Fall betrifft DNS: Holt sich ein Server sein TLS-Zertifikat selbst bei Let’s Encrypt, darf der DNS-Eintrag bei Cloudflare nicht über den Cloudflare-Proxy laufen, sonst scheitert die Prüfung des Zertifikats. Das steht bei uns als Kommentar direkt am Eintrag im Terraform-Code, damit niemand den Schalter später gut gemeint umlegt.
Was zusammengehört, liegt zusammen
Jeder Dienst und jedes Kundenprojekt hat bei uns ein eigenes Terraform-Verzeichnis: die VM auf Proxmox in einem, der DNS-Eintrag in einem zweiten. Die Konfiguration liegt als Ansible-Rolle daneben. Zugangsdaten stehen nie im Klartext im Repository: Für Terraform kommen sie aus Variablendateien, die nicht ins Git gehen, für Ansible aus verschlüsselten Vault-Dateien.
Ansible kennt die Systeme aus einem Inventar. Zusätzlich kann es seine Zielgruppen direkt aus NetBox bilden, etwa alle Hypervisoren, alle Systeme eines Kunden oder eines Standorts. So muss eine neue VM nicht an zwei Stellen nachgetragen werden.
Was nicht im Code steht
Nicht alles ist Terraform oder Ansible. Zweck und Verantwortliche eines Systems pflegen wir in NetBox, nicht im Code. Wichtig ist, dass diese Grenzen bekannt und dokumentiert sind. Gefährlich wird es erst, wenn jemand glaubt, alles stehe im Code, und es stimmt nicht.
Wie wir eine gewachsene Umgebung Schritt für Schritt in Terraform und Ansible abbilden, ohne den Betrieb zu unterbrechen, steht unter Infrastructure as Code und im Beitrag Infrastructure as Code für Bestandsumgebungen. Wie wir mit Ansible einen Agent auf viele Server verteilen, zeigt der Beitrag Wazuh mit Ansible ausrollen.

Geschrieben von Sascha Enke, Gründer & Geschäftsführer von Enke-iTS – über 20 Jahre Erfahrung in Infrastruktur-Architektur und Virtualisierung. Mehr über uns
