← Tots els posts

Terraform per a gent de dades: Infrastructure as Code a Microsoft Fabric

Què és Infrastructure as Code i com funciona Terraform (HCL, providers, estat i plan), explicat amb analogies d'SQL i Delta Lake per a Microsoft Fabric.

DevOpsFabricArquitectura Traduït de l’original en castellà

passos_desplegament.docx. I el _v2. I el _FINAL. I el _FINAL_FINAL2.

A dins: 27 captures de pantalla d’una versió del portal que ja no existeix, la captura 14 en anglès i la resta en castellà, i un pas que només sap fer en Jose. I en Jose és de vacances.

Segur que en tens un de semblant en alguna carpeta. El problema de fons no és el Word: és que muntar un entorn depèn d’un procediment manual que costa repetir i que ningú manté al dia.

A la NetCoreConf, l’Alfonso Ming i jo vam fer la xerrada «Y yo aquí creando workspaces a mano» («I jo aquí creant workspaces a mà»), sobre com deixar de fer això amb Terraform a Microsoft Fabric. Aquí t’explico la part teòrica, el que m’hauria agradat tenir clar abans d’escriure la primera línia. La pràctica, amb el vídeo de la demo, la tens al següent article.


Fem números

Un projecte normal: quatre entorns (dev, test, QA i pro) i tres capes medallion (bronze, silver i gold). Són dotze workspaces abans de crear cap lakehouse. Amb quatre rols per workspace, 48 assignacions de permisos.

Això és una tarda fent clic, i és molt difícil arribar al final sense que se t’escapi algun rol.


Què passa amb el ClickOps

Així ho fem gairebé tots: obres el portal, configures, fas captures «per documentar-ho després» i funciona. Els clics no són el problema. El problema arriba després.

Tres mesos més tard algú pregunta per què el workspace de QA no té el mateix rol que el de pro, i ningú ho sap. Per respondre necessitaries saber què hi havia abans, qui ho va canviar i per què, i el portal no t’ho posa fàcil. Si demà cal muntar el mateix entorn per a un altre projecte, depens de la memòria de qui ho va fer la primera vegada, i dues persones seguint el mateix Word acaben amb dues configuracions diferents. I quan arriba una auditoria preguntant qui té accés a què, toca reconstruir-ho a mà.

Tenir la configuració en codi i a Git en resol bona part: els canvis es revisen en una pull request i queda un historial. Compte, però: Git et diu què ha canviat al codi i qui ho ha aprovat; qui ho ha aplicat i quan ho sabràs si l’apply el llança un pipeline i no cada persona des del seu portàtil.


Què és Infrastructure as Code (IaC)

Infrastructure as Code és descriure la teva plataforma en fitxers de text, guardar-los a Git i que una eina els apliqui per tu. Els fitxers es poden llegir, comparar i copiar d’un projecte a un altre, i a Git tens historial, branques, pull requests i la possibilitat de tornar enrere. Si Git encara et fa respecte, aquí tens el meu traductor Git per a analistes de dades.


Imperatiu o declaratiu: això ja ho domines

Hi ha dues maneres d’automatitzar. La imperativa consisteix a dir-li a la màquina com fer-ho, pas a pas, amb un script on tu escrius tots els if:

$ws = Get-Workspace -Name "Bronze-DEV"
if ($null -eq $ws) {
  $ws = New-Workspace -Name "Bronze-DEV"
  Set-Capacity -Id $cap -Workspace $ws
} else {
  if ($ws.Capacity -ne $cap) { Set-Capacity -Id $cap -Workspace $ws }
}

Ja existeix? Té la capacity bona? Tots aquests casos els controles tu.

La declarativa consisteix a descriure com vols que quedi, i el motor calcula què ha de fer per arribar-hi:

resource "fabric_workspace" "bronze_dev" {
  display_name = "Bronze-DEV"
  capacity_id  = var.capacity_id
}

