Comment Améliorer la Flexibilité en Utilisant les Variables, les Dépendances et les Conditionnelles de Terraform

Introduction

Le Langage de Configuration de HashiCorp (HCL), utilisé par Terraform, offre de nombreuses structures et capacités utiles qui se retrouvent dans d’autres langages de programmation. L’utilisation de boucles dans votre code d’infrastructure permet de réduire considérablement le code en double et d’accroître la lisibilité, ce qui permet un refactoring futur plus facile et une plus grande flexibilité. HCL fournit également quelques structures de données communes, telles que les listes et les cartes (appelées respectivement tableaux et dictionnaires dans d’autres langages), ainsi que des conditions pour le bifurcage du chemin d’exécution.

Une caractéristique unique de Terraform est la possibilité de spécifier manuellement les ressources en dépendance. Bien que le graphe d’exécution construit lors de l’exécution de votre code contienne déjà les liens détectés (ce qui est correct dans la plupart des cas), vous pourriez avoir besoin de forcer une relation de dépendance que Terraform n’a pas pu détecter.

Dans cet article, nous passerons en revue les structures de données que HCL fournit, ses fonctionnalités de boucles pour les ressources (les clés count, for_each et for), les conditions pour traiter les valeurs connues et inconnues, et les relations de dépendance entre les ressources.

Prérequis

  • Un token d’accès personnel de DigitalOcean que vous pouvez créer via le panneau de contrôle de DigitalOcean. Vous trouverez des instructions dans les documents produits DigitalOcean, Comment créer un token d’accès personnel.
  • Terraform installé sur votre machine locale et un projet mis en place avec le fournisseur DigitalOcean. Complétez Steps 1 et Step 2 du tutoriel Comment utiliser Terraform avec DigitalOcean. Assurez-vous de nommer le dossier du projet terraform-flexibilité, plutôt que loadbalance. Pendant Step 2, vous n’avez pas besoin d’inclure la variable pvt_key et la ressource SSH clé lorsque vous configurez le fournisseur.

Note : Ce tutoriel a été testé spécifiquement avec Terraform 1.0.2.

Types de données en HCL

Avant de découvrir plus sur les boucles et autres fonctionnalités de HCL qui rendent votre code plus flexible, nous allons d’abord passer sur les types de données disponibles et leur utilisation.

Le langage de configuration de Hashicorp supporte les types primitifs et complexes. Les types primitifs sont des chaînes de caractères, des nombres et des valeurs booléennes, qui sont les types basiques qui ne peuvent pas être dérivés d’autres. Les types complexes, en revanche, regroupent plusieurs valeurs dans une seule. Les deux types de valeurs complexes sont les types structuraux et les types de collection. Les types structuraux permettent de grouper des valeurs de différents types ensemble. L’exemple principal est les définitions de ressources que vous utilisez pour spécifier ce que votre infrastructure sera comme. En comparaison aux types structuraux, les types de collection également regroupent des valeurs, mais uniquement celles du même type. Les trois types de collections disponibles dans HCL dont nous sommes intéressés sont les listes, les cartes et les ensembles.

Les listes sont similaires à des tableaux dans d’autres langages de programmation. Elles contiennent un nombre connu d’éléments de même type, qui peuvent être accédés en utilisant la notation de tableau ([]) par leur indice entier, commençant à 0. Voici un exemple de déclaration de variable de liste qui contient les noms des Droplet que vous déployerrez dans les étapes suivantes:

Pour le type, vous avez spécifié qu’il s’agit d’une liste dont le type d’élément est une chaine de caractères, puis vous avez fourni sa valeur par défaut. En HCL, les valeurs énumérées entre crochets signifient une liste.

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

Pour le type, vous avez spécifié que c’est une liste dont le type d’élément est une chaîne de caractères, et vous avez fourni son valeur par défaut. En HCL, les valeurs énumérées entre crochets signifient une liste.

Les cartes

Les cartes sont des collections de paires clé-valeur où chaque valeur est accédée en utilisant sa clé de type string. Il y a deux façons de spécifier des cartes entre crochets : par l’utilisation de colones (:) ou d’égalités (=) pour spécifier les valeurs. Dans les deux cas, la valeur doit être enquêtée avec des guillemets. Quand vous utilisez des colones, la clé doit également être enquêtée.

