Industrialisation d’un plan Terraform dans Azure Dev Ops
Dans le précédent article nous avons fait un tour d’horizon d’un plan d’infrastructure écrit avec Terraform et de la façon dont est géré l’état de notre infrastructure au cours de son cycle de vie. Mais afin de tirer le maximum de profit du IaC (donc de notre plan Terraform) il faut l’industrialiser, de la même manière que du code source. On peut très facilement mettre en place de la CI/CD (Continuous Integration/Continuous Delivery) grâce à Azure Dev Ops.
Pipeline de build Azure Dev Ops
Nous allons commencer par la partie CI, nous allons mettre en place une build déclenchée à chaque commit sur notre branche principale (master ou develop en fonction des conventions utilisées). Vous vous dites peut-être que ça n’a pas d’intérêt dans le cadre du IaC car notre code Terraform ne génère aucun artefact, mais il est important de valider notre IaC avant de déclencher une release. La validation de notre plan va nous assurer qu’il pourra être exécuté. On applique ici le principe du Fail-Fast. On lève une erreur dès que le plan a été mis à jour (si celui-ci n’est pas valide) avant de déclencher les déploiements de l’infrastructure via les pipelines de release.
Avant de créer notre build nous avons 2 prérequis à satisfaire :
- Dans Azure : Un service principal de créé pour exécuter les opérations de déploiement dans Azure. On peut utiliser l’Azure CLI pour cela. Une fois notre service principal créé il faut bien noter son id ainsi que le secret généré car il ne sera plus visible après.
az ad sp create-for-rbac --name TerraformSvc
- Dans Azure Dev Ops : Une Azure Ressource Manager service connection. Pour la créer allez dans les Project Settings puis dans la rubrique Pipelines -> Service connections. Les valeurs importantes ici sont le Service principal client ID qui est l’id du service principal que nous avons créé et la Service principal key qui corresponds au secret généré à l’étape précédente.

Nous allons pouvoir passer sur la définition de notre build la première tâche à utiliser est l’installation de Terraform (nous utilisons ici les pipelines Dev Ops en YAML) :
- task: ms-devlabs.custom-terraform-tasks.custom-terraform-installer-task.TerraformInstaller@0 displayName: 'Install Terraform 0.12.7' inputs: terraformVersion: 0.12.7
On passe ensuite à l’étape d’initialisation où l’on va devoir dire à Terraform que nous utilisons un remote backend pour stocker le fichier tfstate. On spécifie comme en local le nom du Storage Account et le nom du container contenant le fichier tfstate. La variable importante ici est le backendServiceArm qui correspond au nom de notre Azure Ressource Manager service connection.
- task: ms-devlabs.custom-terraform-tasks.custom-terraform-release-task.TerraformTaskV1@0 displayName: 'Init plan' inputs: workingDirectory: '$(System.DefaultWorkingDirectory)/infra' backendServiceArm: 'Terraform-Demo' backendAzureRmResourceGroupName: 'terraform-states' backendAzureRmStorageAccountName: tfstatesdcube backendAzureRmContainerName: tfstate backendAzureRmKey: 'terraform.tfstate'
Les étapes suivantes sont très simples à configurer, on exécute la commande validate de Terraform puis on récupère le dossier de scripts Terraform et on le passe comme artefact de build qui sera ensuite utilisé par les pipelines de release.
- task: ms-devlabs.custom-terraform-tasks.custom-terraform-release-task.TerraformTaskV1@0 displayName: 'Validate plan' inputs: command: validate workingDirectory: '$(System.DefaultWorkingDirectory)/infra' - task: PublishBuildArtifacts@1 displayName: 'Publish Artifact: plan' inputs: PathtoPublish: '$(System.DefaultWorkingDirectory)/infra' ArtifactName: plan
Vous noterez que je n’ai plus besoin de spécifier ma clé d’accès au Storage Account car l’authentification utilise directement les permissions de notre Service Principal.
Pipeline de release Azure Dev Ops
Nous allons maintenant mettre en place notre pipeline de release qui sera pour le moment assez simple dans la mesure où l’on ne lance pas de tests de validation de notre environnement. Dans un cas réel vous aurez sans doute des tâches à effectuer après la mise en place de l’environnement afin d’être sûr que les services soient joignables ou vous lancerez des tests de charges pour passer d‘un environnement de Recette à un environnement de Production.
Dans notre cas, nous allons mettre en place 2 stages, un de Recette (UAT) et un autre de Dev avec une validation manuelle entre les 2 stages.
Au sein de chaque stage les tâches utilisées seront identiques c’est uniquement les variables de configuration qui changeront nous allons donc commencer par tokeniser notre fichier tfvars.
env = "__env__" tenant_id = "__tenantId__" db_access_group = "__dbAccessGroup__" db_ad_admin = { id = "__dbAdAdminId__", name = "__dbAdAdminName__" } db_pwd = "__dbPassword__" app_name = "__appName__"
Ci-dessus notre fichier tfvars modifié, nous avons choisi comme convention de délimiter nos variables par des doubles underscore. Nous allons donc ensuite pouvoir commiter ce fichier de variables modifiées avec notre projet Terraform car il ne contient plus de valeurs sensibles. Il faut ensuite alimenter ce fichier par des groupes de variables, un pour chaque environnement. Pour le nommage de nos variables on prend exactement le même nom que notre token en enlevant ses délimiteurs.