Si treballes amb dades, això ja ho coneixes: l’SQL també és declaratiu. Escrius el SELECT que vols i no li dius al motor si ha de fer un hash join o un nested loop. Terraform fa el mateix amb la plataforma.

Sempre m’ha semblat curiós que l’esquema de les nostres taules visqui en codi des de fa anys i la plataforma que les conté, no.


El canvi de mentalitat

Quan adoptes Terraform, el repo passa a ser la referència de com ha d’estar la plataforma, i el portal és el resultat d’aplicar-lo. Canviar alguna cosa a mà al portal continua sent possible, però aquest canvi queda fora del codi i Terraform intentarà desfer-lo la propera vegada (ho veurem més avall, amb el drift).


Què és Terraform

Terraform té tres peces. Una CLI, l’executable terraform, amb la qual faràs servir sobretot init, plan, apply i destroy. Un llenguatge, HCL: fitxers .tf amb blocs i parelles clau = valor, força fàcil de llegir encara que no l’hagis vist mai. I els providers, que són els plugins que saben parlar amb cada servei.

Sobre la llicència: Terraform és gratuït, però des de la versió 1.6, l’agost del 2023, es distribueix amb llicència BSL, que no és open source. Si això t’importa, OpenTofu és el fork obert i entén el mateix codi.


El provider és un connector

Power BI no sap parlar amb SAP; el connector de SAP sí. Amb Terraform passa el mateix: no sap parlar amb Fabric, i el provider de Fabric sí. El teu codi .tf descriu el que vols, Terraform calcula el plan, el provider el tradueix a crides a l’API REST de Fabric i és l’API qui fa la feina.

A Fabric en faràs servir tres:

ProviderPer a què
microsoft/fabricWorkspaces, rols, lakehouses, warehouses, notebooks, pipelines, dominis, integració amb Git i més
hashicorp/azureadEls grups de seguretat d’Entra ID
hashicorp/azurermLa capacity de Fabric i la storage account on guardes l’estat

Es combinen sense problema: al mateix fitxer crees un grup a Entra ID i l’assignes a un workspace.


Anatomia d’un recurs

resource "fabric_workspace" "bronze_dev" {
  display_name = "Bronze-DEV"
  description  = "Capa bronze, DEV"
  capacity_id  = var.capacity_id
}

resource indica que vols que això existeixi. "fabric_workspace" és el tipus de cosa, i el defineix el provider. "bronze_dev" és el nom amb què tu l’anomenes dins del codi. I el que va entre claus són els arguments: com ha de ser.

Aquí hi ha l’error més habitual quan comences: bronze_dev no és el nom del workspace. El nom que veus al portal és display_name. Per referenciar el workspace des d’un altre recurs fas servir fabric_workspace.bronze_dev.id.


Els blocs d’HCL que veuràs

BlocQuè és
resourceUna cosa que Terraform crea i gestiona
variableUn paràmetre d’entrada: l’entorn, la capacity
outputUn valor que retorna: l’ID del workspace creat
dataUna cosa que ja existeix i que només vols consultar
localsValors calculats que reutilitzes: noms, tags
moduleUn paquet reutilitzable: el teu template empaquetat

Per a un primer exemple en tens prou amb resource i variable. Els mòduls arriben quan comences a repetir el mateix patró en diversos projectes.


El teu primer .tf per a Microsoft Fabric

terraform {
  required_providers {
    fabric = {
      source  = "microsoft/fabric"
      version = "~> 1.14"
    }
  }
}

provider "fabric" {}   # autenticació per variables d'entorn

variable "capacity_id" {
  type = string
}

resource "fabric_workspace" "bronze_dev" {
  display_name = "Bronze-DEV"
  capacity_id  = var.capacity_id
}

Són quatre blocs: quins providers necessites i amb quina versió (Terraform els descarrega a l’init), com et connectes, què canvia entre entorns i què vols que existeixi.


Com funciona per dins

