Terraform vs. CloudFormation: Der endgültige Leitfaden

Veröffentlicht: 2022-03-11

Wenn Sie wie ich das Internet durchforstet haben, um sich zwischen CloudFormation und Terraform als Ihrem nächsten Infrastructure-as-Code (IaC)-Tool zu entscheiden, ohne eine endgültige Antwort zu finden, habe ich Ihren Schmerz für eine lange Zeit geteilt. Jetzt habe ich umfangreiche Erfahrung mit beiden Tools und kann eine fundierte Entscheidung darüber treffen, welches ich verwenden möchte.

TL;DR

Wählen Sie für Ihr IaC-Projekt auf AWS CloudFormation, weil:

  1. CloudFormation unterscheidet zwischen Code (dh Templates) und Instanziierungen des Codes (dh Stacks). In Terraform gibt es diese Unterscheidung nicht. Mehr dazu im nächsten Abschnitt.
  2. Terraform handhabt das grundlegende Abhängigkeitsmanagement nicht sehr gut. Mehr dazu in einem späteren Abschnitt.

Unterscheidung zwischen Code und Instanziierungen

Ein Unterschied zwischen CloudFormation und Terraform besteht darin, wie Code und Instanziierungen innerhalb der einzelnen Dienste miteinander in Beziehung stehen.

CloudFormation hat das Konzept eines Stapels , der die Instanziierung einer Vorlage darstellt. Dieselbe Vorlage kann endlos von einem bestimmten Client in einem bestimmten Konto, über mehrere Konten oder von verschiedenen Clients instanziiert werden.

Terraform hat kein solches Konzept und erfordert eine Eins-zu-Eins-Beziehung zwischen Code und seiner Instanziierung. Es wäre vergleichbar mit dem Duplizieren des Quellcodes eines Webservers für jeden Server, den Sie ausführen möchten, oder dem Duplizieren des Codes jedes Mal, wenn Sie eine Anwendung ausführen müssen, anstatt die kompilierte Version auszuführen.

Dieser Punkt ist bei einem einfachen Setup ziemlich trivial, wird aber bei mittleren bis großen Operationen schnell zu einem großen Schmerzpunkt. In Terraform müssen Sie jedes Mal, wenn Sie einen neuen Stack aus vorhandenem Code erstellen müssen, den Code duplizieren. Und das Kopieren/Einfügen von Skriptdateien ist eine sehr einfache Möglichkeit, sich selbst zu sabotieren und Ressourcen zu beschädigen, die Sie nicht berühren wollten.

Terraform hat eigentlich kein Konzept von Stacks wie CloudFormation, was deutlich zeigt, dass Terraform von Grund auf so aufgebaut wurde, dass es eine Eins-zu-Eins-Übereinstimmung zwischen Code und den von ihm verwalteten Ressourcen gibt. Dies wurde später durch das Konzept der Umgebungen (die inzwischen in „Arbeitsbereiche“ umbenannt wurden) teilweise korrigiert, aber die Art und Weise, diese zu verwenden, macht es unglaublich einfach, sie in einer unerwünschten Umgebung bereitzustellen. Dies liegt daran, dass Sie terraform workspace select vor der Bereitstellung ausführen müssen, und wenn Sie diesen Schritt vergessen, wird die Bereitstellung in dem zuvor ausgewählten Workspace erfolgen, der möglicherweise der gewünschte ist oder nicht.

In der Praxis wird dieses Problem zwar durch die Verwendung von Terraform-Modulen gemildert, aber selbst im besten Fall würden Sie eine erhebliche Menge an Boilerplate-Code benötigen. Tatsächlich war dieses Problem so akut, dass die Leute ein Wrapper-Tool um Terraform erstellen mussten, um dieses Problem anzugehen: Terragrunt.

Zustandsverwaltung und Berechtigungen

Ein weiterer wichtiger Unterschied zwischen CloudFormation und Terraform besteht darin, wie sie jeweils Status und Berechtigungen verwalten.

