Wie man Flexibilität mit Terraform-Variablen, Abhängigkeiten und Bedingungen verbessern kann

Die Hashicorp Configuration Language (HCL), die Terraform verwendet, bietet viele nützliche Strukturen und Fähigkeiten, die in anderen Programmiersprachen vorhanden sind. Die Verwendung von Schleifen in Ihrer Infrastrukturcode kann die Code-Wiederholung erheblich reduzieren und die Lesbarkeit erhöhen, was eine einfache zukünftige Refaktorisierung und größere Flexibilität ermöglicht. HCL bietet auch einige gängige Datenstrukturen, wie Listen und Maps (die in anderen Sprachen auch als Arrays und Wörterbücher bezeichnet werden), sowie bedingte Anweisungen für die Verzweigung des Ausführungspfades.

Einzigartig bei Terraform ist die Möglichkeit, Ressourcen manuell festzulegen, von denen man abhängt. Während der Ausführungsgraph, den es beim Ausführen Ihres Codes erstellt, bereits die erkannten Verbindungen enthält (die in den meisten Szenarien korrekt sind), können Sie sich in die Lage versetzt finden, eine Abhängigkeitsbeziehung zu erzwingen, die Terraform nicht erkennen konnte.

In diesem Artikel werfen wir einen Blick auf die Datenstrukturen, die HCL bietet, ihre Schleifenfunktionen für Ressourcen (den count-Schlüssel, for_each und for), Bedingungen zur Handhabung von bekannten und unbekannten Werten sowie Abhängigkeitsbeziehungen zwischen Ressourcen.

Voraussetzungen

  • Ein DigitalOcean Personal Access Token, das Sie über die DigitalOcean-Kontrollpanel erstellen können. Sie finden Anleitungen in den DigitalOcean-Produktdokumenten unter How to Create a Personal Access Token.
  • Terraform installiert auf Ihrem lokalen Computer und ein Projekt mit dem DigitalOcean-Provider eingerichtet. Führen Sie die Schritte 1 und Schritt 2 der How To Use Terraform with DigitalOcean-Anleitung aus und sorgen Sie dafür, dass der Projektordner terraform-flexibility heißt, anstatt loadbalance. Während Schritt 2 haben Sie nicht die Variable pvt_key und die Ressource für den SSH-Key bei der Konfiguration des Providers einzubeziehen.

Hinweis: Diese Anleitung wurde speziell mit Terraform 1.0.2 getestet.

Datentypen in HCL

Bevor Sie mehr über Schleifen und andere Funktionen von HCL lernen, die Ihre Code flexibel machen, erfahren Sie zuerst mehr über die verfügbaren Datentypen und ihre Verwendung.

Die Hashicorp Configuration Language unterstützt primitive und komplexe Datentypen. Primitive Datentypen sind Strings, Zahlen und boolesche Werte, die grundlegenden Typen, die nicht von anderen abgeleitet werden können. Komplexe Typen, im Gegensatz dazu, gruppen mehrere Werte in einem einzigen zusammen. Die zwei Typen komplexer Werte sind strukturale und sammlungselementare Typen. Die strukturale Typen erlauben, dass Werte unterschiedlicher Typen in einer einzelnen Gruppe zusammengefasst werden. Der Hauptbeispiel ist die Ressourcendefinition, die Sie verwenden, um zu bestimmen, wie ihr Infrastrukturaussehen wird. Im Vergleich zu den strukturalelementaren Typen, unterstützen auch die Sammlungstypen eine Gruppierung von Werten, allerdings nur von gleichen Typen. Die drei Sammlungstypen, die wir uns hier ansehen sollen, sind Listen, Maps und Sets.

Listen

.

Listen sind ähnlich zu Arrays in anderen Programmiersprachen. Sie enthalten einen bekannten Anzahl an Elementen des gleichen Typs, die über das Array-Notation ([]) mit ihrem ganzzahligen Index, beginnend von 0, zugänglich gemacht werden können. Hier ist ein Beispiel für die Deklaration einer Listenvariable, die die Namen der Dropletts festlegt, die Sie in den nächsten Schritten deployen werden:

variable "droplet_names" {
  type    = list(string)
  default = ["first", "second", "third"]
}

Für den type, hast du spezifiziert, dass es sich bei dem Elementtyp um einen String handelt, und dann deine default Werte gegeben. In HCL bedeuten Werte in Klammern eine Liste.

Maps

Karten sind Sammlungen von Schlüssel-Wert-Paaren, bei denen jeder Wert über seinen Schlüssel vom Typ string zugegriffen wird. Es gibt zwei Möglichkeiten, Karten innerhalb von Schrägstrich-Zeichenketten anzugeben: durch Verwendung von Doppelpunkten (:) oder gleichheitszeichen (=) zum Festlegen von Werten. In beiden Fällen muss der Wert in Anführungszeichen eingeschlossen werden. Bei Verwendung von Doppelpunkten muss der Schlüssel ebenfalls eingeschlossen werden.