La définition suivante de carte contenant des noms de déploiements pour différents environnements est écrite en utilisant l’égalité:

variable "droplet_env_names" {
  type = map(string)

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

Si la clé commence par un nombre, vous devez utiliser le syntaxe de colonne:

variable "droplet_env_names" {
  type = map(string)

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

Les ensemble

Les ensembles ne supportent pas l’ordre d’éléments, cela signifie que la traversée des ensembles n’est pas garantie à être identique chaque fois et qu’il n’est pas possible d’accéder en manière cible aux éléments. Ils contiennent des éléments uniques répétés exactement une fois, et spécifier le même élément plusieurs fois résultera en leur présence seule une fois dans l’ensemble.

Déclarer un ensemble est similaire à déclarer une liste, la seule différence étant le type du variable:

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

Après avoir appris sur les types de données structurées que HCL offre et examiné le syntaxe des listes, des cartes et des ensembles, que nous utiliserons tout au long de ce tutoriel, vous allez tester des méthodes flexibles pour déployer plusieurs instances de la même ressource dans Terraform.

Configurer le nombre de ressources en utilisant la clé « count »

Dans cette section, vous créerez plusieurs instances de même ressource en utilisant la clé « count ». La clé « count » est disponible sur tous les ressources et indique combien d’instances de la même ressource créer.

Vous verrez comment ça fonctionne en écrivant une ressource de Droplet, que vous stockeraz dans un fichier nommé droplets.tf dans le répertoire du projet que vous avez créé comme préalable. Créez et ouvrez-le pour l’éditer en exécutant :

  1. nano droplets.tf

Ajoutez les lignes suivantes :

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

Ce code définit une ressource de Droplet appelée test_droplet, qui tournera sur Ubuntu 20.04 avec 1 Go de RAM et un cœur de processeur.

Noticez que la valeur de count est fixée à 3, ce qui signifie que Terraform essayera de créer trois instances de la même ressource. Quand vous avez terminé, sauvegardez et fermez le fichier.

Vous pouvez planifier le projet pour voir quelles actions Terraform effectuerait en exécutant :

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

La sortie sera similaire à ceci :

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. ...

Après avoir créé trois instances de test_droplet avec le même nom web dans Terraform, il est préférable de modifier la définition du Droplet pour que chaque instance ait un nom unique. Ouvrez droplets.tf pour le modifier:

  1. nano droplets.tf

Modifiez la ligne indiquée:

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"
}

Sauvegardez et fermez le fichier.

Terraform fournira les détails suivants concernant la création de trois instances de test_droplet, toutes avec le même nom. Bien que cela soit possible, il n’est pas recommandé, donc modifiez la définition du Droplet pour que chaque instance ait un nom unique. Ouvrez droplets.tf pour le modifier:Modifiez la ligne indiquée:

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

Ensuite, sauvegardez et fermez le fichier.

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: La sortie sera similaire à celle-ci: + resource "digitalocean_droplet" "test_droplet" { ... name = "web.0" ... } # digitalocean_droplet.test_droplet[0] will be created + resource "digitalocean_droplet" "test_droplet" { ... name = "web.1" ... } + resource "digitalocean_droplet" "test_droplet" { ... name = "web.2" ... } Plan: 3 to add, 0 to change, 0 to destroy. ...

Les trois instances de test_droplet seront maintenant créées avec leur index dans leur nom, ce qui les rendra plus faciles à suivre.

Vous avez maintenant compris comment créer plusieurs instances d’une ressource en utilisant la clé count, ainsi que comment récupérer et utiliser l’indice d’instance pendant la provisionnement. Prochaine étape : apprendre comment extraire le nom du Droplet d’une liste.

Obtenir des noms de déploiement à partir d’une liste

Dans les situations où plusieurs instances du même ressource doivent avoir des noms personnalisés, vous pouvez dynamiquement les récupérer d’une variable de liste que vous avez définie. Pendant le reste du tutoriel, vous verrez plusieurs façons de déployer des déploiements de nuages en utilisant une liste de noms, ce qui promette de la flexibilité et de l’utilisation facile.

Vous devrez d’abord définir une liste contenant les noms de déploiement. Ouvrir un fichier appelé variables.tf et le fermer pour le modifier :

  1. nano variables.tf

Ajouter les lignes suivantes :

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

Sauvegardez et fermez le fichier. Cet exemple définit une liste appelée droplet_names, contenant les chaînes first, second, third, et fourth.

Ouvrir droplets.tf pour le modifier :

  1. nano droplets.tf

Modifier les lignes soulignées :

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"
}