CloudFormation verwaltet Stack-Zustände für Sie und gibt Ihnen keine Optionen. Aber CloudFormation-Stack-Zustände waren meiner Erfahrung nach solide. Außerdem ermöglicht CloudFormation weniger privilegierten Benutzern, Stacks zu verwalten, ohne über alle erforderlichen Berechtigungen zu verfügen, die der Stack selbst benötigt. Dies liegt daran, dass CloudFormation die Berechtigungen von einer an den Stack angehängten Servicerolle erhalten kann, anstatt die Berechtigungen von dem Benutzer, der den Stack-Vorgang ausführt.

Terraform erfordert, dass Sie ihm einige Backends zur Verfügung stellen, um Zustände zu verwalten. Der Standardwert ist eine lokale Datei, was angesichts folgender Bedingungen völlig unbefriedigend ist:

  1. Die Robustheit Ihrer Zustandsdatei ist vollständig mit der Robustheit der Maschine verbunden, auf der sie gespeichert ist.
  2. Das macht Teamarbeit so gut wie unmöglich.

Sie benötigen also einen robusten und gemeinsam genutzten Zustand, der bei AWS normalerweise durch die Verwendung eines S3-Buckets zum Speichern der Zustandsdatei erreicht wird, begleitet von einer DynamoDB-Tabelle zur Handhabung der Parallelität.

Das bedeutet, dass Sie für jeden Stack, den Sie instanziieren möchten, manuell einen S3-Bucket und eine DynamoDB-Tabelle erstellen und auch die Berechtigungen für diese beiden Objekte manuell verwalten müssen, um weniger privilegierten Benutzern den Zugriff auf Daten zu erschweren, auf die sie keinen Zugriff haben sollten. Wenn Sie nur ein paar Stacks haben, ist das kein allzu großes Problem, aber wenn Sie 20 Stacks verwalten müssen, wird das sehr umständlich.

Übrigens ist es bei der Verwendung von Terraform-Workspaces nicht möglich, eine DynamoDB-Tabelle pro Workspace zu haben. Das bedeutet, wenn Sie möchten, dass ein IAM-Benutzer mit minimalen Berechtigungen Bereitstellungen durchführt, kann dieser Benutzer mit den Sperren aller Arbeitsbereiche herumspielen, da DynamoDB-Berechtigungen nicht bis auf Elementebene abgestuft sind.

Abhängigkeitsmanagement

An diesem Punkt können sowohl CloudFormation als auch Terraform etwas knifflig sein. Wenn Sie die logische ID (dh den Namen) einer Ressource ändern, werden beide davon ausgehen, dass die alte Ressource zerstört und eine neue erstellt werden muss. Daher ist es im Allgemeinen keine gute Idee, die logische ID von Ressourcen in beiden Tools zu ändern, insbesondere für verschachtelte Stacks in CloudFormation.

Wie im ersten Abschnitt erwähnt, verarbeitet Terraform keine grundlegenden Abhängigkeiten. Leider widmen die Terraform-Entwickler dem seit langem bestehenden Problem trotz des offensichtlichen Mangels an Problemumgehungen nicht viel Aufmerksamkeit.

Angesichts der Tatsache, dass ein ordnungsgemäßes Abhängigkeitsmanagement für ein IaC-Tool absolut entscheidend ist, stellen solche Probleme in Terraform seine Eignung in Frage, sobald es um geschäftskritische Vorgänge geht, wie z. B. die Bereitstellung in einer Produktionsumgebung. CloudFormation vermittelt ein viel professionelleres Gefühl, und AWS achtet immer sehr darauf, sicherzustellen, dass es seinen Kunden Tools in Produktionsqualität anbietet. In all den Jahren, in denen ich CloudFormation verwende, bin ich nie auf ein Problem mit dem Abhängigkeitsmanagement gestoßen.