Die folgende Kartendefinition, die Droplet-Namen für verschiedene Umgebungen enthält, wird mit dem gleichheitszeichen geschrieben:

variable "droplet_env_names" {
  type = map(string)

  default = {
    development = "dev-droplet"
    staging = "staging-droplet"
    production = "prod-droplet"
  }
}

Wenn der Schlüssel mit einer Zahl beginnt, müssen Sie die Doppelpunktsyntax verwenden:

variable "droplet_env_names" {
  type = map(string)

  default = {
    "1-development": "dev-droplet"
    "2-staging": "staging-droplet"
    "3-production": "prod-droplet"
  }
}

Sets

Sets unterstützen keine Elementordnung, was bedeutet, dass das Durchlaufen von Sets nicht gewährleistet ist, dass dieselbe Reihenfolge jedes Mal gleich ist und dass ihre Elemente nicht in einer zielgerichteten Weise zugegriffen werden können. Sie enthalten eindeutige Elemente, die exakt einmal wiederholt sind, und das mehrfache Festlegen des gleichen Elements führt dazu, dass sie mit nur einer Instanz kohäsiert werden und nur eine Instanz im Set vorhanden ist.

Die Deklaration einer Sammlung ähnelt der Deklaration einer Liste, der einzige Unterschied besteht in dem Typ der Variable:

variable "droplet_names" {
  type    = set(string)
  default = ["first", "second", "third", "fourth"]
}

Nachdem Sie erfahren haben, um welche Datenstrukturen HCL zu bieten und die Syntax von Listen, Karten und Sets überprüft haben, die wir im gesamten Tutorial verwenden, geht es nun darum, flexible Möglichkeiten zu erforschen, um mehrere Instanzen des gleichen Ressourcen in Terraform zu deployieren.

Die Anzahl der Ressourcen mit dem Schlüssel „count“ festlegen

In diesem Abschnitt erstellen Sie mehrere Instanzen derselben Ressource, indem Sie den Schlüssel count verwenden. Der count-Schlüssel ist ein Parameter, der auf allen Ressourcen verfügbar ist und speziell die Anzahl der zu erstellenden Instanzen angeben.

Sie sehen, wie es funktioniert, indem Sie einen Droplet-Ressourcen schreiben, die Sie in einem Datei namens droplets.tf in dem Projektordner schreiben, den Sie als Teil der Voraussetzungen erstellt haben. Erstellen und öffnen Sie sie für die Bearbeitung durch folgendes ausführen:

  1. nano droplets.tf

Fügen Sie die folgenden Zeilen hinzu:

