← Tots els posts

Terraform i Microsoft Fabric a la pràctica: un medallion en un sol apply

Demo pas a pas amb vídeo: una capacity, 9 workspaces, 36 grups d'Entra ID i els seus rols a Microsoft Fabric amb Terraform. Plan, apply, drift i destroy.

DevOpsFabricArquitectura Traduït de l’original en castellà

A l’article anterior vam veure la teoria: què és Infrastructure as Code, com s’escriu un recurs, què és l’estat i per què cal llegir el plan abans de cada apply.

Avui anem per la demo. L’encàrrec: el medallion d’un projecte que es diu «ventas» (vendes). Tres capes (bronze, silver i gold) per tres entorns (dev, test i prod), cada workspace amb els seus quatre grups de seguretat i els seus quatre rols. I la capacity a sota, que tampoc no existeix encara.

A mà serien nou workspaces, 36 grups i 36 assignacions de rols. Amb Terraform és un apply.

Aquest és el vídeo de la demo que vam fer l’Alfonso Ming i jo a la NetCoreConf.

El vídeo no té so: t’explico cada pas aquí sota.

El codi és a github.com/marlizana/FabricAsCode.


Pas 0: no hi ha res

Abans de començar, comprovem que el punt de partida és buit:

  • Fabric: filtres la llista de workspaces per «ventas». No en surt cap.
  • Azure: a Fabric capacities no hi ha cap capacity del projecte.
  • Entra ID: busques els grups sg-fbc-ventas. Cap.

Pas 1: el codi de Terraform, de dalt a baix

El repo té aquesta pinta:

FabricAsCode/
├── versions.tf          # providers i versions
├── main.tf              # connecta les peces
├── variables.tf
├── outputs.tf
├── environments/        # un .tfvars per escenari
├── modules/
│   ├── capacity/
│   ├── workspace-with-roles/
│   └── templates/medallion-cicd/
└── scripts/demo.ps1     # dreceres per a la demo

versions.tf: els providers

terraform {
  required_providers {
    azurerm = { source = "hashicorp/azurerm", version = "~> 4.0" }
    azuread = { source = "hashicorp/azuread", version = "~> 3.0" }
    fabric  = { source = "microsoft/fabric",  version = "~> 1.14" }
  }
}

provider "azurerm" { features {} }
provider "azuread" {}
provider "fabric" {}

azurerm crea la capacity, azuread els grups i fabric els workspaces i els rols. Els blocs provider van buits expressament: les credencials del service principal arriben per variables d’entorn.

environments/ventas.tfvars: l’encàrrec

capacity_name = "fbcventas"
capacity_sku  = "F2"
region        = "spaincentral"

template     = "medallion-cicd"
project_name = "ventas"
layers       = ["bronze", "silver", "gold"]
environments = ["dev", "test", "prod"]

admin_group_members = [
  "mar@contoso.onmicrosoft.com",
  "alfonso@contoso.onmicrosoft.com",
]

Aquí hi ha tot el que canvia d’un projecte a un altre: la mida de la capacity, la regió, les capes, els entorns i qui entra als grups Admin. Per a un projecte nou es copia aquest fitxer i el codi no es toca.

main.tf: uneix les peces

Crida el mòdul de la capacity i el template medallion-cicd, i li passa al template l’ID de la capacity.

modules/capacity/main.tf: la capacity de Fabric

Un resource group i un azurerm_fabric_capacity amb SKU F2. I un detall que em va costar un plan fallit:

# L'ID d'Azure no és l'ID de Fabric: aquesta data source fa de pont.
data "fabric_capacity" "this" {
  display_name = azurerm_fabric_capacity.this.name
}

azurerm retorna l’ID de recurs d’Azure, però un workspace espera el GUID de Fabric. La data source busca la capacity pel nom i retorna l’ID que necessita el workspace.

modules/templates/medallion-cicd/main.tf: les combinacions

locals {
  workspace_specs = {
    for pair in setproduct(var.layers, var.environments) :
    "${pair[0]}-${pair[1]}" => { layer = pair[0], env = pair[1] }
  }
}

module "workspace" {
  source   = "../../workspace-with-roles"
  for_each = local.workspace_specs

  workspace_name  = "${var.project_name}-${each.value.layer}-${each.value.env}"          # ventas-bronze-dev
  ad_group_prefix = "sg-fbc-${var.project_name}-${each.value.layer}-${each.value.env}"   # sg-fbc-ventas-bronze-dev
  capacity_id     = var.capacity_id
  admin_members   = var.admin_members
}

setproduct combina les dues llistes i en surten nou parelles capa-entorn. Per a cadascuna es crida el mateix mòdul amb el seu nom i el seu prefix de grups.

modules/workspace-with-roles/main.tf: workspaces, grups i rols

resource "fabric_workspace" "this" {
  display_name = var.workspace_name
  capacity_id  = var.capacity_id
}

resource "azuread_group" "roles" {
  for_each         = var.roles   # Admin, Contributor, Member, Viewer
  display_name     = "${var.ad_group_prefix}-${lower(each.value)}"
  security_enabled = true
  members          = each.value == "Admin" ? var.admin_members : null
}

resource "fabric_workspace_role_assignment" "this" {
  for_each     = azuread_group.roles
  workspace_id = fabric_workspace.this.id
  role         = each.key
  principal    = { id = each.value.object_id, type = "Group" }
}