CloudFormation ermöglicht es einem Stack, einige seiner Ausgabevariablen zu exportieren, die dann von anderen Stacks wiederverwendet werden können. Um ehrlich zu sein, ist diese Funktionalität begrenzt, da Sie nicht mehr als einen Stapel pro Region instanziieren können. Dies liegt daran, dass Sie nicht zwei Variablen mit demselben Namen exportieren können und exportierte Variablen keine Namespaces haben.

Terraform bietet keine derartigen Einrichtungen, sodass Ihnen weniger wünschenswerte Optionen zur Verfügung stehen. Mit Terraform können Sie den Zustand eines anderen Stacks importieren, aber das gibt Ihnen Zugriff auf alle Informationen in diesem Stack, einschließlich der vielen Geheimnisse, die in dem Zustand gespeichert sind. Alternativ kann ein Stack einige Variablen in Form einer JSON-Datei exportieren, die in einem S3-Bucket gespeichert ist, aber auch diese Option ist umständlicher: Sie müssen entscheiden, welcher S3-Bucket verwendet werden soll, ihm die entsprechenden Berechtigungen erteilen und alle schreiben Programmieren Sie selbst Code sowohl auf der Schreiber- als auch auf der Leserseite.

Ein Vorteil von Terraform ist, dass es Datenquellen hat. Terraform kann somit Ressourcen abfragen, die nicht von Terraform verwaltet werden. In der Praxis hat dies jedoch wenig Relevanz, wenn Sie eine generische Vorlage schreiben möchten, da Sie dann keine Annahmen über das Zielkonto treffen. Das Äquivalent in CloudFormation besteht darin, weitere Vorlagenparameter hinzuzufügen, was somit Wiederholungen und Fehlerpotenzial mit sich bringt; meiner Erfahrung nach war dies jedoch nie ein Problem.

Zurück zum Problem der Abhängigkeitsverwaltung von Terraform, ein weiteres Beispiel ist, dass Sie eine Fehlermeldung erhalten, wenn Sie versuchen, die Einstellungen für einen Load Balancer zu aktualisieren, und Folgendes erhalten:

 Error: Error deleting Target Group: ResourceInUse: Target group 'arn:aws:elasticloadbalancing:us-east-1:723207552760:targetgroup/strategy-api-default-us-east-1/14a4277881e84797' is currently in use by a listener or a rule status code: 400, request id: 833d8475-f702-4e01-aa3a-d6fa0a141905

Das erwartete Verhalten wäre, dass Terraform erkennt, dass die Zielgruppe eine Abhängigkeit von einer anderen Ressource ist, die nicht gelöscht wird, und folglich nicht versuchen sollte, sie zu löschen – aber es sollte auch keinen Fehler ausgeben.

Operationen

Obwohl Terraform ein Befehlszeilentool ist, erwartet es sehr deutlich, dass ein Mensch es ausführt, da es sehr interaktiv ist. Es ist möglich, es im Stapelmodus auszuführen (dh von einem Skript aus), aber dies erfordert einige zusätzliche Befehlszeilenargumente. Die Tatsache, dass Terraform so entwickelt wurde, dass es standardmäßig von Menschen ausgeführt wird, ist ziemlich verwirrend, wenn man bedenkt, dass der Zweck eines IaC-Tools die Automatisierung ist.

Terraform ist schwer zu debuggen. Fehlermeldungen sind oft sehr einfach und lassen Sie nicht verstehen, was schief läuft. In diesem Fall müssen Sie Terraform mit TF_LOG=debug , was eine riesige Menge an zu durchsuchender Ausgabe erzeugt. Erschwerend kommt hinzu, dass Terraform manchmal API-Aufrufe an AWS durchführt, die fehlschlagen, aber der Fehler ist kein Problem mit Terraform. Im Gegensatz dazu bietet CloudFormation ziemlich klare Fehlermeldungen mit ausreichend Details, damit Sie verstehen können, wo das Problem liegt.