Pour améliorer la flexibilité, au lieu de spécifier manuellement un nombre constant d’éléments, vous passez la longueur de la liste droplet_names au paramètre count, qui retournera toujours le nombre d’éléments dans la liste. Pour le nom, vous récupérez l’élément de la liste situé à l’index count.index, en utilisant la notation avec crochetes. Sauvegardez et fermez le fichier quand vous avez terminé.

Essayez à nouveau de planifier le projet. Vous recevrez une sortie similaire à celle-ci :

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: Un serveur Digital Ocean sera créé. + resource "digitalocean_droplet" "test_droplet" { ... + name = "first" ... } Un second serveur Digital Ocean sera créé. + resource "digitalocean_droplet" "test_droplet" { ... + name = "second" ... } Un troisième serveur Digital Ocean sera créé. + resource "digitalocean_droplet" "test_droplet" { ... + name = "third" ... } Un quatrième serveur Digital Ocean sera créé. + resource "digitalocean_droplet" "test_droplet" { ... + name = "fourth" ... Plan: 4 to add, 0 to change, 0 to destroy. ...

Ainsi, quatre instances de serveurs seront déployées successivement et nommées après les éléments de la liste droplet_names.

Vous avez appris comment utiliser count, ses fonctionnalités et sa syntaxe, et vous l’avez utilisé ensemble avec une liste pour modifier les instances de ressources. Vous allez maintenant voir ses défauts et comment les surmonter.

Comprendre les défauts du count

Maintenant que vous connaissez comment le compte est utilisé, examinons ses défauts lorsqu’il est utilisé pour modifier la liste sur laquelle il est appliqué.

Tentez d’effectuer le déploiement des serveurs dans la nuée :

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

Entrez oui lorsque vous soyez demandé. La fin de votre sortie sera similaire à ceci :

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

Maintenant, créez une autre instance de serveur en augmentant la liste droplet_names. Ouvrez variables.tf pour le modifier :

  1. nano variables.tf

Ajoutez un nouvel élément au début de la liste :

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

Quand vous avez terminé, sauvegardez et fermez le fichier.

Préparation du projet :

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

Vous recevrez un résultat comme celui-ci :

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] sera mis à jour en place ~ resource "digitalocean_droplet" "test_droplet" { ... ~ name = "first" -> "zero" ... } # digitalocean_droplet.test_droplet[1] sera mis à jour en place ~ resource "digitalocean_droplet" "test_droplet" { ... ~ name = "second" -> "first" ... } # digitalocean_droplet.test_droplet[2] sera mis à jour en place ~ resource "digitalocean_droplet" "test_droplet" { ... ~ name = "third" -> "second" ... } # digitalocean_droplet.test_droplet[3] sera mis à jour en place ~ resource "digitalocean_droplet" "test_droplet" { ... ~ name = "fourth" -> "third" ... } # digitalocean_droplet.test_droplet[4] sera créé + resource "digitalocean_droplet" "test_droplet" { ... + name = "fourth" ... } Plan: 1 to add, 4 to change, 0 to destroy. ...

La sortie montre que Terraform renomme les quatre premiers « Droplets » et crée le cinquième appelé fourth, car il considère les instances comme une liste ordonnée et identifie les éléments (Droplets) par leur numéro d’index dans la liste. C’est ainsi que Terraform initialement considère les quatre premiers Droplet :

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

Lorsque le nouveau Droplet zero est ajouté au début, sa représentation interne sous forme de table ressemble ainsi :

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