Si et quedes amb una sola idea d’aquest article, que sigui aquesta. Terraform sempre compara tres coses:

  1. El teu codi (*.tf): el que vols que existeixi.
  2. L’estat (terraform.tfstate): el que Terraform sap que va crear i gestiona.
  3. La realitat (Microsoft Fabric): el que hi ha de debò ara mateix.

Cada plan calcula les diferències entre totes tres i et proposa què fer perquè la realitat coincideixi amb el codi.


L’estat s’assembla molt al _delta_log

Per a qui ve de dades, aquesta és l’analogia que millor m’ha funcionat:

Delta LakeTerraform
Els parquet són les dadesEls workspaces són la realitat
_delta_log diu quins fitxers formen la versió actualterraform.tfstate diu quins recursos gestiona i amb quins IDs
Sense el log: parquets solts i cap taulaSense l’estat: workspaces solts que Terraform no sap que són seus

L’estat és el que permet a Terraform relacionar cada recurs del codi amb el seu identificador real a Fabric. Si el perds, el codi no n’hi ha prou: Terraform no sabrà que aquests workspaces són seus i intentarà crear-los de nou.

Per això convé tractar-lo amb cura des del primer dia. No el pugis a Git, perquè guarda valors en clar, de vegades secrets (*.tfstate va al .gitignore). I així que hi treballi més d’una persona, guarda’l en un backend remot amb bloqueig, per exemple una storage account d’Azure, perquè tothom comparteixi el mateix estat i dos apply no es trepitgin:

terraform {
  backend "azurerm" {
    resource_group_name  = "rg-tfstate"
    storage_account_name = "sttfstate001"
    container_name       = "tfstate"
    key                  = "fabric.tfstate"
  }
}

terraform plan és el teu pla d’execució

Llançaries una query de 40 minuts sense mirar el pla d’execució? Amb Terraform la regla és la mateixa: abans de cada apply, llegeix el plan.

Els símbols que has de saber llegir:

SímbolQuè vol dir
+Es crearà una cosa nova
~Es modifica sense destruir
-S’elimina
-/+Es destrueix i es torna a crear: el que hi hagués a dins es perd

Així es veu un de debò:

$ terraform plan
Terraform will perform the following actions:

  # fabric_workspace.bronze_dev will be created
  + resource "fabric_workspace" "bronze_dev" {
      + display_name = "Bronze-DEV"
      + capacity_id  = "f1a2b3c4-..."
      + id           = (known after apply)
    }

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

plan no canvia res, així que el pots llançar tantes vegades com vulguis. Fixa’t sempre en l’última línia: si apareix alguna cosa a «to destroy» que no esperaves, atura’t i revisa. Els valors (known after apply) són els que encara no existeixen perquè els genera Fabric en crear el recurs.


El cicle de treball

OrdreQuè fa
terraform initDescarrega els providers i configura el backend
terraform planCalcula la diferència i te l’ensenya, sense tocar res
terraform applyExecuta els canvis i actualitza l’estat
terraform destroyElimina tot el que gestiona aquella configuració

Mentre desenvolupes, el que més llançaràs és plan i apply; l’init torna a caldre quan canvies de provider o de backend. En un equip, el més habitual és que el plan surti a la pull request i que un pipeline executi l’apply quan s’aprova.

Per a la gent de dades hi ha una manera fàcil de recordar-ho: apply es comporta com un MERGE, no com un INSERT. El pots llançar deu vegades i continues tenint els mateixos workspaces.


I si algú toca el portal a mà?

Algú entra al portal i treu un rol «un momentet, per provar». La propera vegada que fas plan, Terraform consulta la realitat, la compara amb l’estat i t’ensenya aquest canvi com una cosa que tornarà al seu lloc.

Això es diu drift. A la demo el vam provocar expressament traient el grup Viewer de ventas-silver-prod, perquè és just el tipus de canvi que sense Terraform ningú no veu fins que alguna cosa falla.


El provider de Terraform per a Microsoft Fabric