Ein Beispiel für eine Terraform-Fehlermeldung:

 Error: error reading S3 bucket Public Access Block: NoSuchBucket: The specified bucket does not exist status code: 404, request id: 19AAE641F0B4AC7F, host id: rZkgloKqxP2/a2F6BYrrkcJthba/FQM/DaZnj8EQq/5FactUctdREq8L3Xb6DgJmyKcpImipv4s=

Die obige Fehlermeldung zeigt eine eindeutige Fehlermeldung, die eigentlich nicht das zugrunde liegende Problem widerspiegelt (in diesem Fall ein Berechtigungsproblem).

Diese Fehlermeldung zeigt auch, wie sich Terraform manchmal selbst in die Ecke malen kann. Wenn Sie beispielsweise einen S3-Bucket und eine aws_s3_bucket_public_access_block -Ressource für diesen Bucket erstellen und aus irgendeinem Grund einige Änderungen am Terraform-Code vornehmen, die diesen Bucket zerstören – z. Terraform bleibt beim Versuch, den aws_s3_bucket_public_access_block zu laden, hängen, schlägt aber ständig mit dem obigen Fehler fehl. Das korrekte Verhalten von Terraform wäre, den aws_s3_bucket_public_access_block entsprechend zu ersetzen oder zu löschen.

Schließlich können Sie die CloudFormation-Hilfsskripte nicht mit Terraform verwenden. Dies kann ein Ärgernis sein, insbesondere wenn Sie hoffen, cfn-signal zu verwenden, das CloudFormation mitteilt, dass eine EC2-Instance die Initialisierung abgeschlossen hat und bereit ist, Anfragen zu bedienen.

Syntax, Community und Rollback

Syntaxtechnisch hat Terraform einen guten Vorteil gegenüber CloudFormation – es unterstützt Schleifen. Aber nach meiner eigenen Erfahrung kann sich diese Funktion als etwas gefährlich herausstellen. Typischerweise wird eine Schleife verwendet, um eine Reihe identischer Ressourcen zu erstellen; Wenn Sie jedoch den Stack mit einer anderen Anzahl aktualisieren möchten, besteht die Möglichkeit, dass Sie die alten und die neuen Ressourcen verknüpfen müssen (z. B. mit zipmap() , um Werte aus zwei Arrays zu kombinieren, die jetzt zufällig sind unterschiedlicher Größe, da ein Array die Größe der alten Schleifengröße und das andere die Größe der neuen Schleifengröße hat). Es ist wahr, dass ein solches Problem ohne Schleifen auftreten kann, aber ohne Schleifen wäre das Problem für die Person, die das Skript schreibt, viel offensichtlicher. Die Verwendung von Schleifen in einem solchen Fall verschleiert das Problem.

Ob die Syntax von Terraform oder CloudFormation besser ist, ist meist eine Frage der Vorlieben. CloudFormation unterstützte anfänglich nur JSON, aber JSON-Vorlagen sind sehr schwer zu lesen. Glücklicherweise unterstützt CloudFormation auch YAML, das viel einfacher zu lesen ist und Kommentare zulässt. Die Syntax von CloudFormation neigt jedoch dazu, ziemlich ausführlich zu sein.

Die Syntax von Terraform verwendet HCL, das eine Art JSON-Derivat ist und ziemlich eigenwillig ist. Terraform bietet mehr Funktionen als CloudFormation, und sie sind normalerweise einfacher zu verstehen. Man könnte also argumentieren, dass Terraform in diesem Punkt einen leichten Vorteil hat.

Ein weiterer Vorteil von Terraform ist sein leicht verfügbarer Satz von Community-verwalteten Modulen, was das Schreiben von Vorlagen vereinfacht. Ein Problem könnte sein, dass solche Module möglicherweise nicht sicher genug sind, um die Anforderungen einer Organisation zu erfüllen. Für Organisationen, die ein hohes Maß an Sicherheit benötigen, kann es daher erforderlich sein, diese Module (sowie weitere Versionen, sobald sie verfügbar sind) zu überprüfen.

