Comment structurer le code Terraform et ses modules réutilisables
Avant de plonger dans la structure du projet Terraform, j’aimerais partager un fait amusant pour vous assurer que nous sommes dans le bon bateau avec Terraform !
Par GitHub L’enquête sur l’état de l’Octoverse de 2021-2022, le langage de configuration Hashicorp (HCL) a pris la première place dans la catégorie des langages de programmation à la croissance la plus rapide au cours de l’année écoulée. Cela s’explique en grande partie par la popularité croissante de l’outil Terraform et des pratiques IaC pour automatiser de plus en plus les déploiements dans le cloud.
Guidés par l’architecture de pipeline en libre-service DevOps, nous explorerons comment structurer le code Terraform et ses modules réutilisables dans cette histoire. Remarquez le rectangle en surbrillance rouge dans le diagramme ci-dessous. Plongeons dedans.
Dans Terraform, un module est un conteneur pour plusieurs ressources utilisées ensemble. Les modules peuvent créer des composants réutilisables et constituent un bon moyen d’organiser votre infrastructure en unités logiques. Les avantages des modules Terraform réutilisables incluent :
- Principe DRY (Don’t Repeat Yourself) : les modules vous permettent de définir votre infrastructure de manière réutilisable, en réduisant la quantité de duplication de code et en facilitant sa gestion.
- Réutilisabilité : les modules peuvent être utilisés dans plusieurs environnements et projets, ce qui vous permet de réutiliser votre code d’infrastructure.
- Organisation : les modules vous aident à organiser votre code d’infrastructure en unités logiques, ce qui facilite sa compréhension et sa maintenance.
- Collaboration : les modules peuvent être partagés avec d’autres équipes et organisations, ce qui facilite la collaboration sur des projets d’infrastructure.
- Standardisation : aidez à normaliser les normes de conformité et de sécurité dans diverses infrastructures et projets.
Les modules réutilisables Terraform doivent être conservés dans un référentiel centralisé, qui agit un peu comme un registre Terraform privé. À des fins de démonstration, nous pouvons appeler ce dépôt centralisé reusable-workflows-modules
. À quoi ressemble la structure du module réutilisable ? Voir l’exemple de capture d’écran ci-dessous :
Sous le terraform/modules
répertoire, vous pouvez avoir un ou plusieurs modules réutilisables. Notez que chaque module réutilisable contient une liste de fichiers avec des conventions de dénomination standard, qui sont assez explicites par leurs noms de fichiers :
main.tf
outputs.tf
variables.tf
README.md
Cette structure de fichiers n’est qu’une recommandation. Selon la complexité de vos modules réutilisables, vous devrez peut-être inclure d’autres fichiers dans votre structure de fichiers.
Étant donné que nous utilisons GitHub Actions comme outil CI/CD, il est logique pour nous que le code Terraform soit validé avec le code source du projet dans le même référentiel. Supposons que nous ayons tout le code Terraform pour tous nos projets validés dans un dépôt autonome.
Dans ce cas, nous ne pouvons pas exécuter les flux de travail GitHub Actions pour déployer Terraform dans différents environnements/comptes dans AWS pour différents projets, car il devient extrêmement difficile pour nous de gérer les environnements/secrets GitHub et de faire correspondre les informations d’identification IAM pour de nombreux projets au sein du même référentiel.
Il est préférable que le code Terraform réside dans le même référentiel que le code source de son projet. Voir l’exemple de capture d’écran ci-dessous, où dans ce projet, springboot-infracost-demo
le code Terraform est situé sous un terraform
répertoire sous la racine. Il existe un flux de travail GitHub Actions correspondant terraform.yml
sous .gitub/workflows
répertoire pour exécuter Terraform init/plan/apply, ainsi que les flux de travail pour déployer le code du projet sur ses ressources AWS correspondantes.
Sur la base de la règle 3–2–1 pour l’architecture de pipeline en libre-service DevOps, nous pouvons voir que nos trois types de code source sont mis en évidence dans les rectangles rouges ci-dessous : les flux de travail GitHub Actions, le code source de l’application et le code Terraform.
Comment appeler des modules réutilisables à partir du code Terraform spécifique au projet
Étant donné que les modules Terraform résident dans reusable-workflows-modules
référentiel, le code Terraform spécifique au projet ne contient qu’une logique spécifique au projet, telle que des configurations spécifiques à l’environnement. Nous ne répétons pas la logique du module réutilisable. Nous pouvons appeler les modules Terraform réutilisables situés dans reusable-workflows-modules
dépôt de main.tf
sous la racine du projet.
Il est recommandé de toujours épingler la source du module Terraform à une version particulière, ou main
dans notre exemple ci-dessous, se référant à la dernière version de la branche main
de reusable-workflows-modules
dépôt.
Nos modules réutilisables Terraform résident dans un sous-répertoire de reusable-workflows-modules
dépôt : github.com/wenqiglantz/reusable-workflows-modules/terraform/modules
. Pour spécifier le sous-répertoire du module Terraform, nous devons placer une syntaxe spéciale à double barre oblique juste après le nom du référentiel. Terraform interprète la double barre oblique pour indiquer que le chemin restant après ce point est un sous-répertoire dans le référentiel.
Pour épingler la source du module Terraform à une branche particulière, le main
branche de reusable-workflows-modules
dépôt, nous ajoutons ?ref=main
à la fin du nom du module. Voici un exemple d’extrait de code montrant comment springboot-infracost-demo
applications main.tf
appelle le module réutilisable lambda
:
module "lambda" {
source = "github.com/wenqiglantz/reusable-workflows-modules//terraform/modules/lambda?ref=main"
s3_bucket_name = var.s3_bucket_name
s3_object_key = var.s3_object_key
lambda_functions = var.lambda_functions
}
Regroupez les fichiers .tfvars sous les répertoires liés à l’environnement
Remarquez la capture d’écran ci-dessous à partir d’un dépôt d’application, nous avons terraform.tfvars
fichier situé sous les répertoires liés à l’environnement tels que dev
, qc
et prod
sous .env
. Ce sont les fichiers contenant des valeurs spécifiques à l’environnement pour les variables.
Il existe un connu problème ouvert sur la limitation de ne pas pouvoir passer des variables dans backend.tf
pour la gestion d’état à distance dans S3. Comme backend.tf
est appelé pendant terraform init
et il n’y a aucun moyen pour terraform d’analyser les variables dans backend.tf
avant qu’il ne soit initialisé. Heureusement, il existe une solution de contournement. Voici trois étapes à suivre :
- Nous pouvons garder le
backend.tf
fichier à la racine de terraform, comme indiqué dans la capture d’écran ci-dessus, mais ce fichier ne contiendra aucun détail spécifique à S3. Voici un extrait de code debackend.tf
:
terraform {
backend "s3" {
//details in .env/{env}/backend.tfvars
}
}
- Nous ajoutons un
backend.tfvar
déposer sous le.env
répertoire sous son dossier d’environnement respectif. Ce fichier contient le nom du compartiment S3, la clé, la région et l’indicateur de chiffrement. Voir l’extrait suivant pour.env/dev/backend.tfvar
:
bucket = "terraform-remote-backend-dev"
key = "demo/state.tfstate"
region = "us-east-1"
encrypt = "true"
- Nous courons ensuite
terraform init
en passant dans cebackend.tfvar
. Voici l’extrait pour exécuter cela localement :
terraform init -backend-config='./.env/dev/backend.tfvars'
Lors de l’exécution du flux de travail GitHub Actions, nous obtenons ce qui suit de terraform.yml
:
terraform init -backend-config='./.env/${{ github.event.inputs.environment || 'dev' }}/backend.tfvars' -upgrade=true -no-color -input=false
Assurez-vous de réviser votre .gitignore
fichier à la racine de votre projet pour demander à GitHub d’ignorer certains fichiers/répertoires terraform. Voici un exemple de fichiers/répertoires liés à Terraform à ignorer dans .gitignore
:
#######################################
# Terraform files/directory to ignore #
#######################################
# Local .terraform directories
**/.terraform/*# .tfstate files
*.tfstate
*.tfstate.*
# Crash log files
crash.log
crash.*.log
# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# Include override files you do wish to add to version control using negated pattern
# !example_override.tf
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*
# Ignore CLI configuration files
.terraformrc
terraform.rc
# Lock
.terraform.lock.hcl
# Plan files
*.tfplan
Le workflow GitHub Actions est utilisé pour exécuter terraform init
, plan
, apply
et destroy
pour votre projet. Tout d’abord, passons aux éléments d’entretien ménager pour nous assurer que les secrets GitHub sont correctement configurés.
Configuration des secrets
Les seuls secrets d’environnement GitHub nécessaires pour exécuter le flux de travail terraform sont TERRAFORM_ROLE_TO_ASSUME
et AWS_REGION
. Configurez-les en conséquence selon la configuration de votre compte AWS.
Workflow réutilisable Terraform
Un workflow GitHub Actions réutilisable pour le déploiement de Terraform a été extrait dans reusable-workflows-modules
dépôtdétails de ce workflow réutilisable terraform.yml
sont les suivants:
Quelques faits saillants importants :
- Remarquez la ligne 69 ci-dessus,
git config --global url." secrets.NPM_TOKEN }}@github.com".insteadOf https://github.com
. Ceci est important si vos modules réutilisables résident dans un référentiel privé. Nous passons unNPM_TOKEN
qui a accès au référentiel privé car l’application cliente ne transmet pas ces informations d’identification lors de l’appel du module réutilisable Terraform (crédit : Impossible d’initialiser avec les modules de dépôt privés · Problème #33 · hashicorp/setup-terraform ). Cette ligne est critique. Sans cette ligne, le workflow échouera àterraform init
étape en raison de l’impossibilité d’accéder aureusable-workflows-modules
dépôt privé sans transmettre de jeton valide. - Aussi, notez que nous passons
terraform.tfvars
avec-var-file
aux commandes Terraform. En fonction de l’environnement transmis depuis leworkflow_dispatch
déclencheur manuel, le flux de travail Terraform vérifie dans le dossier d’environnement sous.env
s’exécute pour cet environnement choisi avec les.tfvars
fichier transmis. terraform apply
l’étape ne s’exécute que surapply-branch
qui est transmis depuis le flux de travail appelant, il s’agit par défaut de la branche par défaut de votre référentiel, telle quemain
en fonction de la stratégie de branchement de votre dépôt.- Courir
terraform destroy
créer une branche de fonctionnalité,destroy
et déclenchez ce flux de travail à partir de cette branche à détruire.
Lors du déploiement de fichiers Terraform, le flux de travail de votre application doit appeler le flux de travail réutilisable Terraform ci-dessus. Voici un échantillon terraform.yml
à partir d’une application qui appelle le flux de travail réutilisable de Terraform :
Avec cela, vous disposez d’un pipeline d’infrastructure entièrement fonctionnel et opérationnel pour provisionner vos ressources cloud pour votre application.
Nous avons exploré la structure de projet Terraform centrée sur le libre-service DevOps dans cet article. Nous avons examiné ce que sont les modules réutilisables Terraform, leurs avantages et leur structure dans le référentiel GitHub.
Nous avons ensuite examiné la structure de code des trois types de code source dans un référentiel d’application et comment déclencher un appel du code Terraform du référentiel d’application vers le module réutilisable dans le référentiel centralisé.
Enfin, nous avons approfondi les détails du flux de travail Terraform GitHub Actions, à la fois le flux de travail réutilisable dans le référentiel centralisé et le flux de travail d’appel depuis le référentiel d’application. J’espère que vous trouverez cette histoire utile sur votre chemin vers le libre-service DevOps.
L’exemple de code de cette histoire se trouve dans les dépôts GitHub suivants :
Bon codage !