Espaces de travail Terraform
Terraform espaces de travail permettent de stocker indépendamment l'état d'un environnement pour une configuration IaC unique. Sur sa page consacrée aux espaces de travail, Hashicorp indique : "Les espaces de travail ne conviennent pas à la décomposition des systèmes ou aux déploiements nécessitant des identifiants et des contrôles d'accès distincts. Se référer auxCas d'utilisationdans la documentation Terraform CLI pour plus de détails et les alternatives recommandées". La page des cas d'utilisation indique clairement qu'il existe de nombreuses limitations et qu'il n'est pas recommandé d'isoler les environnements.
Les espaces de travail Terraform de HCP répondent à certains des problèmes, mais nécessitent l'utilisation de sa plateforme cloud et séparent essentiellement ces espaces de travail dans leur propre configuration indépendante, ce qui laisse beaucoup de place à la dérive et à la duplication du code.
Modules Terraform
Une des meilleures pratiques de l'industrie pour obtenir des configurations DRY est d'utiliser des modules Terraform. En utilisant ces modules avec des variables différentes, le code IaC peut appeler le module à plusieurs reprises pour différents environnements. Les paramètres qui ne changent pas restent ainsi globaux, à l'intérieur du module. Les paramètres dynamiques sont conservés en dehors du module dans le code appelant.
Cette approche pose toutefois plusieurs problèmes. En particulier, la configuration du backend doit être répétée et les configurations d'environnement disjointes doivent être mises à jour indépendamment, ce qui peut entraîner une dérive dans les configurations stockées qui sont utilisées.
Terragrunt
Terragrunt a été conçu pour résoudre un grand nombre des problèmes nécessaires à l'obtention de configurations DRY Terraform IaC. L'utilisation de Terragrunt est controversée par certains ingénieurs de l'industrie, mais je crois que beaucoup de ces arguments sont erronés et dans certains cas où ils sont valables, les avantages DRY de l'utilisation de Terragrunt l'emportent souvent sur ces points. C'est particulièrement vrai lorsque la taille et la maintenabilité des configurations IaC deviennent difficiles à gérer, mais cela peut également présenter des avantages pour des cas d'utilisation plus restreints.
L'utilisation de Terragrunt permet de résoudre les problèmes de code IaC DRY de Terraform de plusieurs façons. Les configurations dynamiques peuvent être centralisées pour les entrées, les modules, les fournisseurs et les backends d'état. De plus, le code IaC peut inclure d'autres codes IaC sans avoir à créer un module complètement séparé.
Même en utilisant du code ou des paramètres partagés (que je qualifierai de globaux), nous pouvons concevoir notre solution de manière à pouvoir compléter ce code ou à le remplacer complètement. En plus de remplacer les variables, nous pouvons également inclure des modules avec des versions différentes si nous le souhaitons. Cela peut s'avérer particulièrement important si vous disposez d'un environnement "bac à sable" dans lequel vous souhaitez tester une nouvelle version d'un module ou de paramètres sans affecter d'autres environnements à l'aide de votre configuration globale. Développez ces types de personnalisation dans votre système CICD et le code devient alors gérable au lieu d'être une toile d'araignée de code dupliqué à maintenir.
Solution DRY Terragrunt
Construisons la structure d'un exemple de projet qui transmet des ACL et un nom de domaine à un module.
Structure du projet
Nous obtiendrons la structure de projet suivante :
projet-environnements-multiples
├── dev
│ ├── acls.tf
│ ├─── environment.auto.tfvars
│ ├─── terragrunt.hcl
│ └─── variables.tf
├── global
│ ├── global-acls.tf
│ ├─── global-main.tf
├─── prod
│ ├── acls.tf
│ ├─── environment.auto.tfvars
│ ├─── terragrunt.hcl
│ └─── variables.tf
└── terragrunt-root.hcl
terragrunt-root.hcl
Ce fichier est utilisé pour les paramètres partagés du projet racine. Typiquement, cela inclurait des paramètres d'état à distance ou des configurations de fournisseurs. Pour cette démonstration, l'état n'est pas nécessaire, il peut donc s'agir d'un fichier vide.
locals {
environment_remote_backend = get_env("REMOTE_STATE_CREDENTIALS", "") != "" ? "remote_state_tbd" : "local"
}
generate "backend" {
path = "backend.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
terraform {
%{if local.environment_remote_backend == "local"}
backend "local" {
path = "terraform.tfstate"
}
%{else}
backend "remote_state_tbd" {
bucket = "myproject-tfstate-${basename(get_terragrunt_dir())}"
}
%{endif}
}
EOF
}
terragrunt.hcl
Ce fichier est utilisé dans chaque répertoire d'environnement pour hériter des paramètres racine de terragrunt. Nous l'utilisons également pour inclure du code global.
terraform {
source = "${get_terragrunt_dir()}/../global"
}
include "root" {
path = find_in_parent_folders("terragrunt-root.hcl")
}
variables.tf
Ce fichier est utilisé dans chaque répertoire d'environnement pour définir des variables environnementales qui peuvent être dynamiques par environnement, ou des informations d'identification à transmettre au module.
variable "environment_name" {
description = "Environment Name"
type = string
}
environnement.auto.tfvars
Ce fichier est utilisé dans chaque répertoire d'environnement pour définir les tfvars de l'environnement. Il peut s'agir du nom d'un environnement.
environment_name = "dev|prod"
global-main.tf
Ce fichier est utilisé pour appeler globalement le module principal pour tous les environnements. Cette même fonctionnalité pourrait être placée dans chaque environnement, mais en la gardant dans le répertoire global, elle sera automatiquement utilisée par les environnements. Le module utilise une entrée pour les ACL des ACL locales définies pour chaque environnement.
module "my_reusable_module" {
source = "path-to-my-module"
domain = var.environment_name
acls = local.acls
}
global-acls.tf
Ce fichier est utilisé pour définir globalement les ACL à utiliser pour tout environnement qui le souhaite.
locals {
global_myobjects = [
{
name = "Home"
entries = [
{ ip = "192.168.1.1" },
{ ip = "192.168.1.2" },
]
},
{
name = "Office"
entries = [
{ ip = "192.168.2.1" },
{ ip = "192.168.2.2" },
]
},
]
}
acls.tf
Ce fichier est utilisé dans chaque répertoire d'environnement pour définir une variable ACL locale. Dans l'exemple prod, nous utilisons simplement ce qui se trouve dans les ACL globales. Pour dev, nous ajoutons une troisième ACL que nous souhaitons tester, en plus des ACL globales.
Prod :
locals {
acls = concat(
local.global_acls,
)
}
Dev :
locals {
acls = concat(
local.global_acls,
{
name = "Dev Datacenter"
entries = [
{ ip = "192.168.3.1" },
{ ip = "192.168.3.2" },
]
},
)
}
Exécution
L'exécution du code Terraform avec Terragrunt devient un jeu d'enfant :
terragrunt init --all
terragrunt plan --all
terragrunt apply --all --queue-include-dir dev
terragrunt apply --all --queue-include-dir production
terragrunt destroy –all
Réflexions finales
Bien qu'il existe de nombreuses solutions pour gérer plusieurs environnements avec Terraform, l'exemple fourni nous permet d'obtenir une solution Terraform IaC flexible qui fait abstraction des fonctionnalités globales pour faciliter la réutilisation et la maintenance, tout en permettant de remplacer les paramètres ou les fonctionnalités propres à chaque environnement.
La mise en œuvre de plusieurs environnements pour utiliser la configuration DRY IaC Terraform avec Terragrunt fournit un code gérable, qu'il s'agisse de quelques environnements, de plusieurs environnements ou même d'environnements éphémères. Intégrez-le pour simplifier les flux de travail CICD et laissez-le accélérer votre activité.
Ces types de solutions et de personnalisations offrent une grande flexibilité et une grande efficacité pour les besoins de votre entreprise. Pour en savoir plus sur la façon dont nos solutions personnalisées peuvent contribuer à la réussite de votre entreprise, contactez-nous!