Les quatre premiers Droplets sont alors déplacés d’une place vers la droite. Terraform compare ensuite les deux états représentés dans des tables : à la position 0, le Droplet était appelé first, et parce qu’il est différent dans la seconde table, il planifie une action d’update. Cela se continue jusqu’à la position 4, qui n’a pas un élément comparable dans la première table, et au lieu de cela, une action de provisionnement de Droplet est planifiée.

Cela signifie que ajouter un nouvel élément à la liste n’importe où que ce soit, mais pas au bout, résultera en modifications de ressources qui ne sont pas nécessaires. Des actions similaires d’update seront planifiées si un élément de la liste droplet_names était supprimé.

La principale faiblesse de l’utilisation de count pour déployer un nombre dynamique de instances différentes du même type de ressource est le suivi des ressources incomplet. Pour un nombre constant et constant de instances identiques, count est une solution simple qui fonctionne bien. Dans les cas où certains attributs sont tirés d’une variable, cependant, lorsque certains attributs sont fournis par une variable, le boucle for_each que vous apprendrez plus tard dans cette séquence de tutoriels est une meilleure solution.

Référence à la Ressource Actuelle (self)

Un autre inconvénient de count est que référer à une instance arbitraire de ressource par son indice n’est pas possible dans certains cas.

L’exemple principal est les fournisseurs de provisions de temps de destruction, qui se exécutent quand la ressource est planifiée à être détruite. La raison est que l’instance demandée peut ne pas exister (elle est déjà détruite) ou créer une cyclicité mutuelle de dépendance. En tels cas, plutôt que référer à l’objet par la liste des instances, vous pouvez accéder uniquement à la ressource actuelle avec le mot-clé self.

Pour montrer son utilisation, vous allez maintenant ajouter un fournisseur de localisation destructif à la définition de test_droplet, qui affichera une message lorsque l’exécution sera effectuée. Ouvrez droplets.tf pour le modifier :

  1. nano droplets.tf

Ajoutez les lignes suivantes soulignées :

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!'"
  }
}

Sauvegardez et fermez le fichier.

Le fournisseur local-exec exécutera une commande sur la machine locale où Terraform est exécuté. Puisque le paramètre when est défini sur destroy, il se exécutera uniquement quand la ressource va être détruite. La commande qui est exécutée écoute une chaîne dans stdout, qui remplace le nom de la ressource actuelle en utilisant self.name.

Puisque vous créeront des Droplet de manière différente dans la section suivante, détruisez les Droplet actuellement déployés en exécutant la commande suivante :

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

Entrez oui lorsqu’il vous sera demandé. Vous recevrez alors l’exécution du fournisseur local-exec quatre fois :

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! ...

En cette section, vous avez appris les défauts du constructeur count. Vous allez maintenant apprendre le constructeur de boucle for_each, qui surmonte ces limites et fonctionne avec plus large gamme de types de variables.

Utiliser un Boucle for_each

Dans cette section, vous considérez le constructeur de boucle for_each, sa syntaxe, et comment cela contribue à la flexibilité lors de la définition de ressources avec plusieurs instances.

for_each est un paramètre disponible sur chaque ressource, mais contrairement à count, qui nécessite un nombre d’instances à créer, for_each accepte un map ou un ensemble. Chaque élément de la collection fournie est parcouru une fois et une instance est créée pour lui. for_each permet d’accéder à la clé et à la valeur sous la forme des attributs each.key et each.value respectivement. Lorsqu’un ensemble est fourni, la clé et la valeur seront les mêmes.

Comme il fournit l’élément courant dans l’objet each, vous n’aurez pas à accéder manuellement à l’élément souhaité comme vous l’avez fait avec les listes. Dans le cas d’ensembles, cela n’est même pas possible, car ils n’ont pas de schéma d’ordre interne perceptible. Les listes peuvent également être passées en tant qu’arguments, mais elles doivent d’abord être converties en ensemble à l’aide de la fonction toset.