El provider oficial de Microsoft és de codi obert i treu versions sovint, així que fixa la versió amb ~> perquè no et canviï per sorpresa. Els recursos que estan en preview necessiten preview = true al bloc provider. I una cosa que convé saber abans de portar-lo a un client: segons el seu propi README, no està cobert per les polítiques de suport de Microsoft Fabric; els problemes es reporten com a issues al seu repositori de GitHub.

Amb ell pots crear estructura (workspaces, rols, carpetes, dominis i, amb azurerm, la capacity), elements de dades (lakehouse, warehouse, notebook, pipeline, model semàntic, informe) i peces de plataforma (integració amb Git, deployment pipelines, environments de Spark, connexions). La llista completa és al Terraform Registry i canvia amb cada versió.

L’autenticació és on més temps es perd la primera vegada. Necessites un service principal a Entra ID, que és la identitat amb què Terraform es presenta. Al portal d’administració de Fabric, el tenant setting Service principals can use Fabric APIs ha d’estar activat per a un grup on sigui aquest service principal; si no, tot retorna 401. Per crear workspaces, a més, aquest grup ha de poder crear-ne (Create workspaces); si no, el primer workspace falla amb FeatureNotAvailable. I a Azure i Entra ID, permisos sobre la subscripció per crear la capacity i permisos per crear grups.

Els secrets del service principal no van als .tf: variables d’entorn o Key Vault.


El que sí i el que no fem amb Terraform

La pregunta que sempre arriba a les xerrades és si això substitueix els deployment pipelines. No: cobreixen coses diferents.

Nosaltres fem servir Terraform per al que sosté el projecte: workspaces i capacities, rols i grups, carpetes, dominis i la connexió de cada workspace amb Git. El contingut (notebooks, models semàntics, informes, pipelines) i la seva promoció entre entorns el deixem per a fabric-cicd, els deployment pipelines o la integració amb Git.


El que ens vam trobar preparant la demo

Algunes coses no estaven tan clares llegint la documentació:

  • L’ID de la capacity. azurerm crea la capacity i et retorna el seu ID de recurs d’Azure, però un workspace de Fabric espera el GUID de Fabric. Em va costar un plan fallit; ho vaig resoldre amb una data source de Fabric que busca la capacity pel nom. T’ho ensenyo a la part pràctica.
  • La capacity en pausa. Amb la capacity en pausa, el provider de Fabric no deixa fer ni plan, ni apply, ni destroy. Cal reprendre-la i esperar que estigui Active abans de llançar res.
  • PowerShell 5.1. Un argument com -var-file=environments/ventas.tfvars sense cometes es parteix en dos, i Terraform respon amb un «Too many command line arguments» que no ajuda gens.

I uns quants errors típics quan comences: deixar l’estat només al teu portàtil, no mirar els -/+ del plan (tornar a crear un workspace és perdre el que tenia a dins) i canviar el nom d’un recurs al codi sense fer servir el bloc moved, que per a Terraform equival a esborrar-ne un i crear-ne un altre.


Si vols començar

No intentis automatitzar tota la plataforma de cop. Instal·la Terraform (winget install HashiCorp.Terraform), crea un fitxer .tf amb un únic workspace de prova, com el de més amunt, i llança terraform plan abans d’aplicar res. Després fes l’apply, canvia alguna cosa al codi, torna a mirar el plan i fixa’t en com s’actualitza l’estat. Quan acabis, un destroy sobre aquest workspace de prova (i només sobre aquest) ho deixa tot com estava.

Amb un exemple petit s’entén el cicle molt millor que copiant vint recursos de cop.

Al següent article ho veiem en marxa: una capacity F2, nou workspaces, 36 grups i 36 assignacions de rols, 84 recursos en un sol apply, amb el vídeo de la demo.

La Pris, la meva gata, fa anys que aplica infraestructura declarativa: declara que el sofà és seu i la realitat convergeix sola.


Enllaços d’interès

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

Comentaris