Im Allgemeinen sind Terraform-Module viel flexibler als verschachtelte CloudFormation-Stacks. Ein verschachtelter CloudFormation-Stapel neigt dazu, alles darunter zu verbergen. Aus dem verschachtelten Stapel würde eine Aktualisierungsoperation zeigen, dass der verschachtelte Stapel aktualisiert wird, aber nicht im Detail zeigen, was innerhalb des verschachtelten Stapels passieren wird.

Ein letzter Punkt, der eigentlich umstritten sein könnte, ist, dass CloudFormation versucht, fehlgeschlagene Bereitstellungen rückgängig zu machen. Dies ist eine ziemlich interessante Funktion, kann aber leider sehr lange dauern (z. B. kann es bis zu drei Stunden dauern, bis CloudFormation entscheidet, dass eine Bereitstellung für Elastic Container Service fehlgeschlagen ist). Im Gegensatz dazu hält Terraform im Fehlerfall einfach dort an, wo es war. Ob eine Rollback-Funktion eine gute Sache ist oder nicht, ist umstritten, aber ich habe die Tatsache zu schätzen gelernt, dass ein Stapel so weit wie möglich in einem funktionierenden Zustand gehalten wird, wenn eine längere Wartezeit ein akzeptabler Kompromiss ist.

Zur Verteidigung von Terraform vs. CloudFormation

Terraform hat Vorteile gegenüber CloudFormation. Das Wichtigste ist meiner Meinung nach, dass Ihnen Terraform beim Anwenden eines Updates alle Änderungen anzeigt, die Sie vornehmen werden, einschließlich eines Drilldowns in alle verwendeten Module. Im Gegensatz dazu zeigt Ihnen CloudFormation bei der Verwendung von verschachtelten Stacks nur, dass der verschachtelte Stack aktualisiert werden muss, bietet jedoch keine Möglichkeit, die Details aufzuschlüsseln. Dies kann frustrierend sein, da diese Art von Informationen sehr wichtig ist, bevor Sie auf die Schaltfläche „Los“ klicken.

Sowohl CloudFormation als auch Terraform unterstützen Erweiterungen. In CloudFormation ist es möglich, sogenannte „Custom Resources“ zu verwalten, indem Sie eine selbst erstellte AWS Lambda-Funktion als Backend verwenden. Für Terraform sind Erweiterungen viel einfacher zu schreiben und Teil des Codes zu bilden. In diesem Fall gibt es also einen Vorteil für Terraform.

Terraform kann mit vielen Cloud-Anbietern umgehen. Dadurch ist Terraform in der Lage, eine bestimmte Bereitstellung auf mehreren Cloud-Plattformen zu vereinheitlichen. Angenommen, Sie haben eine einzelne Workload, die zwischen AWS und Google Cloud Platform (GCP) verteilt ist. Normalerweise würde der AWS-Teil der Workload mit CloudFormation und der GCP-Teil mit dem Cloud Deployment Manager von GCP bereitgestellt. Mit Terraform könnten Sie stattdessen ein einziges Skript verwenden, um beide Stacks in ihren jeweiligen Cloud-Plattformen bereitzustellen und zu verwalten. Auf diese Weise müssen Sie nur einen Stack statt zwei bereitstellen.

Keine Argumente für Terraform vs. CloudFormation

Es gibt einige Nicht-Argumente, die weiterhin im Internet kursieren. Das Größte, was herumgeworfen wird, ist, dass Sie, da Terraform Multi-Cloud ist, ein Tool verwenden können, um alle Ihre Projekte bereitzustellen, unabhängig davon, auf welcher Cloud-Plattform sie ausgeführt werden. Technisch gesehen stimmt das, aber es ist nicht der große Vorteil, den es zu sein scheint, insbesondere bei der Verwaltung typischer Single-Cloud-Projekte. Die Realität ist, dass es fast eine Eins-zu-Eins-Entsprechung zwischen Ressourcen gibt, die (zum Beispiel) in CloudFormation deklariert sind, und denselben Ressourcen, die in einem Terraform-Skript deklariert sind. Da Sie die Details der Cloud-spezifischen Ressourcen so oder so kennen müssen, liegt der Unterschied in der Syntax, die kaum der größte Schmerzpunkt bei der Verwaltung von Bereitstellungen ist.