L’avantage principal de l’utilisation de for_each, en plus de la capacité à numéroter tous les trois types de données de collection, est que seuls les éléments touchés seront modifiés, créés ou supprimés. Si vous changez l’ordre des éléments d’entrée, aucune action ne sera planifiée, et si vous ajoutez, supprimez ou modifiez un élément de l’entrée, des actions appropriées seront planifiées uniquement pour cet élément.

Changeons le ressource Droplet de count en for_each et voyons comment ça marche en pratique. Ouvrez droplets.tf pour l’édition en exécutant :

  1. nano droplets.tf

Modifiez les lignes surlignées :

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"
}

Vous pouvez supprimer le fournisseur local-exec. Quand vous aurez terminé, enregistrez et fermez le fichier.

La première ligne remplace count et appelle for_each, en passant la liste droplet_names sous forme de ensemble à l’aide de la fonction toset, qui convertit automatiquement l’entrée donnée. Pour le nom de Droplet, vous spécifiez each.value, qui contient la valeur de l’élément actuel du ensemble des noms de Droplet.

Planifier le projet en exécutant :

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

La sortie détaillera les étapes que Terraform prendra :

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"] will be created + resource "digitalocean_droplet" "test_droplet" { ... + name = "first" ... } # digitalocean_droplet.test_droplet["fourth"] will be created + resource "digitalocean_droplet" "test_droplet" { ... + name = "fourth" ... } # digitalocean_droplet.test_droplet["second"] will be created + resource "digitalocean_droplet" "test_droplet" { ... + name = "second" ... } # digitalocean_droplet.test_droplet["third"] will be created + resource "digitalocean_droplet" "test_droplet" { ... + name = "third" ... } # digitalocean_droplet.test_droplet["zero"] will be created + resource "digitalocean_droplet" "test_droplet" { ... + name = "zero" ... } Plan: 5 to add, 0 to change, 0 to destroy. ...

En revanche, Terraform considère maintenant chaque instance individuellement et non pas comme éléments d’une liste ordonnée. Chaque instance est liée à un élément du jeu donné, comme indiqué par la chaîne d’élément affichée dans les crochets à côté de chaque ressource qui sera créée.

Appliquer le plan au cloud en exécutant :

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

Saisir yes lors de l’invite. Lorsque cela sera terminé, vous retirerez un élément de la liste droplet_names pour démontrer que les autres instances ne seront pas affectées. Ouvrez variables.tf pour l’édition :

  1. nano variables.tf

Modifiez la liste pour qu’elle soit comme ceci :

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

Enregistrez et fermez le fichier.

Planifiez à nouveau le projet, et vous recevrez la sortie suivante :

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"] sera détruit - resource "digitalocean_droplet" "test_droplet" { ... - name = "zero" -> null ... } Plan: 0 to add, 0 to change, 1 to destroy. ...

Cette fois, Terraform détruira uniquement l’instance supprimée (appelée zero), et n’interférera pas avec les autres instances, ce qui est le comportement correct.

Dans cette étape, vous avez appris à propos de for_each, comment l’utiliser et ses avantages par rapport à count. Ensuite, vous apprendrez à propos de la boucle for, sa syntaxe et son utilisation, et quand elle peut être utilisée pour automatiser certaines tâches.

Bouclage utilisant for

La boucle for fonctionne sur des collections et crée une nouvelle collection en appliquant une transformation à chaque élément de l’entrée. Le type exact de la sortie dépendra de la présence de crochets ([]) ou d’accolades ({}) autour de la boucle, ce qui donne respectivement une liste ou une carte. En tant que tel, il est adapté pour interroger des ressources et former des sorties structurées pour un traitement ultérieur.

La syntaxe générale de la boucle for est :

for element in collection:
transform(element)
if condition

Comme dans d’autres langages de programmation, vous commencez par nommer la variable de boucle (element) et spécifier la collection à énumérer. Le corps du boucle est l’étape de transformation, et une clause optionnelle if peut être utilisée pour filtrer la collection d’entrées.

Vous allez maintenant travailler sur quelques exemples en utilisant des sorties. Vous les stockeront dans un fichier nommé outputs.tf. Créez-le pour le modifier en exécutant la commande suivante:

  1. nano outputs.tf

