L'Infrastructure as Code (IaC) implique souvent la gestion de ressources dont les configurations ne sont pas figées à la compilation. Que vous provisionniez des groupes de sécurité AWS, configuriez des déploiements Kubernetes ou mettiez en place des interfaces réseau Azure, le nombre de blocs imbriqués ou d'éléments de liste varie fréquemment. Codifier en dur ces configurations entraîne du code répétitif et des cauchemars de maintenance. C'est ici que les blocs dynamiques Terraform et l'argument méta for_each brillent.
Pour les développeurs de niveau intermédiaire à avancé, maîtriser ces deux fonctionnalités est essentiel pour écrire du code HCL (HashiCorp Configuration Language) propre, évolutif et maintenable. Cet article explore des modèles avancés pour combiner ces outils afin de gérer des collections complexes de longueur variable.
Comprendre les blocs de construction
Avant de plonger dans les modèles avancés, clarifions brièvement la distinction. for_each est un argument méta qui peut être utilisé sur des ressources ou des modules pour créer plusieurs instances d'une ressource à partir d'une carte (map) ou d'un ensemble de chaînes de caractères. Il est idéal pour la création de ressources de niveau supérieur.
D'un autre côté, les blocs dynamiques vous permettent de générer des blocs imbriqués (comme ingress dans un groupe de sécurité) au sein d'une ressource de manière dynamique. Ils itèrent sur une liste ou une carte et injectent la configuration du bloc correspondante pour chaque élément.
Modèle 1 : Le bloc dynamique imbriqué
Le cas d'utilisation le plus courant pour les blocs dynamiques est la génération de configurations imbriquées. Prenons l'exemple d'un aws_security_group AWS. Vous souhaitez définir des règles d'entrée (ingress) basées sur une variable, mais le nombre de règles est inconnu. En utilisant un bloc dynamique, vous pouvez itérer sur une liste de cartes.
variable "ingress_rules" {
type = list(object({
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
}))
default = []
}
resource "aws_security_group" "example" {
name = "example-sg"
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.from_port
to_port = ingress.value.to_port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidr_blocks
}
}
}
# Utilisation dans main.tf
resource "aws_security_group" "web_sg" {
ingress_rules = [
{
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
},
{
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"]
}
]
}
Ce modèle garde vos définitions de variables propres et permet à votre infrastructure de s'adapter instantanément lorsque de nouvelles règles sont ajoutées à la liste d'entrée.
Modèle 2 : Combiner for_each et les blocs dynamiques
Les scénarios avancés nécessitent souvent la création de plusieurs ressources, chacune avec son propre ensemble de blocs imbriqués dynamiques. Par exemple, vous pourriez déployer plusieurs services d'application, chacun avec des variables d'environnement ou des ports de conteneur spécifiques.
En combinant for_each sur la ressource et les blocs dynamic à l'intérieur de la ressource, vous obtenez un haut degré de flexibilité.
variable "services" {
type = map(object({
name = string
ports = list(object({
containerPort = number
protocol = string
}))
}))
}
resource "aws_lb_target_group" "this" {
for_each = var.services
name = each.key
port = 80
protocol = "HTTP"
# Note : Les blocs dynamiques à l'intérieur des groupes de cibles sont limités,
# mais ce modèle s'applique aux ressources comme aws_instance ou aws_lb_listener
tags = {
Name = each.key
}
}
Bien que l'exemple ci-dessus soit simplifié, une implémentation plus complexe implique l'utilisation de for_each pour créer des modules ou des ressources distincts, où chaque instance reçoit une carte de configuration spécifique qui pilote ses blocs dynamiques internes.
Meilleures pratiques et considérations de performance
Lors de la gestion de collections de longueur variable, gardez les points suivants à l'esprit :
- Immuabilité des clés : Lorsque vous utilisez
for_each, assurez-vous que vos clés sont stables. Changer une clé dans une carte entraînera la destruction et la recréation de la ressource par Terraform plutôt que sa mise à jour. - Simplifiez les variables : Utilisez des types de variables structurés (cartes d'objets ou listes d'objets) pour valider les entrées tôt. Cela empêche les erreurs d'exécution lorsque les blocs dynamiques tentent d'accéder à des attributs non définis.
- Lisibilité : Bien que puissants, un excès d'imbrication de blocs dynamiques peut rendre le code difficile à lire. Extrayez les configurations complexes dans des valeurs locales ou des modules séparés si la logique devient trop compliquée.
Conclusion
Les blocs dynamiques et for_each ne sont pas seulement des fonctionnalités de commodité ; ce sont des outils fondamentaux pour construire une infrastructure cloud-native robuste avec Terraform. En exploitant ces modèles avancés, vous pouvez éliminer la duplication de code, réduire le risque de dérive de configuration et créer une infrastructure qui évolue aussi gracieusement que vos applications. Commencez à refactoriser vos blocs codés en dur dès aujourd'hui pour débloquer tout le potentiel de votre stratégie d'IaC.