Microsoft a annoncé récemment la « Public Preview » d’un provider Terraform pour Microsoft Fabric. Nous allons ici tester les basics de la mise en place d’une Infrastructure as Code (IaC) autour de Fabric !
Cet article s’inspire grandement du repository de Microsoft qui est disponible ici : microsoft/fabric-terraform-quickstart: Examples for using the Terraform Provider for Microsoft Fabric (github.com)
Intro et Prérequis
La première chose à avoir en tête à la lecture de cet article est que tout est encore en « beta », et qu’il n’est évidemment pas envisageable de l’utiliser en production car tout peut encore changer, voire même être abandonné ! Cependant on aime la nouveauté et les expériences. C’est donc le moment de plonger dans le grand bain du IaC avec Fabric !
D’un point de vu pratique, je me demande si je ne vais pas gérer mes petits environnements Fabric de démo pour ce blog via Terraform ! Ce n’est pas de la prod et si cela est concluant, nous économiserons quelques clics sur le service !
Pour utiliser Terraform, je vais utiliser sur une machine windows un terminal Powershell avec le module Azure CLI d’installer. Pour ce faire, c’est ici : Installer Azure CLI pour Windows | Microsoft Learn
Authentification et autorisations
Terraform ne peut pas intervenir « seul » sur les différentes plateformes d’infrastructure. Nous allons avoir besoin soit de le faire fonctionner « en notre nom », soit en créant un utilisateur spécifique. Pour la réalisation de mes tests et démos personnels, je n’ai pas besoin d’utiliser un utilisateur particulier et j’utilise généralement l’authentification via « Azure CLI » qui demande une ouverture de session via le navigateur web et les méthodes d’authentification classique pour vous connecter à votre compte Azure/Microsoft. L’avantage est que cela va utiliser notre compte pour toutes les actions et donc nos autorisations … si tant est que nous les ayons ! La documentation Terraform pourra nous guider : Authenticate using the Azure CLI | Terraform | HashiCorp Developer
Pour une utilisation un peu plus automatisée, sécurisés ou dans un environnement professionnel, nous utiliserons plutôt un « Service Principal » à qui nous aurons donné les droits adéquats. Il peut être nécessaire de demander la création de ce Principal à une équipe dédiée à la création de comptes si vous n’avez pas vous-même tous les accès pour le faire. Encore une fois, la doc est là pour vous : Create a Service Principal | Terraform | HashiCorp Developer
IaC via Terraform
L’idée derrière le IaC est de décrire de façon programmatique l’infrastructure qui hébergera ensuite notre code. Ceci va permettre de ne pas dépendre de quelques clics qui pourraient être oubliés ainsi que de versionner notre infrastructure. Il existe de nombreux outils qui peuvent être dédiés au cloud, au On-Prem, ou à un éditeur précis. Terrafrom est une solution multi-plateforme et cloud agnostique qui nous permet de coder une infrastructure sur des architectures différentes.
Terraform n’est pas un outil qui va exécuter des scripts dans un certain ordre comme on pourrait le faire via Python, Powhershell ou AzureCLI. C’est un outil ou l’on va décrire l’infrastructure telle que nous la souhaitons et qui va définir (puis exécuter) les scripts nécessaires pour atteindre l’état décrit par rapport à un état actuel.
Pour plus d’informations, c’est par ici : Terraform by HashiCorp
Pour ce faire, Terraform utilise des « Providers », qui servent à définir une infrastructure et faire le lien vers ces api/scripts permettant de créer/gérer cette infrastructure. Il existe des Providers « officiels » faits par les éditeurs d’infrastructure et de cloud, mais aussi des Producteurs tiers.
Nous sommes ici car Microsoft à fait l’annonce de son Provider Terraform pour Fabric : Announcing the new Terraform Provider for Microsoft Fabric (Public Preview) | Microsoft Fabric Blog | Microsoft Fabric. C’est donc celui que nous allons essayer.
Installation de Terraform
La documentation de Terraform est plutôt bien faite et l’installation l’est tout autant. Voici la documentation officielle concernant l’installation : Install | Terraform | HashiCorp Developer.
Sur un poste Windows, il suffit de télécharger le binaire, de la placer dans un répertoire dédié puis d’ajouter à la variable d’environnement « Path », le chemin en question.
Une fois fait, pour vérifier que tout fonctionne, nous allons ouvrir une invite de commande pour y exécuter la commande suivante :
terraform -v
Si tout c’est bien passé, nous devrions avoir comme retour le numéro de version de Terraform :
Utilisation de Terraform
Premiers fichiers d’exemples
Terraform utilise des fichiers « .tf » qui sont écrits au format YAML. C’est une sorte de notation d’objets json qui utilise une notation et une indentation assez stricte. La majorité des éditeurs de code ont une extension pour les fichiers Terraform qui vous aideront à respecter cette notation. Dans nos exemples, nous allons rester très simples dans nos définitions, nous n’aurons donc pas vraiment de problème d’écriture.
Si nous écrivons souvent différents fichiers, avec des noms un peu précis, globalement Terraform n’y apporte pas grande importance tant que ce qui est écrit est correcte à l’intérieur de l’ensemble des fichiers .tf du répertoire d’exécution.
Comme dans beaucoup de projets de code, la première chose que nous allons devoir définir, ce sont nos « dépendances ». Nous allons ici principalement parler de Providers. Pour les définir, nous allons donc créer dans notre répertoire projet un fichier « providers.tf ». Ce nom va simplement nous servir à nous rappeler que dans ce fichier nous allons déclarer l’ensemble de nos providers :
# providers.tf
terraform {
required_version = ">= 1.8, < 2.0"
required_providers {
fabric = {
source = "microsoft/fabric"
version = "0.1.0-beta.4"
}
}
}
Dans ce block de code, nous indiquons :
- la version de Terraform. Ici nous demandons à minima la version 1.8 mais aussi strictement inférieur à 2.0
- la liste des providers que nous utiliserons dans notre projet
- nous définissons ici le provider Fabric dans sa version 0.1.0-beta.4
Une fois nos dépendances définies, nous allons commencer à décrire notre architecture ! La nomenclature traditionnelle est de commencer à décrire celle-ci dans un fichier « main.tf », qui va être notre fichier principal de description. Comme dans tout projet Fabric, nous aurons besoin d’un workspace. Nous allons donc, dans un premier temps créer uniquement un workspace Fabric.
# main.tf
resource "fabric_workspace" "ws_fabric" {
display_name = "NiceData - Fabric Terraform"
}
A la ligne 3, nous définissions que l’on souhaite créer une « ressource », de type « fabric_workspace », que l’on appellera dans notre projet Terraform « ws_fabric ».
A la ligne 4, nous commençons à définir les propriétés de notre ressource. Dans le service en ligne Fabric, la seule chose obligatoire qui nous est demandée est le nom du workspace. Nous le définition ici via la propriété « display_name » à laquelle nous donnons la valeur « NiceData – Fabric Terraform ».
Initialisation de Terraform
La première commande à exécuter avec Terraform va nous servir à initialiser notre répertoire projet. Pour ce faire, rien de plus simple. Il suffit d’ouvrir notre terminal, de nous placer dans le répertoire de notre projet et d’y exécuter la commande relativement parlante :
terraform init
le résultat ressemblera normalement à quelque chose du genre :
Globalement, cela va télécharger les dépendances et instancier certains fichiers interne à Terraform.
Application de la description
Dans le monde Terraform, nous allons demander à « Appliquer » notre configuration d’infrastructure. C’est donc assez naturellement que nous utiliserons la commande :
terraform apply
Terraform va dans un premier temps analyser l’état actuel de notre infrastructure et va planifier les actions qu’il a besoin de réaliser pour arriver à la description de notre infrastructure. La commande « apply », va donc dans un premier temps présenter les actions qu’il va devoir réaliser et vous demander si vous souhaitez vraiment réaliser ces actions. Pour accepter nous entrerons « yes » :
Et c’est à ce moment que notre infrastructure commence à se créer :
Nous pouvons aller vérifier directement dans le service :
Destruction de l’infrastructure
Maintenant que nous sommes en capacité de construire notre infrastructure très rapidement (et sans risque de nous tromper), nous allons pouvoir détruire celle-ci de la même façon. L’idée c’est que nous créons régulièrement des infrastructures pour des POC, projets, tests ou actions limitées dans le temps. Cependant, entre deux initiatives, l’infrastructure n’est plus utilisée et peux donc soit induire un cout direct pour des ressources cloud ou réserver de la ressource qui pourraient être octroyé à d’autres initiatives (sur des serveurs de VM ou directement sur le poste développeur par exemple).
De la même façon que pour appliquer notre configuration, nous allons pouvoir la détruire très simplement :
terraform destroy
Une fois encore, avant de détruire l’intégralité de notre infrastructure, Terraform va nous décrire ces actions et en entrant « yes », nous validons la destruction.
En rafraichissant notre fenêtre Fabric, nous avons cette fois une pop-up qui nous indique que nous n’avons plus accès à celui-ci. Si le message n’est pas totalement représentatif de la réalité, celui-ci est en fait générique sur le fait que nous n’avons plus accès au workspace, peu importe la raison ! Dans les faits, le workspace étant supprimé, nous n’avons effectivement plus accès à celui-ci.
L’intégralité du code de cette première partie se trouve sur le github dédié : MsFabric_Terraform | fabric_101
Création d’une capacité Fabric avec Terraform
Si la création d’un workspace est une étape importante, cela ne nous aidera pas beaucoup dans nos travaux avec Fabric ! Ce qui fera vraiment la différence sera la création et l’assignation d’une capacité Fabric à un workspace. Et nous allons devoir passer par la case ressource group pour faire ca bien !
Création d’un ressource groupe Azure
Avant toutes choses, une capacité Fabric étant une ressource Azure, il va nous falloir un ressource groupe dans lequel héberger notre capacité. Pour manipuler nos ressources Azure, nous allons utiliser le Azure Ressource Manager (azurerm). Et notre fichier « providers.tf » sera déclaré de la sorte :
# providers.tf
terraform {
required_version = ">= 1.8, < 2.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "4.4.0"
}
}
}
provider "azurerm" {
features {}
}
Vous remarquerez la section provider qui est nouvelle pour nous. Elle sert à configurer le provider en question. Ce block est nécessaire même si nous ne souhaitons rien configurer de particulier. Ici nous pourrions par exemple déclarer la souscription et le tenant à utiliser. Nous l’avons dans notre cas déjà déclaré en tant que variables d’environnements et n’avons pas à les surcharger.
Il est maintenant temps de déclarer ce ressource group dans notre fichier « main.tf »
# main.tf
resource "azurerm_resource_group" "rg-fabric" {
name = "rg-nicedata-fabricterraform"
location = "France central"
}
Nous n’allons pas hésiter à tester notre configuration à chaque étape avec un terraform apply (et init pour la première exécution, ou modification des providers) :
Un tour du côté d’azure nous montrera notre ressource groupe créé dans la bonne souscription :
Création de la capacité Fabric
Nous allons continuer la description en ajoutant cette fois notre capacité Fabric. Oui, nous y sommes enfin !!
Nous commençons par l’ajout des providers nécessaires. En ajoutant uniquement le provider « fabric », j’ai des erreurs m’indiquant qu’il me manque « azapi » … Nous travaillons sur un outil en bêta et je ne suis pas forcément choqué que ce « Azure API » soit utilisé quelque part. Nous allons donc le rajouter a nos définitions pour que tout le monde soit contant !
# providers.tf
terraform {
required_version = ">= 1.8, < 2.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "4.4.0"
}
azapi = {
source = "Azure/azapi"
version = "1.15.0"
}
fabric = {
source = "microsoft/fabric"
version = "0.1.0-beta.4"
}
}
}
provider "azurerm" {
features {}
}
provider "fabric" {
}
Pour décrire notre capacité, la petite subtilité sera que comme une capacité Fabric doit être dans un ressource groupe, nous allons devoir passer l’id de notre ressource groupe à notre capacité. Ici, nous allons pouvoir profiter de la puissance de Terraform pour lui passer un « chemin de variable » pour indiquer à Terraform ce qu’il doit envoyer à notre ressource. C’est maintenant que nous comprenons l’intérêt de « nommer » nos ressources Terraform. Nous avons nommé, dans Terraform, notre ressource groupe « rg-fabric » (attention, ce n’est pas le nom du ressource groupe azure, mais bien le nom de la ressource Terraform !) et cette ressource possède une variable nommée « id ». nous pourrons donc connaitre l’idée de notre groupe de ressource de la manière suivante :
#[ressourcetype].[ressourcename].[variablename]
azurerm_resource_group.rg-fabric.id
Pour la configuration de notre capacité, nous allons définir plusieurs paramètres et notamment :
- les classiques :
- nom – attention aux règles spécifiques de nommage de chaque type de ressource
- localisation
- ressource groupe
- les spécifiques
- SKU (la « taille »)
- les utilisateurs, notamment administrateur
Voici à quoi va ressembler notre main.tf :
# main.tf
resource "azurerm_resource_group" "rg-fabric" {
name = "rg-nicedata-fabricterraform"
location = "France central"
}
resource "azapi_resource" "fc-fabric" {
type = "Microsoft.Fabric/capacities@2023-11-01"
name = "fcnicedatafabricterraform"
parent_id = azurerm_resource_group.rg-fabric.id
location = "France central"
body = {
sku = {
name = "F2"
tier = "Fabric"
}
properties = {
administration = {
members = [
"[UPN de l'administrateur]"
]
}
}
}
}
Utilisation des « data » Terraform
Dans la section précédente, nous avons mis en dure l’UPN d’un utilisateur (probablement notre mail), et cela n’est évidemment pas une bonne pratique ! Nous allons donc utiliser une autre fonctionnalité de Terraform que sont les « data ». L’idée est de faire une sorte d’appel api et de stocker le résultat dans une variable utilisable par la suite. Dans le cas présent, nous allons « appeler une api » Microsoft Entra pour avoir des informations sur l’utilisateur connecté, tel que le « user_principal_name » à passer à notre capacité Fabric ! (Cet appel va lui-même demander des informations sur le client azure rm)
cela nous donne pour la partie provider, l’ajout de « hashicorp/azuread » :
# providers.tf
terraform {
required_version = ">= 1.8, < 2.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "4.4.0"
}
azapi = {
source = "Azure/azapi"
version = "1.15.0"
}
azuread = {
source = "hashicorp/azuread"
version = "3.0.2"
}
fabric = {
source = "microsoft/fabric"
version = "0.1.0-beta.4"
}
}
}
provider "azurerm" {
features {}
}
provider "fabric" {
}
Puis, côté main.tf, nous avons ajouté les deux créations de « data » et l’utilisation de ces données notamment pour le UPN pour la capacité Fabric :
# main.tf
data "azurerm_client_config" "rmclient" {}
data "azuread_user" "user" {
object_id = data.azurerm_client_config.rmclient.object_id
}
resource "azurerm_resource_group" "rg-fabric" {
name = "rg-nicedata-fabricterraform"
location = "France central"
}
resource "azapi_resource" "fc-fabric" {
type = "Microsoft.Fabric/capacities@2023-11-01"
name = "fcnicedatafabricterraform"
parent_id = azurerm_resource_group.rg-fabric.id
location = "France central"
body = {
sku = {
name = "F2"
tier = "Fabric"
}
properties = {
administration = {
members = [
data.azuread_user.user.user_principal_name
]
}
}
}
}
Attention, lors de la création de la capacité azure, celle-ci est au statut « active » et peux engendrer des coûts. Il faut bien penser à la mettre en pause ou la supprimer (terraform destroy !!!) lorsque nous ne l’utilisons pas.
Nous avons donc maintenant une capacité Fabric créée et active dans notre ressource groupe :
Création du workspace et association de la capacité Fabric
Nous allons réutiliser ce que nous avons fait dans la première partie de cet article et juste ajouter une nouvelle data Terraform, pour récupérer l’id de notre capacité Fabric et la passer à notre workspace :
# main.tf
data "azurerm_client_config" "rmclient" {}
data "azuread_user" "user" {
object_id = data.azurerm_client_config.rmclient.object_id
}
resource "azurerm_resource_group" "rg-fabric" {
name = "rg-nicedata-fabricterraform"
location = "France central"
}
resource "azapi_resource" "fc-fabric" {
type = "Microsoft.Fabric/capacities@2023-11-01"
name = "fcnicedatafabricterraform"
parent_id = azurerm_resource_group.rg-fabric.id
location = "France central"
body = {
sku = {
name = "F2"
tier = "Fabric"
}
properties = {
administration = {
members = [
data.azuread_user.user.user_principal_name
]
}
}
}
}
data "fabric_capacity" "fc-fabric" {
display_name = azapi_resource.fc-fabric.name
}
resource "fabric_workspace" "ws-fabric" {
capacity_id = data.fabric_capacity.fc-fabric.id
display_name = "NiceData - Fabric Terraform"
}
Attention, afin d’associer notre capacité Fabric à notre workspace, il est impératif que la capacité soit active. Si nous l’avons déjà créée puis mise en pause, nous aurons une erreur lors de la création du workspace : « Could not create resource: Target capacity is not in active state ». Il nous faudra soit la réactiver, soit la détruire pour qu’elle soit recréée.
Nous avons maintenant un environnement complet :
L’intégralité du code de cette seconde partie se trouve sur le github dédié : MsFabric_Terraform | fabric_capacity&ws
Conclusion
Nous avons vu dans cet article comment automatiser la création (et la suppression) d’un environnement de travail Fabric. Si l’écriture du code servant à décrire notre architecture peut prendre un peu de temps au démarrage, il faut bien voir que le but et d’accélérer les déploiements futurs. Aujourd’hui, pour créer un petit environnement de test, il ne me faut que 20 secondes pour tout créer et tout détruire à la fin de ma journée !
Evidemment dans cet article nous avons fait les choses « simples ». Nous avons deux axes à travailler :
- L’utilisation de variables dans Terraform afin de rendre le tout un peu plus exploitable. A l’instant le nom de nos ressources sont en dur !!
- L’exploitation et la manipulation des objets fabric ! Configuration d’un repos git, déploiement de notebook Spark, de lakehouse et autre … !