Ajoutez les lignes suivantes pour stocker dans un fichier les paires de noms de déploiements de noeuds et leurs adresses IP:

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

Ce code spécifie une sortie appelée ip_addresses, et spécifie une boucle qui itère sur les instances de la ressource test_droplet que vous avez personnalisé précédemment. Puisque la boucle est encadrée entre des crochets, son résultat sera une map. La étape de transformation pour les maps est similaire aux fonctions lambda dans d’autres langages de programmation, et ici elle crée une paire clé-valeur en combinant le nom de l’instance avec sa propriété IP privée.

Sauvez et fermez le fichier, puis rafraîchissez ensuite le statut de Terraform pour tenir compte de la nouvelle sortie en exécutant:

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

La commande refresh de Terraform met à jour le statut local avec l’état réel de l’infrastructure dans le nuage.

Vérifiez alors le contenu des sorties:

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

Terraform a affiché le contenu de la sortie ip_addresses, qui est une map construite par le boucle for. (L’ordre des entrées peut être différent pour vous.) Le boucle fonctionnera parfaitement pour tout nombre d’entrées, ce qui signifie que vous pouvez ajouter un nouvel élément à la liste droplet_names et le nouveau Droplet, qui serait créé sans aucune autre entrée manuelle, apparaîtrait également dans cette sortie automatiquement.

En encadrant le boucle for entre crochets, vous pouvez faire en sorte que la sortie soit une liste. Par exemple, vous pourriez ne sortir que les adresses IP des Droplets, ce qui est utile pour des logiciels externes qui parsèment les données. Le code ressemblerait à ceci :

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

Dans ce cas, l’étape de transformation sélectionne l’attribut de l’adresse IP. Elle donnerait le sortie suivante :

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

Comme mentionné précédemment, vous pouvez également filtrer la collection d’entrées en utilisant la clause if. Voici comment vous écrivez le boucle pour filtrer par la région fra1 :

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

En HCL, l’opérateur == vérifie l’égalité des valeurs des deux côtés, ici il vérifie si instance.region est égal à fra1. Si c’est le cas, le test est passé et l’instance est transformée et ajoutée à la sortie, sinon elle est ignorée. La sortie de ce code serait la même que dans l’exemple précédent, car toutes les instances de Droplet sont dans la région fra1, selon la définition du ressource test_droplet. La condition if est également utile lorsque vous voulez filtrer la collection d’entrées pour d’autres valeurs dans votre projet, comme la taille ou la distribution des Droplets.

Parce que vous devez créer des ressources différentes dans la section suivante, détruisez les ressources actuellement déployées en exécutant la commande suivante :

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

Entrez oui lorsqu’il vous est demandé pour terminer le processus.

Nous avons expliqué le boucle for, son syntaxe et des exemples d’utilisation dans les sorties. Vous apprendrez maintenant sur les conditionnels et comment ils peuvent être utilisés ensemble avec count.

Direttive e condizionali

Nel precedente sezione hai visto come funziona la chiave count e come funziona. Ora impararemo ad usare gli operatori condizionali ternari che puoi usare altrove nel tuo codice di Terraform e come funzionano insieme con count.

La sintassi dell’operatore ternario è:

condition ? value_if_true : value_if_false

condizione è un’espressione che calcola un valore booleano (true o false). Se la condizione è vera, allora l’espressione valuta valore_se_vero. Al contrario, se la condizione è falsa, il risultato sarà valore_se_falso.

L’uso principale degli operatori ternari è per abilitare o disabilitare la creazione singola di risorse secondo i contenuti della variabile passata al valore count desiderato sulle risorse desiderate. Questo può essere fatto passando il risultato della comparazione (either 1 o 0) alla chiave count sulle risorse desiderate.

En cas d’utilisation de l’opérateur ternaire pour récupérer un seul élément d’une liste ou d’un ensemble, vous pouvez utiliser la fonction one. Si la collection donnée est vide, elle renvoie null. Sinon, elle renvoie l’élément unique dans la collection, sinon elle lance une erreur si il y en a plusieurs.

Ouvrez maintenant le fichier variables.tf pour le modifier :

  1. nano variables.tf

Ajoutez les lignes soulignées :

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

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

