Comment crafter une infrastructure avec Terraform ?

L’IaC (Infrastructure as Code) est une pratique de développement logiciel permettant le déploiement et la gestion du cycle de vie des ressources d’infrastructures. Ces ressources peuvent être des machines virtuelles (VM), mais aussi des services managés (App Service pour du compute, Azure SQL Database pour de la Data ou Azure Service Bus pour un service de messaging).
Cette approche est nécessaire pour profiter des avantages du Cloud, de son élasticité et de ses usages :
- Gérer l’ensemble des environnements, depuis le développement jusqu’à la production ;
- Le provisionnement d’environnements éphémères, dont la durée de vie est scopée sur leur utilisation réelle ;
- Faire évoluer son infrastructure, qui n’est plus gravée dans le marbre lors de la mise en place d’un projet, mais évolue au fil du temps, que cela soit en termes de dimensionnement ou de services
Terraform est aujourd’hui un outil d’IaC devenu incontournable, à travers son approche déclarative, sa gestion de l’idempotence, et sa capacité à interagir avec un large panel de Cloud Providers et de services grâce à ses providers.
Nous allons voir dans cet article comment les principes du Software Engineering peuvent et doivent être appliqués pour une utilisation optimale de Terraform.
Le Craft appliqué à Terraform
Terraform est un outil d’Infra as Code. Il est donc naturel d’appliquer l’ensemble des bonnes pratiques que nous connaissons pour la gestion du code.
Comme rappelé dans le premier article de ce Mois du Craft, cette culture doit s’appliquer à tous les niveaux, et le Cloud et l’infrastructure ne font pas exception.
Lisibilité
La lisibilité est un élément essentiel dans une démarche Craft. Elle est nécessaire dans une approche d’IaC pour garantir :
- De pouvoir faire évoluer son infrastructure rapidement ;
- De ne pas créer de goulot d’étranglement, avec une seule personne capable de comprendre et maintenir un template Terraform.
Un template standardisé
L’utilisation d’un template standardisé permet de fournir une structure commune, partagée et comprise. Elle facilite la prise en main, et permet un bootstrappe rapide.
Le template Terraform classique s’organise de la façon suivante :
- main.tf contient les ressources, les datasources, les locals et les appels de modules.
- variables.tf contient la déclaration de l’ensemble des variables. Ces variables doivent être documentées (type et description).
- versions.tf contient les informations de versions sur Terraform et les différents providers utilisés.
- providers.tf contient la configuration spécifique de chaque provider. Celle-ci étant spécifique au type de provider, cela dépendra de ceux que vous utilisez (pour azurerm par exemple, on retrouvera les features à activer ou l’activation de l’enregistrement automatique des providers).
À cette organisation standard viendront s’ajouter, pour les infrastructures complexes, d’autres fichiers qui permettront de ne pas se retrouver avec un main.tf de 3000 lignes, difficilement maintenable et lisible. On pourra s’orienter sur une structuration par types de service (compute, data…).
Le nommage des ressources
Il ne s’agit pas ici du nom des ressources déployées, mais de leur nom interne dans le template Terraform. Par exemple, un Resource Group Azure peut être déclaré de la façon suivante :
resource "azurerm_resource_group" "rg" { … }
Le nom interne de ce Resource Group est ici rg, et c’est avec ce nom qu’on pourra le référencer dans la déclaration des ressources qu’il contiendra. Il est important, dès le début du projet, de s’astreindre à utiliser des noms qui permettront de comprendre l’usage des ressources sans ambiguïté.
Quand l’infrastructure évoluera, on pourra y retrouver 4 Resource Groups, qui seront respectivement nommés rg_1,rg_2,rg_3 et rg_5. À quoi servent-ils ? Où se trouve rg_4 ? Pourquoi n’est-il n’est pas là ? Puis-je utiliser ce nom pour le Resource Group que je dois créer ? Voici autant de questions qu’il faut éviter d’avoir à se poser.
Robustesse
Autre pilier d’une culture Craft : la robustesse du code permet de garantir qu’au moment du déploiement, l’infrastructure correspondra aux attentes. Cela passe par la mise en place d’une stratégie de tests.
L’Infra as Code partage avec le développement applicatif un même principe : plus un bug est détecté tardivement, plus sa résolution occasionnera des coûts importants.
Ces tests ne doivent pas se substituer à un hardening et un monitoring des environnements Cloud, ils sont complémentaires. Ils permettront de détecter et corriger au plus tôt les problèmes de configurations.
Les tests d’infrastructures
Leur but est de valider :
- La bonne fin technique d’un déploiement. Ils permettent d’identifier les erreurs dans le template, telles que des dépendances ayant besoin d’être explicitées ou la mise en place d’un timer entre deux ressources.
- La variabilisation et l’interpolation. Le nom des ressources est-il bien celui prévu ? Les instructions for_each ou count sont-elles bien implémentées ?
Ces tests vont nécessiter un environnement dédié où l’on pourra de façon répétable, déployer, tester et supprimer une infrastructure.
L’implémentation peut se faire avec différents outils :
- Pester: un framework de test généraliste en Powershell. Le workflow sera alors déploiement (terraform apply) -> test (Invoke-Pester) puis suppression (terraform destroy).
- Terratest ou Kitchen et son plugin Terraform qui prendront en charge la création et la suppression de l’infrastructure.
Dans l’idéal, ces tests doivent être lancés à chaque incrément apporté à un template Terraform. En fonction des ressources, le temps de déploiement peut être relativement important (par exemple une instance d’Azure API Management ou un App Service isolated) et on pourra préférer, dans ce type de situation, de lancer ces tests en Nightly Build, avec une fréquence adaptée.
L’analyse statique de code
Il est possible d’utiliser des outils d’analyse statique afin de détecter, avant même de déployer la moindre ressource, d’éventuels problèmes de configuration ou de syntaxe.
Terraform fournit nativement deux commandes pouvant répondre à cet objectif :
- Terraform fmt permet de s’assurer que le template est au format canonique ;
- Terraform validate permet de valider la syntaxe et la configuration.
On pourra y associer d’autres outils comme Checkov ou terrascan permettant de vérifier la configuration et valider, par exemple, que :
- Les tags sont bien appliqués sur les ressources ;
- La configuration de l’exposition Internet correspond aux règles de sécurité ;
- L’utilisation de certains tiers est interdite pour des raisons de coûts.
Maintenabilité
Garantir la maintenabilité d’un projet Terraform durant tout le cycle de vie (un projet ne s’arrête pas après le premier déploiement) nécessite d’adopter un ensemble de pratiques issues du Software Engineering.
Utiliser un gestionnaire de code source
Ce point parait évident quand il s’agit de développement applicatif. En fonction de la maturité des organisations, il ne l’est pas forcément quand il s’agit de projet Terraform.
Il est indispensable d’utiliser un gestionnaire de code source et de définir clairement son cadre d’utilisation (branches, type de flow utilisé…).
Ces processus doivent être documentés et revus régulièrement.
Utiliser un remote backend
Terraform, pour son fonctionnement, nécessite un fichier d’état : le tfstate. Sans rentrer dans les détails de son contenu, ce fichier est aussi important que le template lui-même. Un déploiement ne peut se faire sans lui.
Ce fichier contient des éléments sensibles et ne doit pas être présent dans un gestionnaire de source.
Terraform permet plusieurs types de backends pour pouvoir le stocker, notamment :
- Un backend local. Le fichier d’état est stocké localement, à côté du template. Ce type de backend doit être utilisé pour des cas d’usages bien spécifiques (valider une feature, faire un test en local) sur des scopes extrêmement limités et ne se prête pas à des scénarios industrialisés.
- Un backend azurerm (pour les projets sur le Cloud Azure, il s’agit d’un choix logique). Ce type de backend est pertinent, car il permet à la fois de sécuriser ce fichier (via le modèle RBAC appliqué au compte de stockage sous-jacent) et de faciliter le travail collaboratif (le blob storage peut être utilisé par chaque membre de l’équipe, ou un Service Principal quand on travaille avec des pipelines).
Pipelines
L’intégration continue apporte énormément de valeur. Tous les tests évoqués précédemment doivent être intégrés et lancés systématiquement, le plus souvent et le plus tôt possible.
Le déploiement automatisé, jusqu’en production, est également un point important. Pouvoir déployer de façon prédictible, depuis un agent de déploiement connu, en utilisant une ou des identités dédiées est un facteur clé de la réussite d’un projet Terraform.
Les avantages du Craft, les risques également
Adopter une culture Craft pour les projets Terraform est bénéfique, mais cette adoption va également exposer aux mêmes risques qu’une démarche Craft sur un projet applicatif.
Premature optimization
Une “premature optimization” est la mise en place d’un code, supposément optimisé, avant que le besoin réel ne soit validé.
Dans un projet Terraform, cela peut se traduire par l’utilisation abusive de modules. Les modules sont un excellent moyen d’appliquer le principe du DRY (Don’t Repeat Yourself). Leur mise en place prématurée peut être contreproductive. Ils peuvent se révéler compliqués à maintenir et faire évoluer.
La complexité accidentelle
La complexité accidentelle dans un projet Terraform est le résultat d’une implémentation prenant en compte des fonctionnalités ou des cas d’usages non nécessaires, provoquant une difficulté à maintenir ou faire évoluer un template.
Un exemple serait de vouloir dès le début gérer du multi-régions pour une géo-redondance, là où l’infrastructure demandée est mono-région. Il va en résulter des boucles et une interpolation inutile, rendant la compréhension et la maintenabilité difficile.
Alors, on crafte ou pas ?
En conclusion, oui, craftez vos infrastructures ! Le retour sur investissement d’une démarche Craft dans des projets Terraform (ou autres outils d’IaC) est extrêmement important.
Il est même obligatoire pour bénéficier de tous les avantages du Cloud.
Le succès d’une telle démarche résidera aussi dans la capacité, à l’échelle de l’organisation, à faire tendre vers ce modèle de façon raisonnée et progressive en suivant les principes suivants :
- Établir une roadmap;
- Utiliser des baby steps, avec un incrément de valeur rapide et démontrable ;
- Expérimenter sur les outils, pratiques, frameworks …
- Capitaliser sur les projets réussis, et aussi ceux en échec ;
- Documenter, diffuser et industrialiser.
Vous souhaitez en savoir plus sur le Craftsmanship ? Retrouvez tous les articles de notre série du Mois du Craft :
- Le Craft est-il toujours d’actualité ?
- Comment choisir l’architecture logicielle idéale grâce aux Architectural Drivers ?
- Craft et PowerShell : de la nécessité d’appliquer les pratiques de Software Engineering à l’architecture
- Les bonnes pratiques de tests unitaires PySpark
- Télémétrie : la garantie d’un code qui fonctionne
- Boostez la performance de vos applications avec Asyncio : un guide pratique pour les développeurs Python