Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Dieses Beispiel enthält Code als Beispiel für die Strukturierung von Terraform-Konfigurationen für eine mittelgroße Infrastruktur, dazu werden verwendet:
2 AWS-Konten
2 separate Umgebungen (prod
und stage
, die sich nichts teilen). Jede Umgebung befindet sich in einem separaten AWS-Konto.
Jede Umgebung verwendet die gleiche Version eines internen Moduls modules/network
, da es aus einem lokalen Verzeichnis stammt.
Perfekt für Projekte, bei denen die Infrastruktur logisch getrennt ist (separate AWS-Konten)
Gut, wenn keine Notwendigkeit besteht, zwischen AWS-Konten geteilte Ressourcen zu ändern (eine Umgebung = ein AWS-Konto = eine Statusdatei)
Gut, wenn kein Bedarf an der Orchestrierung von Änderungen zwischen den Umgebungen besteht
Gut, wenn die Infrastrukturressourcen pro Umgebung absichtlich unterschiedlich sind und nicht verallgemeinert werden können (z. B. sind einige Ressourcen in einer Umgebung oder in einigen Regionen nicht vorhanden)
Je größer das Projekt wird, desto schwieriger wird es, diese Umgebungen untereinander auf dem neuesten Stand zu halten. Erwägen Sie den Einsatz von Infrastrukturmodulen (von der Stange oder intern) für wiederholbare Aufgaben.
Dieses Beispiel enthält Code als Beispiel für die Strukturierung von Terraform-Konfigurationen für eine groß angelegte Infrastruktur, dazu werden verwendet:
2 AWS-Konten
2 Regionen
2 separate Umgebungen (prod
und stage
, die sich nichts teilen). Jede Umgebung befindet sich in einem separaten AWS-Konto und verteilt die Ressourcen auf 2 Regionen.
Jede Umgebung verwendet die gleiche Version eines internen Moduls modules/network
, da es aus einem lokalen Verzeichnis stammt.
Perfekt für Projekte, bei denen die Infrastruktur logisch getrennt ist (separate AWS-Konten)
Gut, wenn keine Notwendigkeit besteht, zwischen AWS-Konten geteilte Ressourcen zu ändern (eine Umgebung = ein AWS-Konto = eine Statusdatei)
Gut, wenn kein Bedarf an der Orchestrierung von Änderungen zwischen den Umgebungen besteht
Gut, wenn die Infrastrukturressourcen pro Umgebung absichtlich unterschiedlich sind und nicht verallgemeinert werden können (z. B. sind einige Ressourcen in einer Umgebung oder in einigen Regionen nicht vorhanden)
Je größer das Projekt wird, desto schwieriger wird es, diese Umgebungen untereinander auf dem neuesten Stand zu halten. Erwägen Sie den Einsatz von Infrastrukturmodulen (von der Stange oder intern) für wiederholbare Aufgaben.
Es sollte keinen Grund geben, nicht wenigstens diese Konventionen zu befolgen :)
Beachten Sie, dass die tatsächlichen Cloud-Ressourcen oft Einschränkungen bei den zulässigen Namen haben. Einige Ressourcen dürfen zum Beispiel keine Bindestriche enthalten, andere müssen in Kamelschreibweise geschrieben werden. Die Konventionen in diesem Buch beziehen sich auf die Terraform-Namen selbst.
Verwenden Sie überall _
(Unterstrich) anstelle von -
(Bindestrich) (Ressourcennamen, Datenquellennamen, Variablennamen, Ausgaben usw.).
Verwenden Sie vorzugsweise Kleinbuchstaben und Zahlen (auch wenn UTF-8 unterstützt wird).
Wiederholen Sie den Ressourcentyp nicht im Ressourcennamen (weder teilweise noch vollständig):
resource "aws_route_table" "public" {}
resource "aws_route_table" "public_route_table" {}
resource "aws_route_table" "public_aws_route_table" {}
Verwenden Sie bei Namen immer die Einzahl.
Verwenden Sie -
innerhalb von Argumenten und an Stellen, an denen der Wert für einen Menschen sichtbar ist (z. B. innerhalb des DNS-Namens der RDS-Instanz).
Fügen Sie das Argument count
/ for_each
innerhalb des Ressourcen- oder Datenquellenblocks als erstes Argument oben ein und trennen Sie es danach durch einen Zeilenumbruch.
Fügen Sie das Argument tags
, falls von der Ressource unterstützt, als letztes echtes Argument ein, gefolgt von depends_on
und lifecycle
, falls erforderlich. Alle diese Argumente sollten durch eine einzelne Leerzeile getrennt werden.
Bei der Verwendung von Bedingungen in einem count
/ for_each
Argument sind boolesche Werte zu bevorzugen, anstatt length
oder andere Ausdrücke zu verwenden.
resource
count
/ for_each
tags
count
Erfinden Sie das Rad in Ressourcenmodulen nicht neu: Verwenden Sie den Namen, die Beschreibung und den Standardwert für Variablen, wie sie im Abschnitt "Argumentreferenz" für die Ressource, mit der Sie arbeiten, definiert sind.
Die Unterstützung für die Validierung von Variablen ist ziemlich begrenzt (z.B. kann nicht auf andere Variablen zugegriffen werden oder Lookups durchgeführt werden). Planen Sie entsprechend, denn in vielen Fällen ist diese Funktion nutzlos.
Verwenden Sie die Pluralform in einem Variablennamen, wenn der Typ list(...)
oder map(...)
ist.
Ordnen Sie die Schlüssel in einem Variablenblock wie folgt an: description
, type
, default
, validation
Fügen Sie immer eine description
allen Variablen hinzu, auch wenn Sie denken, dass es offensichtlich ist (Sie werden es in Zukunft brauchen).
Verwenden Sie lieber einfache Typen (number
, string
, list(...)
, map(...),
any
) als spezifische Typen wie object()
, es sei denn, Sie müssen strenge Einschränkungen für jeden Schlüssel haben.
Verwenden Sie spezifische Typen wie map(map(string))
, wenn alle Elemente der Map denselben Typ haben (z. B. string
) oder in diesen umgewandelt werden können (z. B. kann der Typ number
in string
umgewandelt werden).
Verwenden Sie type any
, um die Typüberprüfung ab einer bestimmten Tiefe zu deaktivieren oder wenn mehrere Typen unterstützt werden sollen.
Der Wert {}
ist manchmal eine map()
und manchmal ein object()
. Verwenden Sie tomap(...)
, um eine map()
zu erstellen, da es keine Möglichkeit gibt, ein object()
zu erstellen.
Machen Sie Ausgaben konsistent und verständlich außerhalb des Moduls (wenn ein Benutzer ein Modul verwendet, sollte es offensichtlich sein, welchen Typ und welches Attribut der Wert hat, den es zurückgibt).
Der Name der Ausgabe sollte die darin enthaltene Eigenschaft beschreiben und weniger frei formuliert sein, als Sie es normalerweise wünschen würden.
Eine gute Struktur für den Namen der Ausgabe sieht aus wie {name}_{type}_{attribute}
, wobei:
{name}
ein Ressourcen- oder Datenquellenname ohne Provider-Präfix ist. {name}
für aws_subnet
ist subnet
, für aws_vpc
ist es vpc
.
{type}
ist ein Typ einer Ressourcenquelle
{attribute}
ist ein Attribut, das von der Ausgabe zurückgegeben wird.
Geben Sie immer eine description
für alle Ausgaben an, auch wenn Sie denken, dass es offensichtlich ist.
Vermeiden Sie es, sensitive
Argumente zu setzen, es sei denn, Sie kontrollieren die Verwendung dieser Ausgabe an allen Stellen in allen Modulen vollständig.
Bevorzugen Sie try()
(verfügbar seit Terraform 0.13) gegenüber element(concat(...))
(Legacy-Ansatz für die Version vor 0.13)
output
Höchstens eine ID einer Security-Gruppe ausgeben:
Wenn mehrere Ressourcen desselben Typs vorhanden sind, sollte this
im Namen der Ausgabe weggelassen werden:
Pluralname verwenden, wenn der Rückgabewert eine Liste ist:
Typ | Beschreibung | Einsatzbereitschaft |
---|---|---|
Typ | Beschreibung | Einsatzbereitschaft |
---|---|---|
Quellcode:
Jede Umgebung verwendet eine andere Version des Standard-Infrastrukturmoduls (alb
), das aus der stammt.
Quellcode:
Jede Umgebung verwendet eine andere Version des Standard-Infrastrukturmoduls (alb
), das aus der stammt.
In einem großen Projekt wie dem hier beschriebenen werden die Vorteile der Verwendung von Terragrunt sehr deutlich. Siehe .
Der Ressourcenname sollte this
benannt werden, wenn kein beschreibender und allgemeiner Name verfügbar ist, oder wenn das Ressourcenmodul eine einzelne Ressource dieses Typs erstellt (z. B. gibt es im eine einzelne Ressource des Typs aws_nat_gateway
und mehrere Ressourcen des Typs aws_route_table
, daher sollte aws_nat_gateway
this
benannt werden und aws_route_table
sollte beschreibendere Namen haben - wie private
, public
oder database
).
.
Wenn die Ausgabe einen Wert mit Interpolationsfunktionen und mehreren Ressourcen zurückgibt, sollten {name}
und {type}
dort so allgemein wie möglich sein (this
sollte als Präfix weggelassen werden). .
Wenn der zurückgegebene Wert eine Liste ist, sollte er einen Pluralnamen haben. .
Wenige Ressourcen, keine externen Abhängigkeiten. Ein AWS-Konto. Eine Region. Eine Umgebung.
Ja
Mehrere AWS-Konten und Umgebungen, handelsübliche Infrastrukturmodule mit Terraform.
Ja
Viele AWS-Konten, viele Regionen. Dringender Bedarf, Copy-Paste zu reduzieren, benutzerdefinierte Infrastrukturmodule, starke Nutzung von Compositions. Verwendung von Terraform.
In Arbeit
sehr groß
Mehrere Anbieter (AWS, GCP, Azure). Multi-Cloud-Einsatz. Verwendung von Terraform.
Nein
mittel
Mehrere AWS-Konten und Umgebungen, handelsübliche Infrastrukturmodule, Kompositionsmuster mit Terragrunt.
Nein
groß
Many AWS accounts, many regions, urgent need to reduce copy-paste, custom infrastructure modules, heavy usage of compositions. Using Terragrunt. Viele AWS-Konten, viele Regionen. Dringender Bedarf, Copy-Paste zu reduzieren, benutzerdefinierte Infrastrukturmodule, starke Nutzung von Kompositionen. Verwendung von Terragrunt.
Nein
sehr groß
Mehrere Anbieter (AWS, GCP, Azure). Multi-Cloud-Einsätze. Verwendung von Terragrunt.
Nein
Quellcode: https://github.com/antonbabenko/terraform-best-practices/tree/master/examples/small-terraform
Dieses Beispiel enthält Code als Beispiel für die Strukturierung von Terraform-Konfigurationen für eine kleine Infrastruktur, in der keine externen Abhängigkeiten verwendet werden.
Perfekt für den Einstieg und zum Refactoring im laufenden Betrieb
Perfekt für kleine Ressourcenmodule
Gut für kleine und lineare Infrastrukturmodule (z.B. terraform-aws-atlantis)
Gut geeignet für eine kleine Anzahl von Ressourcen (weniger als 20-30)
Eine einzige Statusdatei für alle Ressourcen kann den Arbeitsprozess mit Terraform verlangsamen, wenn die Anzahl der Ressourcen wächst (erwägen Sie die Verwendung des Arguments -target
, um die Anzahl der Ressourcen zu begrenzen)
Es gibt eine Menge Leute, die großartige Inhalte erstellen und Open-Source-Projekte verwalten, die für die Terraform-Gemeinschaft relevant sind, aber ich weiß nicht, wie ich diese Links hier am besten auflisten kann, ohne Sammlungen wie awesome-terraform zu kopieren.
https://twitter.com/antonbabenko/lists/terraform-experts - Liste von Leuten, die sehr aktiv mit Terraform arbeiten und Ihnen eine Menge erzählen können (wenn Sie sie fragen).
https://github.com/shuaibiyy/awesome-terraform - Kuratierte Liste von Ressourcen zu HashiCopr Terraform.
http://bit.ly/terraform-youtube - "Your Weekly Dose of Terraform" YouTube Kanal von Anton Babenko. Live-Streams mit Reviews, Interviews, Fragen und Antworten, Live-Coding und ein wenig Hacking mit Terraform.
https://weekly.tf - Terraform Weekly Newsletter. Verschiedene Neuigkeiten aus der Terraform-Welt (Projekte, Ankündigungen, Diskussionen) von Anton Babenko.
FTP (Frequent Terraform Problems) - Häufige Probleme mit Terraform
Terragrunt - Orchestrierungswerkzeug
tflint - Code linter
tfenv - Terraform Versionsverwaltung
Atlantis - Pull Request Automatisierung
pre-commit-terraform - Sammlung von Git-Hooks für Terraform, die mit dem Pre-Commit-Framework verwendet werden können
Infracost - Cloud-Kostenschätzungen für Terraform in Pull Requests. Funktioniert auch mit Terragrunt, Atlantis und pre-commit-terraform.
Die Versionen der Ressourcen- und Infrastrukturmodule sollten angegeben werden. Provider sollten außerhalb von Modulen konfiguriert werden, aber nur in der Komposition. Die Versionen von Providern und Terraform können auch fixiert werden.
Es gibt kein Master-Tool für die Verwaltung von Abhängigkeiten, aber es gibt einige Tipps, um die Abhängigkeitshölle weniger problematisch zu machen. Zum Beispiel kann Dependabot verwendet werden, um die Aktualisierung von Abhängigkeiten zu automatisieren. Dependabot erstellt Pull Requests, um Ihre Abhängigkeiten sicher und aktuell zu halten. Dependabot unterstützt Terraform-Konfigurationen.
Es gibt auch einen Workshop für alle, die einige der in diesem Leitfaden beschriebenen Dinge üben wollen.
Der Inhalt ist hier zu finden - https://github.com/antonbabenko/terraform-best-practices-workshop
Die offizielle Terraform-Dokumentation beschreibt alle Aspekte der Konfiguration im Detail. Lesen Sie sie sorgfältig, um den Rest dieses Abschnitts zu verstehen.
In diesem Abschnitt werden die wichtigsten Konzepte beschrieben, die in diesem Buch verwendet werden.
aws_vpc
, aws_db_instance
und andere sind Beispiele für Ressourcen. Eine Ressource gehört zu einem Provider, akzeptiert Argumente, gibt Attribute aus und hat Lebenszyklen. Eine Ressource kann erstellt, abgerufen, aktualisiert und gelöscht werden.
Ein Ressourcenmodul ist eine Sammlung zusammenhängender Ressourcen, die gemeinsam eine Aktion durchführen (z. B. erstellt das AWS VPC Terraform-Modul VPC, Subnetze, NAT-Gateway usw.). Es hängt von der Konfiguration des Providers ab, die darin oder in übergeordneten Strukturen (z. B. im Infrastrukturmodul) definiert werden kann.
Ein Infrastrukturmodul ist eine Sammlung von Ressourcenmodulen, die nicht zwingend logisch miteinander verbunden sein müssen, aber in der aktuellen Situation/im aktuellen Projekt/im aktuellen Setup demselben Zweck dienen. Es definiert die Konfiguration für Provider, die an die nachgelagerten Ressourcenmodule und an Ressourcen weitergegeben wird. Normalerweise ist die Arbeit auf eine Einheit pro logischer Begrenzung beschränkt (z. B. AWS Region, Google Project).
Das Modul terraform-aws-atlantis verwendet beispielsweise Ressourcenmodule wie terraform-aws-vpc und terraform-aws-security-group, um die für den Betrieb von Atlantis auf AWS Fargate erforderliche Infrastruktur zu verwalten.
Ein weiteres Beispiel ist das terraform-aws-cloudquery Modul, bei dem mehrere Module von terraform-aws-modules zusammen verwendet werden, um die Infrastruktur zu verwalten und Docker-Ressourcen zu nutzen, um Docker-Images zu erstellen, zu pushen und zu verteilen. Alles in einem Modul.
Eine Komposition ist eine Sammlung von Infrastrukturmodulen, die sich über mehrere logisch getrennte Bereiche erstrecken kann (z. B. AWS-Regionen, mehrere AWS-Konten). Eine Komposition wird verwendet, um die komplette Infrastruktur zu beschreiben, die für das gesamte Unternehmen oder Projekt erforderlich ist.
Eine Komposition besteht aus Infrastrukturmodulen, die aus Ressourcenmodulen bestehen, die einzelne Ressourcen implementieren.
Eine Datenquelle führt einen Lese-Vorgang durch und ist abhängig von der Konfiguration des Providers; sie wird in einem Ressourcenmodul und einem Infrastrukturmodul verwendet.
Die Datenquelle terraform_remote_state
dient als Bindeglied für übergeordnete Module und Kompositionen.
Die externe Datenquelle ermöglicht es einem externen Programm, als Datenquelle zu fungieren und beliebige Daten zur Verwendung in der Terraform-Konfiguration freizugeben. Hier ist ein Beispiel aus dem terraform-aws-lambda Modul, bei dem der Dateiname durch den Aufruf eines externen Python-Skripts berechnet wird.
Die http-Datenquelle führt eine HTTP-GET-Anfrage an die angegebene URL durch und exportiert Informationen über die Antwort, was oft nützlich ist, um Informationen von Endpunkten zu erhalten, für die kein eigener Terraform-Provider existiert.
Infrastrukturmodule und Kompositionen sollten ihren Terraform-Status an einem entfernten Ort aufbewahren, wo er von anderen kontrolliert (z.B. mittels ACL, Versionierung und Logging) abgerufen werden kann.
Provider, Provisioner und einige andere Begriffe sind in der offiziellen Dokumentation sehr gut beschrieben und es macht keinen Sinn, sie hier zu wiederholen. Meiner Meinung nach haben sie wenig mit dem Schreiben guter Terraform-Module zu tun.
Während einzelne Ressourcen wie Atome in der Infrastruktur sind, sind Ressourcenmodule Moleküle. Ein Modul ist die kleinste versionierte und gemeinsam nutzbare Einheit. Es hat eine genaue Liste von Argumenten und implementiert die grundlegende Logik für eine solche Einheit, um die erforderliche Funktion auszuführen. Beispielsweise erstellt das terraform-aws-security-group Modul aws_security_group
und aws_security_group_rule
Ressourcen basierend auf der Eingabe. Dieses Ressourcenmodul selbst kann zusammen mit anderen Modulen verwendet werden, um das Infrastrukturmodul zu erstellen.
Der übergreifende Zugriff auf die Daten einzelner Moleküle (Ressourcenmodule und Infrastrukturmodule) erfolgt über die Ausgaben und Datenquellen der Module.
Der Zugriff zwischen Kompositionen erfolgt häufig über Remote state Datenquellen. Für die gemeinsame Nutzung von Daten zwischen Konfigurationen gibt es mehrere Möglichkeiten.
Wenn man die oben beschriebenen Konzepte in Pseudo-Beziehungen zueinander setzt, kann das so aussehen:
Dieses Dokument ist ein Versuch, die besten Praktiken bei der Verwendung von Terraform systematisch zu beschreiben und Empfehlungen für die häufigsten Probleme zu geben.
Terraform ist ein relativ neues Projekt (wie die meisten DevOps-Tools), das 2014 gestartet wurde.
Terraform ist leistungsfähig (wenn nicht sogar das leistungsfähigste, das es derzeit gibt) und eines der am häufigsten verwendeten Tools, das die Verwaltung der Infrastruktur als Code ermöglicht. Es erlaubt Entwicklern eine Menge Dinge zu tun und schränkt sie nicht ein, Dinge zu tun, die schwer zu unterstützen oder zu integrieren sind.
Einige der in diesem Buch beschriebenen Informationen mögen nicht als die besten Praktiken erscheinen. Ich weiß das, und um den Lesern zu helfen, zu unterscheiden, was bewährte Praktiken sind und was nur eine andere Art ist, Dinge zu tun, verwende ich manchmal Hinweise, um etwas Kontext zu liefern, und Symbole, um den Reifegrad jedes Unterabschnitts in Bezug auf bewährte Praktiken anzugeben.
Das Buch ist 2018 im sonnigen Madrid entstanden und ist hier kostenlos erhältlich - https://www.terraform-best-practices.com/ .
Ein paar Jahre später wurde es mit mehr aktuellen Best Practices aktualisiert, die mit Terraform 1.0 verfügbar waren. Letztendlich sollte dieses Buch die meisten der unbestrittenen besten Praktiken und Empfehlungen für Terraform-Nutzer enthalten.
Please contact me if you want to become a sponsor.