Ce code définit la variable create_droplet de type bool. Sauvegardez et fermez le fichier.

Pour ensuite modifier la déclaration du Droplet, ouvrez droplets.tf pour le modifier en exécutant :

  1. nano droplets.tf

Modifiez votre fichier comme suit :

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"
}

Pour count, vous utilisez un opérateur ternaire pour retourner soit 1 si la variable create_droplet est vraie, soit 0 si fausse, ce qui résultera en aucun Droplet ne étant pas fourni. Sauvegardez et fermez le fichier quand vous avez terminé.

Exécutez le plan d’exécution du projet avec la variable définie à false en exécutant :

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

Vous recevrez les informations suivantes :

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.

Parce que create_droplet a été passé avec la valeur de false, le nombre d’instances est 0, et aucun Droplet n’est créé, donc aucune adresse IP n’est affichée.

Vous avez vu comment utiliser l’opérateur conditionnel ternaire en combinaison avec la clé count pour activer un niveau supérieur de flexibilité dans le choix de déployer les ressources désirées. La suite, vous apprendrez à définir explicitement les dépendances de ressources pour vos ressources.

Définition Explicite de Dépendances de Ressources

Lors de la création du plan d’exécution de votre projet, Terraform détecte les chaînes de dépendances entre les ressources et les ordonne implicitement de manière à ce qu’elles soient construites dans l’ordre approprié. Dans la plupart des cas, Terraform est capable de détecter les relations en examinant toutes les expressions dans les ressources et en construisant un graphe.

Cependant, lorsqu’une ressource, afin d’être provisionnée, nécessite l’accès aux paramètres de contrôle déjà déployés par le fournisseur de cloud, il n’y a pas de signe clair pour Terraform qu’elles sont liées. En conséquence, Terraform ne saura pas qu’elles dépendent l’une de l’autre sur le plan de comportement. Dans de tels cas, la dépendance doit être spécifiée manuellement en utilisant l’argument depends_on.

La clé depends_on est disponible sur chaque ressource et utilisée pour spécifier les liens de dépendance cachés entre des ressources spécifiques. Les relations de dépendance cachées se forment quand une ressource dépend de la behavior d’une autre sans utiliser aucune de ses données dans sa déclaration, ce qui ferait de Terraform de les connecter d’une manière.

Voici un exemple de comment la depends_on est spécifiée dans le code :

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

  depends_on = [
    # Ressources...


  ]
}

Il accepte une liste de références à d’autres ressources, et il ne accepte pas des expressions arbitraires.

depends_on doit être utilisé avec prudence, et seulement lorsque toutes les autres options sont épuisées. Son utilisation signifie que ce que vous essayez de déclarer se trouve hors des limites du système automatique de détection de dépendances de Terraform; cela peut signifier que la ressource est explicitement dépendant de plus de ressources qu’elle n’en a pas besoin.

Vous avez maintenant appris sur le fait de spécifier explicitement des dépendences supplémentaires pour une ressource en utilisant la clé depends_on. Et cela signifie que vous essayez de déclarer quelque chose qui se trouve hors des limites du système automatique de détection de dépendances de Terraform.

Conclusion

Dans cet article, nous avons expliqué les fonctionnalités de HCL qui améliorent la flexibilité et la scalabilité de votre code, telles que count pour spécifier le nombre d’instances de ressources à déployer et for_each comme façon avancée de boucler sur les types de données de collection et personnaliser les instances. Lorsqu’utilisées correctement, elles réduisent considérablement le coût opérationnel lié au gouvernement de l’infrastructure déployée.

Vous avez également appris sur les opérateurs conditionnels et ternaires, et comment ils peuvent être utilisés pour contrôler si une ressource sera déployée. Bien que le système automatique de détection de dépendances de Terraform soit assez capable, il peut arriver que vous deviez spécifier manuellement les dépendances des ressources en utilisant la clé depends_on.

Cet tutoriel fait partie de la série Comment Gérer l’Infrastructure avec Terraform . La série couvre plusieurs sujets relatifs à Terraform, du premier install du logiciel jusqu’à la gestion de projets complexes.

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