Un workspace, un grup per rol i una assignació que lliga cada grup al seu rol. Aquest mòdul, cridat nou vegades, és el que genera els 36 grups i les 36 assignacions.


Pas 2: terraform plan

Amb les credencials en variables d’entorn:

terraform init
terraform plan "-var-file=environments/ventas.tfvars" "-out=ventas.tfplan"

Compte: a Windows PowerShell 5.1, posa entre cometes els arguments que porten un punt. Sense cometes, -var-file=environments/ventas.tfvars es parteix en dos i Terraform es queixa de «Too many command line arguments».

Al plan val la pena aturar-se en quatre llocs: la capacity, un workspace, un grup i una assignació de rol. I després a l’última línia:

Plan: 84 to add, 0 to change, 0 to destroy.

Les 84 són nou workspaces, 36 grups, 36 assignacions, la capacity, el seu resource group i el sufix aleatori del seu nom. Cap canvi i cap esborrat, que és el que esperes la primera vegada.


Pas 3: terraform apply

terraform apply ventas.tfplan

Primer es crea la capacity, que triga un parell de minuts. Després, en paral·lel, els grups i els workspaces. Al final:

Apply complete! Resources: 84 added, 0 changed, 0 destroyed.

Mentre corre, hi ha temps per a un cafè.


Pas 4: el que ha creat

  • Azure: la capacity, al seu propi resource group.
  • Entra ID: busques sg-fbc-ventas i surten 36 grups. A sg-fbc-ventas-silver-prod-admin, pestanya Members, hi som l’Alfonso i jo.
  • Fabric: filtres per «ventas» i surten els nou workspaces. A ventas-silver-prod, Manage access mostra els quatre grups, cadascun amb el seu rol. I a Workspace settings → License, la capacity.

Els nou workspaces segueixen el mateix patró de noms i tenen exactament els mateixos permisos.


Pas 5: tornar a llançar el plan

Què passa si torno a fer plan sense canviar res?

No changes. Your infrastructure matches the configuration.

Res. Com explicava a la teoria, apply es comporta com un MERGE: el pots llançar deu vegades i continues tenint nou workspaces.


Pas 6: drift, algú ha tocat el portal

Ara faig de companya amb pressa: entro a ventas-silver-prod, Manage access, i trec el grup sg-fbc-ventas-silver-prod-viewer. «Un momentet, per provar».

Plan una altra vegada:

  # module.medallion_cicd[0].module.workspace["silver-prod"].fabric_workspace_role_assignment.this["Viewer"] will be created
  + resource "fabric_workspace_role_assignment" "this" { ... }

Plan: 1 to add, 0 to change, 0 to destroy.

Terraform ha consultat Fabric, ha vist que aquesta assignació ja no existeix i proposa tornar-la a crear. Un apply i el grup torna a tenir el seu rol.


Pas 7: un entorn més en una línia

I si demà cal QA? S’afegeix al .tfvars:

environments = ["dev", "test", "qa", "prod"]

I el plan:

Plan: 27 to add, 0 to change, 0 to destroy.

Tres workspaces (bronze, silver i gold de QA), dotze grups i dotze assignacions, amb el mateix patró que la resta. Els entorns que ja existien no es toquen.


Pas 8: terraform destroy

Quan el projecte, la demo o la prova de concepte s’acaba:

terraform plan -destroy "-var-file=environments/ventas.tfvars" "-out=borrar.tfplan"
terraform apply borrar.tfplan

Llegeix el plan abans: ha de dir 84 to destroy i res més. S’esborren els workspaces, els grups i la capacity, i sense la capacity es deixa de facturar.

Compte: amb la capacity en pausa, el provider de Fabric no deixa fer ni plan, ni apply, ni destroy. Reprèn-la abans i espera que estigui Active.


L’script de la demo

Al repo veuràs scripts/demo.ps1. Embolcalla aquestes mateixes ordres per no haver de teclejar-les davant de 200 persones.

DreceraQuè fa
. .\scripts\demo.ps1 envCarrega les credencials a la sessió (amb el punt davant)
.\scripts\demo.ps1 initterraform init i el workspace d’estat
.\scripts\demo.ps1 planPlan amb el .tfvars de l’escenari
.\scripts\demo.ps1 applyPlan a fitxer, confirmació i apply d’aquest fitxer
.\scripts\demo.ps1 driftPlan per veure què ha canviat fora de Terraform
.\scripts\demo.ps1 qa / sin-qaAfegeix o treu l’entorn de QA
.\scripts\demo.ps1 pausa / reanudaPosa en pausa o reprèn la capacity
.\scripts\demo.ps1 destroyPlan d’esborrat, confirmació i destroy

Abans i després

AbansDesprés
Una tarda de clics per projecteUn apply d’uns minuts
Un Word desactualitzat com a documentacióEl codi descriu com està la plataforma
QA i pro semblants, però no igualsTots els entorns surten del mateix mòdul
«Qui ha tret aquest rol?» sense respostaEl drift apareix al següent plan

El següent projecte comença copiant un .tfvars en lloc d’obrir el portal. Si ho proves amb el repo, explica’m als comentaris com t’ha anat.

La Pris, la meva gata, ha vist el vídeo sencer i la seva única aportació ha estat asseure’s al teclat durant l’apply. Per sort ja estava aplicant el plan desat.


Enllaços d’interès

T’ha servit? Aplaudeix, sense compte. Pots fer-ho diverses vegades.

Comentaris