Einige argumentieren, dass man durch die Verwendung von Terraform eine Anbieterbindung vermeiden kann. Dieses Argument gilt nicht in dem Sinne, dass Sie durch die Verwendung von Terraform von HashiCorp (dem Schöpfer von Terraform) eingesperrt sind, genauso wie Sie durch die Verwendung von CloudFormation von AWS usw. für andere Clouds eingesperrt sind Plattformen.

Dass Terraform-Module einfacher zu handhaben sind, ist für mich weniger wichtig. Zunächst einmal glaube ich, dass AWS aufgrund der wahrgenommenen Verantwortung für benutzergemachte Sicherheitslücken und Verstöße gegen verschiedene Compliance-Programme bewusst vermeiden möchte, ein einziges Repository für Community-basierte CloudFormation-Vorlagen zu hosten.

Auf einer persönlicheren Ebene verstehe ich die Vorteile der Verwendung von Bibliotheken im Fall der Softwareentwicklung voll und ganz, da diese Bibliotheken leicht Zehntausende von Codezeilen umfassen können. Im Fall von IaC ist der Code jedoch normalerweise viel kleiner, und solche Module sind normalerweise einige Dutzend Zeilen lang. Die Verwendung von Kopieren/Einfügen ist eigentlich keine so schlechte Idee in dem Sinne, dass es Probleme bei der Aufrechterhaltung der Kompatibilität vermeidet und Ihre Sicherheit an unbekannte Personen delegiert.

Die Verwendung von Copy/Paste ist bei vielen Entwicklern und DevOps-Ingenieuren verpönt, und dafür gibt es gute Gründe. Mein Standpunkt ist jedoch, dass Sie Codeschnipsel mit Kopieren/Einfügen einfach an Ihre Bedürfnisse anpassen können, und es ist nicht erforderlich, eine Bibliothek daraus zu machen und viel Zeit damit zu verbringen, sie generisch zu machen. Der Aufwand für die Pflege dieser Codeschnipsel ist normalerweise sehr gering, es sei denn, Ihr Code wird in beispielsweise einem Dutzend oder mehr Vorlagen dupliziert. In einem solchen Fall ist es sinnvoll, sich den Code anzueignen und ihn als verschachtelten Stapel zu verwenden, und die Vorteile, sich nicht zu wiederholen, sind wahrscheinlich größer als der Ärger, nicht sehen zu können, was im verschachtelten Stapel aktualisiert wird, wenn Sie eine Aktualisierung durchführen Operation.

Fazit CloudFormation vs. Terraform

Mit CloudFormation möchte AWS seinen Kunden ein grundsolides Tool zur Verfügung stellen, das jederzeit wie vorgesehen funktioniert. Das Team von Terraform tut das natürlich auch – aber es scheint, dass ein entscheidender Aspekt ihrer Werkzeuge, das Abhängigkeitsmanagement, leider keine Priorität hat.

Terraform könnte einen Platz in Ihrem Projekt haben, insbesondere wenn Sie eine Multi-Cloud-Architektur haben. In diesem Fall sind Terraform-Skripte eine Möglichkeit, die Verwaltung von Ressourcen über die verschiedenen von Ihnen verwendeten Cloud-Anbieter hinweg zu vereinheitlichen. Aber Sie könnten die Nachteile von Terraform in diesem Fall immer noch vermeiden, indem Sie Terraform nur verwenden, um Stacks zu verwalten, die bereits mit ihren jeweiligen Cloud-spezifischen IaC-Tools implementiert wurden.

Das allgemeine Gefühl zwischen Terraform und CloudFormation ist, dass CloudFormation, obwohl unvollkommen, professioneller und zuverlässiger ist, und ich würde es definitiv für jedes Projekt empfehlen, das nicht speziell Multi-Cloud ist.