Nous pouvons passer à la création de notre pipeline :

Ce pipeline de release sera défini en utilisant l’interface d’Azure Dev Ops. Dans un premier temps on sélectionne notre artefact que nous avons généré grâce à la précédente étape. On active le déploiement continu et on filtre nos artefact en spécifiant les builds de quelle(s) branche(s) seront acceptées, ici nous prenons tout simplement les builds déclenchées depuis la branche master.

On peut donc maintenant passer au contenu de notre premier stage. Il est composé de 4 tâches.

La première remplace les tokens dans notre fichier tfvars, ici sa configuration en YAML pour être plus concis. Les points importants ici sont les tokenPrefix et tokenSuffix à modifier en fonction de comment on a décoré ses token dans notre fichier de variables. Ces paramètres sont disponibles sous l’onglet avancé dans l’éditeur visuel de cette tâche.
- task: qetza.replacetokens.replacetokens-task.replacetokens@3 displayName: 'Replace tokens in **/*.tfvars' inputs: rootDirectory: '$(System.DefaultWorkingDirectory)' targetFiles: '**/*.tfvars' verbosity: detailed actionOnMissing: fail tokenPrefix: '__' tokenSuffix: '__'
Je ne vais pas revenir sur la configuration de la tâche d’initialisation de Terraform car elle est exactement identique à celle dans notre pipeline de build. Par contre on va passer sur la tâche d’application du plan Terraform, comme la tâche d’initialisation elle a besoin de la connexion de service Azure que nous avons configuré au préalable (Terraform-Demo)
- task: ms-devlabs.custom-terraform-tasks.custom-terraform-release-task.TerraformTaskV1@0 displayName: 'Terraform : apply plan' inputs: command: apply workingDirectory: '$(System.DefaultWorkingDirectory)/_Terraform Plan-CI/plan' environmentServiceNameAzureRM: 'Terraform-Demo'
Pour notre second stage les tâches sont les mêmes ce sont juste les variables de configuration qui vont changer. Je ne vais donc pas détailler sa configuration dans la mesure où l’on peut cloner notre stage UAT pour créer notre stage PROD.
Pour lier des groupes de variables on va dans l’onglet variable de notre pipeline et on lie les groupes de variables que nous avons créés à nos stages. A noter que le scope Release s’applique à tous les stages.

La dernière étape est d’ajouter une validation manuelle entre les stages UAT et PROD afin de ne pas détruire notre infrastructure de production à chaque déploiement. Une fois que notre environnement UAT est stabilisé on peut approuver le déploiement vers la PROD.

Nous avons maintenant une infra entièrement industrialisée où chaque changement est historisé et entraine un déploiement en environnement de Test (notre stage User Acceptance Test) pour valider les changements d’infrastructure et ensuite déployer cette nouvelle infrastructure en production avec une validation manuelle.
La fin
A travers les trois articles de notre série « IaC dans Azure Dev Ops » nous avons appliqué une partie des concepts Dev Ops et mis en avant les avantages de gérer sont infrastructures avec des langages tel que Terraform.
Partie 1 : C’est quoi l’Infrastructure As Code (IaC)
Partie 2 : Création d’un plan Terraform pour Azure
Partie 3 : Industrialisation d’un plan Terraform dans Azure Dev Ops (cet article)
Nous avons vu ensembles les bénéfices qu’un tel système pouvait avoir sur nos produits. Cela permet de déployer de manière rapide et contrôlée notre produit (infrastructure + application) et donc pouvoir itérer plus vite et fournir aux utilisateurs de notre produit des déploiements plus réguliers donc de nouvelles fonctionnalités/correctifs. En outre, on va pouvoir réagir très rapidement aux erreurs et faire des rollbacks complets d’environnement si une erreur est détectée, le temps de la corriger.
Le IaC s’intègre parfaitement en environnement agile dans la mesure où il soutient l’itération rapide et l’évolutivité de notre produit, l’infra est maintenant au même niveau que notre code source.
A vous de jouer maintenant et de vous lancer dans votre premier plan Terraform !
0 commentaires