Bei der Arbeit mit Terraformsollte das Standard-Meta-Argument zum Erstellen von Ressourcen fast immer „for_each“ lauten – insbesondere bei Infrastruktur, die voraussichtlich lange bestehen bleibt und sich im Laufe der Zeit weiterentwickelt.
Auch wenn COUNT auf den ersten Blick einfacher erscheint , bringt es doch erhebliche Einschränkungen mit sich, sobald die Infrastruktur skaliert, umgestaltet oder parallele Umgebungen unterstützen muss. Dies wird in realen Szenarien, in denen Flexibilität und Wartbarkeit eine wichtige Rolle spielen, schmerzlich deutlich.
Dieser Artikel beschreibt Schritt für Schritt eine reale Migration von COUNT-basierten Ressourcen zu FOR_EACH und erläutert, warum sich der Aufwand lohnt und worauf man dabei achten muss.

Das Problem mit der Zählung bei langlebiger Infrastruktur
Dieses Problem trat auf, als eine zusätzliche Amazon OpenSearch Service -Domäne aus einem bestehenden Git-Repository bereitgestellt wurde.
Die ursprüngliche Implementierung verwendete COUNT-basierte Ressourcen ohne Modulabstraktion. Zwar funktionierte dies für eine einzelne Domäne, doch die Erweiterung erwies sich schnell als mühsam.
Ein häufiger Anwendungsfall, in dem dies vorkommt, ist, wenn:
- Master- oder Datenknoten-Instanztypen können nicht an Ort und Stelle migriert werden
- Es muss ein paralleler OpenSearch-Cluster eingerichtet werden
- Die Daten müssen per Snapshot und Wiederherstellung migriert werden
Mit „count“ wird diese Art der Weiterentwicklung instabil und fehleranfällig.
Die Ausgangslage: Zu viele Variablen, zu wenig Flexibilität
Als Ausgangspunkt dienten 33 einzelne Variablen, die jeweils Standardwerte aufwiesen und separat in der Datei „variables.tf“ definiert waren.
Jede Variable wurde direkt mit einzelnen Ressourcen verbunden, darunter:
aws_iam_service_linked_role
aws_kms_key
aws_security_group
aws_cloudwatch_log_group
aws_cloudwatch_log_resource_policy
aws_opensearch_domain
aws_opensearch_domain_policy
aws_s3_bucket
aws_s3_bucket_public_access_block
aws_s3_bucket_versioning
aws_s3_bucket_policy
aws_iam_role
aws_iam_policy
aws_iam_role_policy_attachment
Diese Struktur machte es praktisch unmöglich, eine zweite OpenSearch-Domäne in derselben Region einzurichten, ohne große Teile des Quellcodes zu duplizieren.
Umstellung auf FOR_EACH: Die zentrale Designänderung
Der erste und wichtigste Schritt bestand darin, alle 33 Variablen in einer einzigen Objektkarte zusammenzufassen.
Anstatt Dutzende einzelner Variablen zu verwalten, wurde alles in einer einzigen strukturierten Variablen zusammengefasst – wobei weiterhin dieselben Standardwerte verwendet wurden, nun jedoch mehrere Domänen deklarativ definiert werden konnten.
Dazu mussten die Ressourcendefinitionen aktualisiert und eine bedingte Logik für die Erstellung von Ressourcen eingeführt werden.
Beispiel: Bedingte Erstellung von Ressourcen mit FOR_EACH
resource "aws_cloudwatch_log_resource_policy" "main" {
for_each = {
for k, v in var.es_domain :
k => v
if length(v.es_cloudwatch_log_types) > 0
}
}
In diesem Beispiel:
- Die CloudWatch-Log-Ressourcenrichtlinie wird nur erstellt, wenn „es_cloudwatch_log_types“ definiert ist.
- Wenn das Feld nicht angegeben wird, wird standardmäßig die leere Liste verwendet.
es_cloudwatch_log_types = optional(list(string), [])
Wenn nichts angegeben wird, wird die Ressource nicht erstellt – übersichtlich, vorhersehbar und flexibel.
Snapshot und Wiederherstellung zwischen parallelen OpenSearch-Domänen
Eine der Voraussetzungen für die Einrichtung einer neuen Domain war die Möglichkeit, Folgendes zu tun:
- Schreibvorgänge auf der bestehenden Domäne unterbinden
- Snapshot erstellen
- Stellen Sie diesen Snapshot in der neuen Domäne in derselben AWS-Region wieder her.
Um dies zu unterstützen, waren folgende Komponenten erforderlich:
Erforderliche Infrastruktur
- Ein S3-Bucket mit einer Zugriffsrichtlinie, die das Lesen und Schreiben von Snapshots erlaubt
- Eine IAM-Rolle, die vom Dienstprinzipal „es.amazonaws.com“ übernommen werden kann
- Registrierung des S3-Buckets als Snapshot-Repository in beiden Domänen
Das Snapshot-Repository registrieren
PUT https://vpc-ew2-test-domain.eu-west-2.es.amazonaws.com/_snapshot/my-snapshots-repo
-d '{
"type": "s3",
"settings": {
"bucket": "opensearch-snapshots-ew2-test",
"region": "eu-west-2",
"role_arn": "arn:aws:iam::001122334455:role/opensearch-snapshot-role-ew2-test"
}
}'
Nach der Registrierung:
- Auf Domäne A wird ein Snapshot erstellt
- OpenSearch übernimmt die IAM-Rolle „Snapshot“
- Die Daten werden in den S3-Bucket geschrieben
- Domäne B stellt den Snapshot aus demselben Repository wieder her
Dieser Ansatz ermöglicht sichere, kontrollierte Migrationen zwischen Domänen.
Umgang mit Änderungen an Ressourcenadressen mithilfe von „moved“
Ein entscheidender Schritt beim Wechsel von COUNT zu FOR_EACH teilt Terraform mit, dass sich die Adressen der Ressourcen geändert haben.
Wird dies nicht getan, versucht Terraform, die vorhandene Infrastruktur zu löschen und neu zu erstellen.
Beispiel:
moved {
from = aws_opensearch_domain.main[0]
to = aws_opensearch_domain.main["ew2-test"]
}
Wichtige Einschränkungen
- Verschobene Blöcke akzeptieren nur statische Zeichenfolgen
- Schleifen oder dynamische Ausdrücke werden nicht unterstützt
- Umfangreiche Migrationen müssen schrittweise durchgeführt werden, nicht auf einmal.
Das verlangsamt zwar den Übergang, gewährleistet jedoch die Konsistenz des Systemzustands und verhindert Ausfallzeiten.
Abschließende Gedanken: Warum sich FOR_EACH lohnt
Die Umstellung von COUNT auf FOR_EACH ist selten trivial – insbesondere in ausgereiften Terraform-Codebasen.
Die langfristigen Vorteile überwiegen jedoch bei weitem die kurzfristigen Schwierigkeiten:
- Mehrere OpenSearch-Domänen pro Region
- Übersichtlichere, aussagekräftigere Konfiguration
- Einfachere Snapshots, Wiederherstellungen und Außerbetriebnahmen
- Eine Infrastruktur, die sich weiterentwickelt, anstatt sich zu wehren
Letztendlich ermöglicht FOR_EACH es Terraform, mit Ihrer Infrastruktur mitzuwachsen – anstatt sie zu bremsen.

