Ce document fournit des recommandations de base pour le style et la structure de vos configurations Terraform. Ces recommandations s'appliquent aux modules Terraform réutilisables et aux configurations racine.
Ce guide n'est pas une introduction à Terraform. Pour une présentation de l'utilisation de Terraform avec Google Cloud, consultez la page Premiers pas avec Terraform.
Suivre une structure de module standard
- Les modules Terraform doivent respecter la structure de module standard.
- Démarrez chaque module avec un fichier
main.tf
où les ressources sont placées par défaut. - Dans chaque module, incluez un fichier
README.md
au format Markdown. Dans le fichierREADME.md
, incluez la documentation de base du module. - Placez les exemples dans un dossier
examples/
, avec un sous-répertoire distinct pour chaque exemple. Pour chaque exemple, incluez un fichierREADME.md
détaillé. - Créez des regroupements logiques de ressources avec leurs propres fichiers et des noms descriptifs comme
network.tf
,instances.tf
ouloadbalancer.tf
.- Évitez d'attribuer à chaque ressource son propre fichier. Regroupez les ressources en fonction de leur objectif partagé. Par exemple, combinez
google_dns_managed_zone
etgoogle_dns_record_set
dansdns.tf
.
- Évitez d'attribuer à chaque ressource son propre fichier. Regroupez les ressources en fonction de leur objectif partagé. Par exemple, combinez
- Dans le répertoire racine du module, n'incluez que Terraform (
*.tf
) et les fichiers de métadonnées du dépôt (tels queREADME.md
etCHANGELOG.md
). - Placez toute documentation supplémentaire dans un sous-répertoire
docs/
.
Adopter une convention d'attribution de noms
Nommez tous les objets de configuration en utilisant des traits de soulignement pour délimiter plusieurs mots. Cette pratique garantit la cohérence avec la convention d'attribution de noms pour les types de ressources, les types de sources de données et les autres valeurs prédéfinies. Cette convention ne s'applique pas aux arguments de noms.
Recommandations :
resource "google_compute_instance" "web_server" { name = "web-server" }
Option déconseillée :
resource "google_compute_instance" "web-server" { name = "web-server" }
Pour simplifier les références à une ressource qui est la seule de son type (par exemple, un équilibreur de charge unique pour un module entier), nommez la ressource
main
.- Il faut un surcroît de travail mental pour se souvenir de
some_google_resource.my_special_resource.id
par rapport àsome_google_resource.main.id
.
- Il faut un surcroît de travail mental pour se souvenir de
Pour différencier les ressources d'un même type les unes des autres (par exemple,
primary
etsecondary
), utilisez des noms de ressources pertinents.Utilisez des noms de ressource au singulier.
Dans le nom de la ressource, ne répétez pas le type de ressource. Exemple :
Recommandations :
resource "google_compute_global_address" "main" { ... }
Option déconseillée :
resource "google_compute_global_address" "main_global_address" { … }
Utiliser les variables avec soin
- Déclarez toutes les variables dans
variables.tf
. - Attribuez aux variables des noms descriptifs pertinents pour leur utilisation ou leur objectif :
- Les entrées, les variables locales et les sorties représentant des valeurs numériques (tailles de disque ou de RAM, par exemple) doivent être nommées avec des unités (comme
ram_size_gb
). Les API Google Cloud ne disposant pas d'unités standards, le fait de nommer les variables avec des unités permet d'indiquer clairement l'unité d'entrée attendue pour les responsables de configuration. - Pour les unités de stockage, utilisez des préfixes d'unité binaire (puissances de 1 024) :
kibi
,mebi
,gibi
. Pour toutes les autres unités de mesure, utilisez des préfixes décimaux d'unités (multiples de 1 000) :kilo
,mega
,giga
. Cette pratique correspond à celle utilisée dans Google Cloud. - Pour simplifier la logique conditionnelle, attribuez des noms positifs aux variables booléennes (par exemple,
enable_external_access
).
- Les entrées, les variables locales et les sorties représentant des valeurs numériques (tailles de disque ou de RAM, par exemple) doivent être nommées avec des unités (comme
- Les variables doivent comporter une description. Les descriptions sont automatiquement incluses dans la documentation générée automatiquement d'un module publié. Pour les nouveaux développeurs, les descriptions ajoutent un contexte supplémentaire que les noms descriptifs seuls ne peuvent pas fournir.
- Attribuez des types définis aux variables.
- Le cas échéant, indiquez les valeurs par défaut :
- Pour les variables dont les valeurs sont indépendantes de l'environnement (telles que la taille du disque), fournissez les valeurs par défaut.
- Pour les variables ayant des valeurs spécifiques à l'environnement (telles que
project_id
), ne fournissez pas de valeurs par défaut. De cette façon, le module appelant doit fournir des valeurs significatives.
- N'utilisez des valeurs par défaut vides pour les variables (chaînes ou listes vides, par exemple) que si l'utilisation d'une variable vide est une préférence valide que les API sous-jacentes ne rejettent pas.
- Soyez prudent lorsque vous utilisez des variables. Ne définissez des paramètres que pour les valeurs qui changent pour chaque instance ou chaque environnement. Lorsque vous décidez d'exposer une variable, assurez-vous de disposer d'un cas d'utilisation concret pour la modification de cette variable. S'il est peu probable qu'une variable soit nécessaire, ne l'exposez pas.
- L'ajout d'une variable avec une valeur par défaut est rétrocompatible.
- La suppression d'une variable n'est pas rétrocompatible.
- Dans les cas où un littéral est réutilisé à plusieurs endroits, vous pouvez utiliser une valeur locale sans l'exposer en tant que variable.
Exposer les sorties
- Organisez toutes les sorties dans un fichier
outputs.tf
. - Fournissez des descriptions pertinentes pour toutes les sorties.
- Documentez les descriptions de sorties dans le fichier
README.md
. Générez automatiquement des descriptions sur le commit avec des outils tels que terraform-docs. - Générez toutes les valeurs utiles que les modules racine peuvent avoir besoin de référencer ou de partager. En particulier pour les modules Open Source ou hautement utilisés, exposez toutes les sorties ayant un potentiel de consommation.
Ne transmettez pas de sorties directement via des variables d'entrée, car cela empêche leur ajout correct au graphe de dépendance. Pour vous assurer que des dépendances implicites sont créées, assurez-vous que les sorties renvoient des attributs de ressources. Au lieu de référencer directement une variable d'entrée pour une instance, transmettez l'attribut comme indiqué ici :
Recommandations :
output "name" { description = "Name of instance" value = google_compute_instance.main.name }
Option déconseillée :
output "name" { description = "Name of instance" value = var.name }
Utiliser des sources de données
- Placez les sources de données à côté des ressources qui y font référence. Par exemple, si vous récupérez une image à utiliser lors du lancement d'une instance, placez-la avec l'instance plutôt que de collecter des ressources de données dans son propre fichier.
- Si le nombre de sources de données devient important, envisagez de les déplacer vers un fichier
data.tf
dédié. - Pour extraire les données relatives à l'environnement actuel, utilisez l'interpolation de variables ou de ressources.
Limiter l'utilisation des scripts personnalisés
- N'utilisez des scripts que si cela est vraiment nécessaire. L'état des ressources créées via des scripts n'est ni pris en compte, ni géré par Terraform.
- Évitez les scripts personnalisés, si possible. Utilisez-les uniquement lorsque les ressources Terraform ne sont pas compatibles avec le comportement souhaité.
- Tous les scripts personnalisés utilisés doivent avoir une raison clairement documentée d'existence et, idéalement, un plan d'abandon.
- Terraform peut appeler des scripts personnalisés via des approvisionneurs, y compris l'approvisionneur local-exec.
- Placez les scripts personnalisés appelés par Terraform dans un répertoire
scripts/
.
Inclure les scripts d'aide dans un répertoire distinct
- Organisez les scripts d'aide qui ne sont pas appelés par Terraform dans un répertoire
helpers/
. - Décrivez les scripts d'aide dans le fichier
README.md
avec des explications et des exemples d'appels. - Si les scripts d'aide acceptent des arguments, incluez une vérification des arguments et une sortie
--help
.
Placer les fichiers statiques dans un répertoire distinct
- Les fichiers statiques référencés par Terraform mais non exécutés (tels que les scripts de démarrage chargés sur des instances Compute Engine) doivent être organisés dans un répertoire
files/
. - Placez les documents HereDocs dans des fichiers externes, séparés de leur HCL.
Référencez-les en utilisant la fonction
file()
. - Pour les fichiers lus à l'aide de la fonction
templatefile
de Terraform, utilisez l'extension de fichier.tftpl
.- Les modèles doivent être placés dans un répertoire
templates/
.
- Les modèles doivent être placés dans un répertoire
Protéger les ressources avec état
Pour les ressources avec état, telles que les bases de données, assurez-vous que la protection contre la suppression est activée. Exemple :
resource "google_sql_database_instance" "main" {
name = "primary-instance"
settings {
tier = "D0"
}
lifecycle {
prevent_destroy = true
}
}
Utiliser la mise en forme intégrée
Tous les fichiers Terraform doivent être conformes aux normes de terraform fmt
.
Limiter la complexité des expressions
- Limitez la complexité des expressions interpolées individuelles. Si de nombreuses fonctions sont nécessaires dans une seule expression, envisagez de la diviser en plusieurs expressions en utilisant des valeurs locales.
- N'exécutez jamais plusieurs opérations ternaires sur une seule ligne. Utilisez plutôt plusieurs valeurs locales pour créer la logique.
Utiliser count
pour les valeurs conditionnelles
Pour instancier une ressource de manière conditionnelle, utilisez le méta-argument count
.
Exemple :
variable "readers" {
description = "..."
type = list
default = []
}
resource "resource_type" "reference_name" {
// Do not create this resource if the list of readers is empty.
count = length(var.readers) == 0 ? 0 : 1
...
}
Soyez prudent lorsque vous utilisez des variables spécifiées par l'utilisateur pour définir la variable count
pour les ressources. Si un attribut de ressource est fourni pour une variable de ce type (comme project_id
) et que cette ressource n'existe pas encore, Terraform ne peut pas générer de plan. Au lieu de cela, Terraform rapporte une erreur value of count cannot be computed
.
Dans ce cas, utilisez une variable enable_x
distincte pour calculer la logique conditionnelle.
Utiliser for_each
pour les ressources itérées
Si vous souhaitez créer plusieurs copies d'une ressource en vous basant sur une ressource d'entrée, utilisez le méta-argument for_each
.
Publier les modules dans un registre
Modules réutilisables : publiez les modules réutilisables dans un registre de modules.
Modules Open Source : publiez les modules Open Source dans Terraform Registry.
Modules privés : publiez les modules privés dans un registre privé.
Étapes suivantes
- Découvrez les bonnes pratiques concernant l'utilisation de modules réutilisables.
- Découvrez les bonnes pratiques concernant l'utilisation des modules racine Terraform.