terraform-flexibility/droplets.tf
resource "digitalocean_droplet" "test_droplet" {
  count  = 3
  image  = "ubuntu-20-04-x64"
  name   = "web"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

Dieser Code definiert eine Droplet-Ressourcen namens test_droplet, die Ubuntu 20.04 läuft mit 1GB RAM und einem CPU-Kern.

Beachten Sie, dass der Wert von count auf 3 gesetzt ist, was bedeutet, dass Terraform versucht, drei Instanzen dieselbe Ressource zu erstellen. Wenn Sie fertig sind, speichern und schließen Sie die Datei.

Sie können das Projekt planen, um zu sehen, welche Aktionen Terraform unternehmen würde, indem Sie folgendes ausführen:

  1. terraform plan -var "do_token=${DO_PAT}"

Die Ausgabe wird ähnlich sein:

Output
... Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: digitalocean_droplet.test_droplet[0] will be created + resource "digitalocean_droplet" "test_droplet" { ... name = "web" ... } digitalocean_droplet.test_droplet[1] will be created + resource "digitalocean_droplet" "test_droplet" { ... name = "web" ... } digitalocean_droplet.test_droplet[2] will be created + resource "digitalocean_droplet" "test_droplet" { ... name = "web" ... } Plan: 3 to add, 0 to change, 0 to destroy. ...

Die Ausgabe der Terraform werde drei Instanzen von test_droplet erstellen, alle mit dem gleichen Namen web. Obwohl möglich, ist es nicht empfohlen, daher modifizieren wir die Definition des Droplet, um den Namen jeder Instanz einzigartig zu machen. Öffnen Sie droplets.tf für Bearbeitung:

  1. nano droplets.tf

Modifizieren Sie die unterstrichene Zeile:

terraform-flexibility/droplets.tf
resource "digitalocean_droplet" "test_droplet" {
  count  = 3
  image  = "ubuntu-20-04-x64"
  name   = "web.${count.index}"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

Speichern und schließen Sie das Datei.

Die count-Objekt gibt das index-Parameter an, das die aktuelle Iterationszahl startet, beginnend mit 0. Die aktuelle Index wird in den Namen des Droplets als String-Interpolation verwendet, was dir erlaubt, einen dynamischen String zu bilden, indem du Variablen einfügen kannst. Du kannst das Projekt nochmals planen, um die Änderungen zu sehen:

  1. terraform plan -var "do_token=${DO_PAT}"

Die Ausgabe wird ähnlich sein:

Output
... Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # digitalocean_droplet.test_droplet[0] wird erstellt + resource "digitalocean_droplet" "test_droplet" { ... name = "web.0" ... } # digitalocean_droplet.test_droplet[1] wird erstellt + resource "digitalocean_droplet" "test_droplet" { ... name = "web.1" ... } # digitalocean_droplet.test_droplet[2] wird erstellt + resource "digitalocean_droplet" "test_droplet" { ... name = "web.2" ... } Plan: 3 to add, 0 to change, 0 to destroy. ...

Diesmal werden die drei Instanzen von test_droplet ihren Index in ihren Namen haben, damit sie leichter zu tracken sind.

Sie kennen jetzt die Methode, wie du mehrere Instanzen einer Ressource mit Hilfe des count-Key erstellen kannst sowie wie du eine Zahl aus einer Liste abfragen kannst. In der nächsten Schritt lernst du, wie du den Droplet-Namen aus einer Liste abfragen kannst.

Die Namen der Dropletten aus einer Liste abrufen

In Situationen, in denen mehrere Instanzen des gleichen Ressourcens benötigt werden, die benutzerdefinierten Namen haben, können Sie sie dynamisch aus einer Listenvariable abrufen, die Sie definieren. Im Rest dieser Tutorials zeigen wir dir mehrere Wege, wie du Droplet-Deployments von einer Liste namens automatisierst, um Flexibilität und Einfachheit zu gewähren.

Sie müssen zunächst eine Datei erstellen, die variables.tf heißt und sie öffnen, um sie zu bearbeiten:

  1. nano variables.tf

Fügen Sie folgende Zeilen hinzu:

terraform-flexibility/variables.tf
variable "droplet_names" {
  type    = list(string)
  default = ["first", "second", "third", "fourth"]
}

Speichern und schließen Sie die Datei. Dieser Code definiert eine Liste namens droplet_names, die die Zeichenketten first, second, third, und fourth enthält.

Öffnen Sie droplets.tf für die Bearbeitung:

  1. nano droplets.tf

Modifizieren Sie die hellgrau unterstrichenen Zeilen:

terraform-flexibility/droplets.tf
resource "digitalocean_droplet" "test_droplet" {
  count  = length(var.droplet_names)
  image  = "ubuntu-20-04-x64"
  name   =  var.droplet_names[count.index]
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

Zum verbessern der Flexibilität stattdessen manuell einen konstanten Wert an die count Parameter zu übergeben, der immer den Wert der droplet_names Liste zurückgibt, indem Sie die Array-Brackets verwenden. Für den Namen holen Sie das Element der Liste ab, dessen Position count.index ist. Speichern und schließen Sie die Datei, wenn du fertig bist.

Probieren Sie das Projekt erneut. Sie erhalten Ausgaben ähnlich zu dieser:

Output
... Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: Eine neue DigitalOcean-Droplett wird erstellt. + resource "digitalocean_droplet" "test_droplet" { ... + name = "first" ... } Eine zweite neue DigitalOcean-Droplett wird erstellt. + resource "digitalocean_droplet" "test_droplet" { ... + name = "second" ... } Eine dritte neue DigitalOcean-Droplett wird erstellt. + resource "digitalocean_droplet" "test_droplet" { ... + name = "third" ... } Eine vierte neue DigitalOcean-Droplett wird erstellt. + resource "digitalocean_droplet" "test_droplet" { ... + name = "fourth" ... Plan: 4 to add, 0 to change, 0 to destroy. ...

Aus diesen Modifikationen resultieren vier Droplet-Instanzen, die nach den Elementen der droplet_names-Liste sequenzielle Namen bekommen sollen.

Sie haben gelernt, wie man count verwendet, seine Eigenschaften und Syntax kennengelernt und sie zusammen mit einer Liste zur Modifikation von Ressourceninstanzen verwendet. Sie werden jetzt sehen, welche Nachteile es hat, und wie du sie überwindest.

Die Disadvantagen des count verstehen

Nachdem Sie wiederum die Verwendung von count kennengelernt haben, lassen sich seine Disadvantagen bei der Modifikation der Liste unterstützen durch einmalige Anpassungen festmachen.

Lass uns nun versuchen, die Droplets in die Cloud zu deployen:

  1. terraform apply -var "do_token=${DO_PAT}"

Antworten Sie auf die Frage mit Ja. Das Ende Ihres Outputs sieht ähnlich zu diesem aus:

Output
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Nun erstellen wir noch eine weitere Droplet-Instanz, indem wir die droplet_names-Liste vergrößern. Öffnen Sie variables.tf für Bearbeitung:

  1. nano variables.tf

Fügen Sie einen neuen Element an den Beginn der Liste hinzu:

terraform-flexibility/variables.tf
variable "droplet_names" {
  type    = list(string)
  default = ["zero", "first", "second", "third", "fourth"]
}

Wenn Sie fertig sind, speichern und schließen Sie das Datei.

Plan der Projektentwicklung:

  1. terraform plan -var "do_token=${DO_PAT}"

Sie erhalten eine Ausgabe wie diese:

Output
... Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create ~ update in-place Terraform will perform the following actions: # digitalocean_droplet.test_droplet[0] wird in-place updatet ~ resource "digitalocean_droplet" "test_droplet" { ... ~ name = "first" -> "zero" ... } # digitalocean_droplet.test_droplet[1] wird in-place updatet ~ resource "digitalocean_droplet" "test_droplet" { ... ~ name = "second" -> "first" ... } # digitalocean_droplet.test_droplet[2] wird in-place updatet ~ resource "digitalocean_droplet" "test_droplet" { ... ~ name = "third" -> "second" ... } # digitalocean_droplet.test_droplet[3] wird in-place updatet ~ resource "digitalocean_droplet" "test_droplet" { ... ~ name = "fourth" -> "third" ... } # digitalocean_droplet.test_droplet[4] wird erstellt + resource "digitalocean_droplet" "test_droplet" { ... + name = "fourth" ... } Plan: 1 to add, 4 to change, 0 to destroy. ...

Die Ausgabe zeigt, dass Terraform die ersten vier Droplets umbenennen und einen fünften neuen Droplet namens vierter erstellen würde, weil es die Elemente (Droplets) als eine sortierte Liste mit Indexnummern interpretiert. So ist das, wie Terraform die vier zuerst anfänglich behandelt hat:

Index Number 0 1 2 3
Droplet Name first second third fourth

Wenn der neue Droplet zero am Anfang hinzugefügt wird, sieht seine internen Listenrepräsentation so aus:

Index Number 0 1 2 3 4
Droplet Name zero first second third fourth

Die vier initialen Droplets sind nun um einen Platz nach rechts verschoben. Terraform vergleicht dann die beiden durch Tabelle repräsentierten Zustände: an Position 0, der Droplet war erster, und weil es im zweiten Tabelleneintrag unterschiedlich ist, plant es eine Aktion zum Update. Dies setzt sich fort bis zur Position 4, die keinem Element in der ersten Tabelle entsprechend ist, sondern stattdessen eine Droplet-Provisionierungsvorrichtung planen sollte.

Dies bedeutet, dass die Liste nicht an einer beliebigen Stelle außer am Ende einem neuen Element hinzugefügt wird, sondern es zu Ressourcenmodifikationen kommt, wenn sie nicht notig sind. Die gleichen Aktionen zur Updates werden auch planen, wenn ein Element der droplet_names-Liste entfernt wird.

Die Hauptvorteil von count ist, dass sie bei konstantem Anzahl und konstantem Typ gleichartiger Ressourcen eine einfach funktionierende Lösung ist. Bei Situationen, in denen Attribute aus Variablen zugewiesen werden, die vom selben Ressourcentyp abhängen, ist jedoch der später in diesem Tutorial erlernte for_each-Loop eine viel bessere Wahl.

Zu Referenzieren des aktuellen Ressourcenelements (self)

Eine weitere Nachteile von count ist, dass man in bestimmten Fällen nicht auf einen beliebigen Index eines beliebigen Objekts innerhalb der Ressourceliste zugreifen kann.

Der größte Fall ist destroy-time provisioners, bei denen das gewünschte Objekt nicht mehr existiert (es ist schon gelöscht) oder würde zu einem mutuelleren Abhängigkeitszyklus führen. In solchen Situationen können Sie nur über das self-Keyword auf die aktuelle Ressource zugreifen.

Um seine Nutzung zu demonstrieren, fügen Sie jetzt einen lokalen Provisioner für die Definition test_droplet hinzu, der bei der Ausführung eine Nachricht ausgibt. Öffnen Sie droplets.tf für die Bearbeitung:

  1. nano droplets.tf

Fügen Sie die folgenden hervorgehobenen Zeilen ein:

terraform-flexibility/droplets.tf
resource "digitalocean_droplet" "test_droplet" {
  count  = length(var.droplet_names)
  image  = "ubuntu-20-04-x64"
  name   =  var.droplet_names[count.index]
  region = "fra1"
  size   = "s-1vcpu-1gb"

  provisioner "local-exec" {
    when    = destroy
    command = "echo 'Droplet ${self.name} is being destroyed!'"
  }
}

Speichern und schließen Sie das Datei.

Der local-exec Provisioner läuft auf dem lokalen Maschinen unter Terraform aus. Da der Parameter when auf destroy gesetzt ist, wird er nur dann ausgeführt, wenn das Ressourcenelement gelöscht werden soll. Die angegebene Befehlssatz ruft einen Befehl auf der lokalen Maschine aus, der durch den Wert von self.name ersetzt wird.

Da Sie in einem späteren Abschnitt die Dropletts in einer anderen Weise erstellen werden, löschen Sie die momentan deployierten Dropletts, indem Sie die folgende Befehle ausführen:

  1. terraform destroy -var "do_token=${DO_PAT}"

Geben Sie ja an, wenn Sie darauf gefragt werden. Sie erhalten vier Mal die Ausführung des local-exec Provisioners:

Output
... digitalocean_droplet.test_droplet[0] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet first is being destroyed!'"] digitalocean_droplet.test_droplet[1] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet second is being destroyed!'"] digitalocean_droplet.test_droplet[1] (local-exec): Droplet second is being destroyed! digitalocean_droplet.test_droplet[2] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet third is being destroyed!'"] digitalocean_droplet.test_droplet[2] (local-exec): Droplet third is being destroyed! digitalocean_droplet.test_droplet[3] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet fourth is being destroyed!'"] digitalocean_droplet.test_droplet[3] (local-exec): Droplet fourth is being destroyed! digitalocean_droplet.test_droplet[0] (local-exec): Droplet first is being destroyed! ...

Im letzten Abschnitt haben Sie erfahren, welche Disadvantagen die count-Konstruktion hat. Sie lernen nun das for_each-Loop-Konstrukt kennen, das sie überwindet und mehrflexibel ist, wenn Sie Ressourcen mit mehreren Instanzen definieren.

Looping Using for_each

In diesem Abschnitt werden Sie das Syntax des for_each-Loops betrachten, seine Anwendungsmöglichkeiten sowie wie es helfen kann, Flexibilität zu gewinnen, wenn Sie Ressourcen mit mehreren Instanzen definieren.

for_each ist ein auf jeder Ressource verfügbares Parameter, aber im Gegensatz zu count, welches die Anzahl der zu erstellenden Instanzen benötigt, akzeptiert for_each eine Map oder ein Set. Jedes Element der bereitgestellten Sammlung wird einmal durchlaufen und für es wird eine Instanz erstellt. for_each macht den Schlüssel und den Wert unter dem Schlüsselwort each als Attribute verfügbar (das Schlüssel-Wert-Paar als each.key und each.value). Wenn ein Set bereitgestellt wird, sind der Schlüssel und der Wert identisch.

Da es das aktuelle Element im each-Objekt bereitstellt, müssen Sie nicht manuell auf das gewünschte Element zugreifen, wie Sie es bei Listen mussten. Bei Sets ist das sogar nicht möglich, da sie intern keine beobachtbare Ordnung haben. Listen können auch übergeben werden, müssen jedoch zuerst mit der Funktion toset in ein Set umgewandelt werden.

Der Hauptvorteil der Verwendung von for_each, abgesehen davon, dass alle drei Sammlungsdatentypen aufgezählt werden können, ist, dass nur die betroffenen Elemente geändert, erstellt oder gelöscht werden. Wenn Sie die Reihenfolge der Elemente in der Eingabe ändern, werden keine Aktionen geplant, und wenn Sie ein Element aus der Eingabe hinzufügen, entfernen oder ändern, werden nur für dieses Element geeignete Aktionen geplant.

Lassen Sie uns die Droplet-Ressource von count zu for_each umwandeln und sehen, wie sie in der Praxis funktioniert. Öffnen Sie droplets.tf zur Bearbeitung, indem Sie ausführen:

  1. nano droplets.tf

Verändern Sie die hervorgehobenen Zeilen:

terraform-flexibility/droplets.tf
resource "digitalocean_droplet" "test_droplet" {
  for_each = toset(var.droplet_names)
  image    = "ubuntu-20-04-x64"
  name     = each.value
  region   = "fra1"
  size     = "s-1vcpu-1gb"
}

Sie können den local-exec-Provisioner entfernen. Wenn Sie fertig sind, speichern und schließen Sie die Datei.

Die erste Zeile ersetzt count und ruft for_each auf, wobei die Liste droplet_names in Form eines Sets mit der Funktion toset übergeben wird, die automatisch die angegebene Eingabe konvertiert. Für den Droplet-Namen geben Sie each.value an, das den Wert des aktuellen Elements aus dem Set der Droplet-Namen enthält.

Planen Sie das Projekt, indem Sie ausführen:

  1. terraform plan -var "do_token=${DO_PAT}"

Die Ausgabe wird detaillierte Schritte beschreiben, die Terraform ausführen würde:

Output
... Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # digitalocean_droplet.test_droplet["first"] wird erstellt + resource "digitalocean_droplet" "test_droplet" { ... + name = "first" ... } # digitalocean_droplet.test_droplet["fourth"] wird erstellt + resource "digitalocean_droplet" "test_droplet" { ... + name = "fourth" ... } # digitalocean_droplet.test_droplet["second"] wird erstellt + resource "digitalocean_droplet" "test_droplet" { ... + name = "second" ... } # digitalocean_droplet.test_droplet["third"] wird erstellt + resource "digitalocean_droplet" "test_droplet" { ... + name = "third" ... } # digitalocean_droplet.test_droplet["zero"] wird erstellt + resource "digitalocean_droplet" "test_droplet" { ... + name = "zero" ... } Plan: 5 to add, 0 to change, 0 to destroy. ...

Im Gegensatz zur Verwendung von count betrachtet Terraform jetzt jede Instanz individuell und nicht als Elemente einer geordneten Liste. Jede Instanz ist mit einem Element des gegebenen Sets verknüpft, wie das in den Klammern neben jeder Ressource, die erstellt wird, angezeigte Zeichenkettenelement zeigt.

Wenden Sie den Plan auf die Cloud an, indem Sie ausführen:

  1. terraform apply -var "do_token=${DO_PAT}"

Geben Sie bei der Aufforderung yes ein. Wenn es abgeschlossen ist, entfernen Sie ein Element aus der Liste droplet_names, um zu demonstrieren, dass andere Instanzen nicht betroffen sind. Öffnen Sie variables.tf zur Bearbeitung:

  1. nano variables.tf

Ändern Sie die Liste, damit sie wie folgt aussieht:

terraform-flexibility/variables.tf
variable "droplet_names" {
  type    = list(string)
  default = ["first", "second", "third", "fourth"]
}

Speichern Sie die Datei und schließen Sie sie.

Planen Sie das Projekt erneut, und Sie erhalten die folgende Ausgabe:

Output
... Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: - destroy Terraform will perform the following actions: # digitalocean_droplet.test_droplet["zero"] wird gelöscht - resource "digitalocean_droplet" "test_droplet" { ... - name = "zero" -> null ... } Plan: 0 to add, 0 to change, 1 to destroy. ...

Dieses Mal würde Terraform nur die entfernte Instanz (zero) löschen und keine der anderen Instanzen berühren, was das korrekte Verhalten ist.

In diesem Schritt haben Sie etwas über for_each gelernt, wie man es verwendet und seine Vorteile gegenüber count. Als Nächstes erfahren Sie über die for-Schleife, ihre Syntax und Verwendung und wann sie zum Automatisieren bestimmter Aufgaben verwendet werden kann.

Schleifen mit for

Die for-Schleife funktioniert auf Sammlungen und erstellt eine neue Sammlung, indem sie eine Transformation auf jedes Element der Eingabe anwendet. Der genaue Typ der Ausgabe hängt davon ab, ob die Schleife von Klammern ([]) oder geschweiften Klammern ({}) umgeben ist, die eine Liste oder eine Karteikarte geben. Daher ist sie geeignet, Ressourcen abzufragen und strukturierte Ausgaben für die spätere Verarbeitung zu bilden.

Die allgemeine Syntax der for-Schleife ist:

for element in collection:
transform(element)
if condition

Ähnlich wie bei anderen Programmiersprachen geben Sie zuerst den Laufvariablen Namen (element) an und legen die collection fest, die durchgezählt werden soll. Der Körper der Schleife ist der transformatorische Schritt, und die optionale if-Klausel kann zur Filterung der Eingabesammlung verwendet werden.

Sie werden nun einige Beispiele mit Ausgaben durchgehen. Sie speichern sie in einer Datei namens outputs.tf. Erstellen Sie sie zum Bearbeiten, indem Sie den folgenden Befehl ausführen:

  1. nano outputs.tf

Fügen Sie die folgenden Zeilen hinzu, um Paare aus部署 Droplet-Namen und deren IP-Adressen auszugeben:

terraform-flexibility/outputs.tf
output "ip_addresses" {
  value = {
    for instance in digitalocean_droplet.test_droplet:
    instance.name => instance.ipv4_address
  }
}

Dieser Code legt eine Ausgabe namens ip_addresses fest und gibt eine for-Schleife an, die über die Instanzen der test_droplet-Ressource iteriert, die Sie in den vorherigen Schritten angepasst haben. Da die Schleife von geschweiften Klammern umgeben ist, wird ihre Ausgabe eine Karte. Der transformatorische Schritt für Karten ist ähnlich wie lambda-Funktionen in anderen Programmiersprachen, und hier erstellt er ein Schlüssel-Wert-Paar, indem er den Instanznamen als Schlüssel mit seiner privaten IP als Wert kombiniert.

Speichern Sie die Datei und schließen Sie sie, dann aktualisieren Sie den Terraform-Status, um die neue Ausgabe zu berücksichtigen, indem Sie ausführen:

  1. terraform refresh -var "do_token=${DO_PAT}"

Der Terraform-Befehl refresh aktualisiert den lokalen Status mit dem tatsächlichen Infrastrukturstatus in der Cloud.

Dann überprüfen Sie den Inhalt der Ausgaben:

Output
ip_addresses
= { "first" = "ip_address" "fourth" = "ip_address" "second" = "ip_address" "third" = "ip_address" }

Terraform hat den Inhalt der Ausgabe ip_addresses angezeigt, das eine durch den for-Schleif konstruierte Map ist. (Die Reihenfolge der Einträge kann für Sie unterschiedlich sein.) Der Schleif funktioniert problemlos für jede Anzahl von Einträgen – das bedeutet, dass Sie ein neues Element zur Liste droplet_names hinzufügen können, und der neue Droplet, der ohne weitere manuelle Eingabe erstellt wird, erscheint ebenfalls in dieser Ausgabe automatisch.

Indem Sie den for-Schleif in eckige Klammern setzen, können Sie die Ausgabe in eine Liste verwandeln. Zum Beispiel könnten Sie nur Droplet-IP-Adressen ausgeben, was für externe Software, die die Daten parses, nützlich ist. Der Code würde so aussehen:

terraform-flexibility/outputs.tf
output "ip_addresses" {
  value = [
    for instance in digitalocean_droplet.test_droplet:
    instance.ipv4_address
  ]
}

Hier wählt der transformatorische Schritt das Attribut der IP-Adresse aus. Es würde die folgende Ausgabe geben:

Output
ip_addresses
= [ "ip_address", "ip_address", "ip_address", "ip_address", ]

Wie bereits erwähnt, können Sie auch die Eingabesammlung mit der if-Klausel filtern. So schreiben Sie den Schleif, um nach der fra1-Region zu filtern:

terraform-flexibility/outputs.tf
output "ip_addresses" {
  value = [
    for instance in digitalocean_droplet.test_droplet:
    instance.ipv4_address
    if instance.region == "fra1"
  ]
}

In HCL überprüft der ==-Operator die Gleichheit der Werte auf beiden Seiten – hier überprüft er, ob instance.region gleich fra1 ist. Wenn dem so ist, Bestanden die Überprüfung und der instance wird transformiert und zur Ausgabe hinzugefügt, andernfalls wird er übersprungen. Die Ausgabe dieses Codes wäre die gleiche wie im vorherigen Beispiel, da alle Droplet-Instanzen laut Definition der Ressource test_droplet in der fra1-Region sind. Die if-Bedingung ist auch nützlich, wenn Sie die Eingabesammlung für andere Werte in Ihrem Projekt filtern möchten, wie z.B. die Größe oder die Distribution des Droplets.

Weil Sie in dem nächsten Abschnitt Ressourcen unterschiedlich erstellen werden, zerstören Sie die derzeit bereitgestellten Ressourcen, indem Sie den folgenden Befehl ausführen:

  1. terraform destroy -var "do_token=${DO_PAT}"

Geben Sie yes ein, wenn Sie dazu aufgefordert werden, den Prozess abzuschließen.

Wir haben den for-Schleifen, seine Syntax und Beispiele für die Verwendung in Ausgaben behandelt. Sie werden nun über Bedingungen und deren Verwendung zusammen mit count lernen.

Direktiven und Bedingungen

In einem der vorherigen Abschnitte haben Sie den Schlüssel count und dessen Funktion gesehen. Sie werden nun über ternäre Bedingungsoperatoren lernen, die Sie an anderer Stelle in Ihrem Terraform-Code verwenden können und wie sie mit count zusammengewirkt werden können.

Die Syntax des ternären Operators ist:

condition ? value_if_true : value_if_false

Bedingung ist ein Ausdruck, der auf einen booleschen Wert (wahr oder falsch) berechnet. Wenn die Bedingung wahr ist, wird der Ausdruck auf Wert_wenn_wahr ausgewertet. Andernfalls wird das Ergebnis Wert_wenn_falsch sein.

Der Hauptzweck von ternären Operatoren ist es, das Erstellen einzelner Ressourcen je nach Inhalt einer Variablen zu aktivieren oder zu deaktivieren. Dies kann erreicht werden, indem das Ergebnis der Vergleichs (entweder 1 oder 0) an den Schlüssel count der gewünschten Ressource übergeben wird.

Um eine einzelne Element aus einer Liste oder einem Set mit dem Ternaren Operator zu erhalten, kann die Funktion one verwendet werden. Wenn die gegebenen Collection leer ist, liefert sie null. Ansonsten gibt sie das einzige Element in der Collection zurück, oder wirft einen Fehler, falls mehr als ein Element vorhanden sind.

Lass uns den Variable namens create_droplet hinzufügen, der kontrolliert ob ein Droplet erstellt wird. Erst öffnen Sie variables.tf für Bearbeitung:

  1. nano variables.tf

Fügen Sie die hervorgehobenen Zeilen hinzu:

terraform-flexibility/variables.tf
variable "droplet_names" {
  type    = list(string)
  default = ["first", "second", "third", "fourth"]
}

variable "create_droplet" {
  type = bool
  default = true
}

Diese Code definiert die Variable create_droplet vom Typ bool. Speichern und schließen Sie die Datei.

Danach, um die Droplet-Anmeldung zu modifizieren, öffnen Sie droplets.tf für Bearbeitung durch Ausführen:

  1. nano droplets.tf

Modifizieren Sie Ihr File wie folgt:

terraform-flexibility/droplets.tf
resource "digitalocean_droplet" "test_droplet" {
  count  = var.create_droplet ? 1 : 0
  image  = "ubuntu-20-04-x64"
  name   =  "test_droplet"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

Für count, verwenden Sie einen Ternaren Operator, um entweder 1 zu returnieren, wenn die create_droplet Variable true ist, oder 0 falls falsch, was bedeutet, dass keine Droplets provisioniert werden. Speichern und schließen Sie die Datei, nachdem du fertig ist.

Plan die Projektausführungsplan mit der Variablen festgelegt auf falsch durch Ausführen:

  1. terraform plan -var "do_token=${DO_PAT}" -var "create_droplet=false"

Sie erhalten die folgende Ausgabe:

Output
Changes to Outputs: + ip_addresses = {} You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.

weil create_droplet mit dem Wert von false übergeben wurde, ist die count der Instanzen 0, also werden keine Droplets erstellt, daher werden keine IP-Adressen ausgegeben.

Sie haben schon die Verwendung des Ternaren Conditional Operators mit dem Schlüssel count erlernt, um eine höhere Flexibilität zu gewähren, ob es sinnvoll ist, gewünschte Ressourcen zu deployieren. Nächstes Mal lernen Sie, wie Sie explizite Ressourcenabhängigkeiten für Ihre Ressourcen festlegen.

Explicitly Setting Resource Dependencies

Während der Erstellung des Ausführungsplanes für Ihr Projekt erkennt Terraform die Abhängigkeitsketten zwischen Ressourcen und ordnet sie automatisch so an, dass sie in der richtigen Reihenfolge gebaut werden. In den meisten Fällen kann Terraform durch das Scannen aller Expressiven in Ressourcen einen Graphen bilden und damit die Beziehungen selbst entdecken.

Aber wenn eine Ressource, um bereitgestellt zu werden, Zugriffssettings auf den Cloud-Provider benötigt, die schon部署 wurden, ist kein offensichtlicher Zeichen, dass sie sich im Verhalten abhängig sind. Im Gegensatz dazu wird Terraform nicht wissen, dass sie zusammenbehangen sind. Um solche Fallweise zu definieren, muss man die Abhängigkeit explizit mit dem Argument depends_on spezifizieren.

Der Schlüssel depends_on ist für jede Ressource verfügbar und wird zum Spezifizieren der verborgenen Abhängigkeitsverknüpfungen zwischen bestimmten Ressourcen verwendet. Verborgene Abhängigkeitsbeziehungen entstehen, wenn eine Ressource von einem anderen Ressourcen abhängig ist, ohne dessen Daten in ihrer Deklaration zu verwenden, was Terraform dazu bringen würde, sie einander einzuverbinden.

Hier ist ein Beispiel, wie depends_on in Code festgelegt wird:

resource "digitalocean_droplet" "droplet" {
  image  = "ubuntu-20-04-x64"
  name   = "web"
  region = "fra1"
  size   = "s-1vcpu-1gb"

  depends_on = [
    Ressourcen...
  ]
}

Es akzeptiert eine Liste von Referenzen zu anderen Ressourcen, und es akzeptiert keine beliebigen Ausdrücke.

depends_on sollte sparsam verwendet werden, und nur wenn alle anderen Optionen ausgeschöpft sind. Die Verwendung bedeutet, dass das, was Sie versuchen zu deklarieren, außerhalb der automatischen Abhängigkeitsdetektionssysteme von Terraform liegt; es kann bedeuten, dass die Ressource explizit mehr Ressourcen als sie benötigt ist abhängig ist.

Sie haben jetzt gelernt, wie Sie explizit zusätzliche Abhängigkeiten für eine Ressource mit dem Schlüssel depends_on festlegen können, und in welchen Fällen sie verwendet werden sollen.

Konklusion

In diesem Artikel haben wir über die Funktionen von HCL gesprochen, die die Flexibilität und Skalierbarkeit Ihres Codes verbessern, wie zum Beispiel count für die Angabe der Anzahl der zu deployenden Ressourceneinstanzen und for_each als ein fortgeschrittenes Werkzeug zur Schleife über Kollektionstypen und Custom-Einstanzen sowie die Personalisierung von Instanzen. Wenn sie richtig verwendet werden, reduzieren sie stark den operativen Overhead des Managements der bereitgestellten Infrastruktur.

Sie haben auch lernt, wie man Conditionals und Ternary Operators verwenden kann, und wie sie dazu genutzt werden, um zu bestimmen, ob eine Ressource部署 wird. Während das automatische Abhängigkeitsanalysensystem von Terraform sehr fähig ist, könnte es vorkommen, dass Sie manuelle Ressourcenabhängigkeiten mithilfe des Schlüssels depends_on spezifizieren müssen.

Dieses Tutorial ist Teil der How To Manage Infrastructure with Terraform-Serie. Die Serie deckt eine Reihe von Terraform-Themen ab, von der ersten Installation von Terraform bis hin zur Verwaltung komplexer Projekte.

Source:
https://www.digitalocean.com/community/tutorials/how-to-improve-flexibility-using-terraform-variables-dependencies-and-conditionals