La differenza tra un team che riesce a tirare su un ambiente di staging fresco in trenta minuti e un team che ci mette tre giorni è quasi sempre come è definita la loro infrastruttura. Il team da trenta minuti la tiene in codice: un repository di file dichiarativi che descrive ogni risorsa cloud, network, database, ruolo IAM, record DNS e secret. Lanciano un comando, il cloud si riconcilia con la descrizione, e un ambiente funzionante esiste. Il team da tre giorni ce l’ha nella memoria di qualcuno e in una pagina wiki mezza finita aggiornata l’ultima volta quando la console AWS aveva un’altra faccia.
Infrastructure as code, IaC, è la disciplina di definire l’infrastruttura nello stesso modo in cui definisci il codice applicativo: in file versionati, revisionati, testati. Questa lezione attraversa i tre tool che dominano lo spazio (Terraform, Pulumi, AWS CDK), il problema dello state file che condividono tutti, il workflow GitOps che ci si incarta sopra, e perché tutto questo conta di più per il lavoro sui dati che per la maggior parte degli altri tipi di ingegneria.
L’alternativa pre-IaC
Per fare il caso a favore dell’IaC, guarda cosa rimpiazza.
Pre-IaC, l’infrastruttura succede in una console cloud. Qualcuno clicca “create database” e digita i parametri. Sei mesi dopo, nessuno si ricorda quali fossero i parametri. Il database deve essere riprodotto in staging; l’ingegnere che fa la riproduzione tira a indovinare sui parametri e ne sbaglia qualcuno. Un anno dentro, il database di produzione e quello di staging sono andati abbastanza alla deriva da far sì che i bug in staging non si riproducano in produzione, e i bug in produzione non si riproducano in staging. Ogni ambiente è un fiocco di neve. Ogni cambio è un rituale manuale.
L’effetto cumulativo è peggio del dolore singolo per incidente. Ogni account cloud accumula debito: risorse orfane di cui nessuno è proprietario, security group con regole il cui scopo è stato dimenticato, policy IAM troppo permissive perché nessuno sa quale sia il permesso minimo di cui il servizio ha davvero bisogno. L’audit diventa un esercizio forense. Il disaster recovery diventa una speranza.
L’IaC rende l’infrastruttura revisionabile, riproducibile e rollback-abile. Il prezzo è che devi imparare il tooling e accettare i vincoli della configurazione dichiarativa. Per qualunque cosa al di là di un setup a una sola VM, il prezzo si ripaga in pochi mesi.
Terraform: il default
Terraform, rilasciato da HashiCorp nel 2014, è il tool a cui la maggior parte dei team allunga la mano. Usa un DSL dichiarativo chiamato HCL (HashiCorp Configuration Language) e un modello a provider che gli permette di parlare con quasi qualunque cloud o servizio: AWS, GCP, Azure, Kubernetes, Cloudflare, Datadog, GitHub, e una lunga coda di altri. Scrivi file HCL che descrivono lo stato desiderato, lanci terraform plan per vedere cosa cambierebbe, lanci terraform apply per far succedere i cambiamenti.
Un piccolo esempio per un bucket S3:
resource "aws_s3_bucket" "data_lake" {
bucket = "company-data-lake-prod"
}
resource "aws_s3_bucket_versioning" "data_lake" {
bucket = aws_s3_bucket.data_lake.id
versioning_configuration {
status = "Enabled"
}
}
I punti di forza sono reali. L’ecosistema di provider è enorme. La community ha decenni di pattern e moduli condivisi. Il workflow plan-poi-apply dà ai revisori un diff concreto di cosa cambierà nella realtà cloud. Lo stesso codice Terraform funziona per dev, staging e prod con variabili diverse, ed è quello che rende possibile l’ambiente fresco da trenta minuti.
La situazione di licensing vale la pena conoscerla. Nel 2023 HashiCorp ha ri-licenziato Terraform da MPL alla Business Source License, restringendo qualche uso commerciale. La community ha risposto forkando il codice open source in OpenTofu, ora un progetto della Linux Foundation. OpenTofu è un drop-in replacement e il percorso open source in avanti; i nuovi team che scelgono oggi spesso vanno di default su quello. I file HCL funzionano in entrambi.
Per la maggior parte dei team la maggior parte del tempo, Terraform o OpenTofu è il punto di partenza giusto. La copertura dei provider e la community ne fanno il percorso di minor resistenza.
Pulumi: infrastruttura in linguaggi veri
Pulumi, rilasciato nel 2017, ha fatto una scommessa diversa. Invece di un DSL custom, ti lascia definire l’infrastruttura in linguaggi di programmazione veri: TypeScript, Python, Go, C#, Java. Lo stesso modello dichiarativo sotto, lo stesso workflow plan-poi-apply, ma l’input è codice in un linguaggio che il tuo team già conosce.
Lo stesso bucket S3 in TypeScript:
import * as aws from "@pulumi/aws";
const dataLake = new aws.s3.Bucket("data-lake", {
bucket: "company-data-lake-prod",
versioning: { enabled: true },
});
I vantaggi saltano fuori quando l’infrastruttura ha una qualunque complessità. Loop, condizionali, astrazioni, type checking, autocompletamento dell’IDE, framework di test veri: tutto gratis, perché è solo codice. I team che hanno superato i blocchi for_each e dynamic di Terraform spesso trovano Pulumi più chiaro per la stessa logica.
Il costo è che l’astrazione perde più colpi. Con HCL, il file è la verità: leggi il file, sai che infrastruttura esiste. Con Pulumi, il codice è un programma che produce la verità, e un programma sufficientemente furbo può essere difficile da leggere. La disciplina che tiene Pulumi pulito è la disciplina di qualunque codebase: semplice meglio di furbo, le astrazioni si guadagnano da vivere, il nuovo arrivato dovrebbe riuscire a leggere cosa sta succedendo.
Pulumi è la scelta giusta per i team i cui ingegneri sono più forti in codice che nei DSL e la cui logica infrastrutturale è cresciuta abbastanza da rendere HCL un freno. Per un piccolo team con bisogni semplici, la potenza extra è un overkill.
AWS CDK: solo AWS con ergonomia code-native
L’AWS Cloud Development Kit, rilasciato nel 2019, è la risposta di Amazon allo stesso pitch dei “linguaggi veri” di Pulumi, con uno scope più stretto. Il codice CDK in TypeScript, Python, Java, C# o Go viene compilato in template CloudFormation che AWS deploya.
Lo stesso bucket in CDK:
import * as s3 from "aws-cdk-lib/aws-s3";
new s3.Bucket(this, "DataLake", {
bucketName: "company-data-lake-prod",
versioned: true,
});
CDK è solo AWS. Il punto è proprio quello. Se la tua infrastruttura è AWS dall’alto in basso e vuoi le astrazioni di livello più alto per le risorse AWS, CDK ti dà construct che impacchettano pattern comuni (un servizio ECS con un load balancer e una dashboard CloudWatch, tutto configurato con criterio) in singoli oggetti. L’integrazione con feature specifiche AWS è più profonda di quello che offre il provider AWS di Terraform, perché CDK è costruito da AWS.
Il prezzo è il lock-in. CDK non è portabile. Se l’azienda si sposta su multi-cloud, il codice CDK non viene dietro. Per un team che si è impegnato su AWS a lungo termine e vuole l’ergonomia per gli sviluppatori, quel lock-in è una feature, non un bug. Per un team che vuole tenere aperte le opzioni, Terraform o Pulumi è la scommessa più sicura.
Il problema dello state file
Ogni tool IaC deve tracciare “cosa esiste attualmente nel cloud” così sa cosa cambiare al prossimo apply. Terraform scrive uno state file: un documento JSON che mappa le risorse nel tuo codice alle risorse che esistono nella realtà, con i loro ID, i loro attributi, le loro dipendenze. Pulumi ha lo stesso concetto sotto un nome diverso. CDK delega a CloudFormation, che tiene il proprio stato.
Lo state file è da dove viene la maggior parte del dolore operativo dell’IaC.
È un pezzo di stato critico. Perdilo e perdi il legame tra codice e realtà. Il prossimo apply proverà a creare tutto da capo, fallirà perché le risorse esistono già, e ti lascerà in uno stato rotto. Tratta lo state file come un backup di database: stoccato remoto (S3 con versioning è il setup canonico per Terraform), criptato e non nel repo git.
Può essere lockato. Due ingegneri che lanciano terraform apply contro lo stesso state allo stesso tempo producono corruzione. Terraform supporta il locking tramite DynamoDB; OpenTofu tramite DynamoDB o HTTP. Il lock è essenziale per qualunque setup di team; nel momento in cui due persone stanno lanciando apply, il lock è quello che ti tiene sano di mente.
Può andare alla deriva dalla realtà. Qualcuno clicca nella console e cambia una regola di security group. La vista del mondo di Terraform è ora stantia. Il prossimo plan riporta cambi inattesi; l’apply o ribalta il cambio manuale o, peggio, ci combatte. La disciplina che previene la deriva è “tutti i cambi passano dall’IaC, nessuna eccezione”. La realtà pragmatica è che la deriva succede, e tool come terraform refresh e il refresh di Pulumi ti permettono di riconciliare.
Lo state file è anche il posto da cui possono colare i secret. Alcuni attributi di risorse contengono valori sensibili: password di database, token generati, chiavi TLS. Questi finiscono nello state file. Cripta lo state at rest. Restringi l’accesso. Tratta il bucket dello state nel modo in cui tratti un secrets manager.
GitOps: il workflow che lega tutto insieme
GitOps è il pattern operativo che incarta l’IaC in qualcosa che un team può usare senza pestarsi i piedi a vicenda. L’idea è semplice: il repository git è la singola fonte di verità per l’infrastruttura. Ogni cambio è una pull request. Un controller riconcilia di continuo lo stato cloud con lo stato git. Se la realtà va alla deriva da git, il controller o avvisa o corregge.
Per Terraform, Atlantis è il tool canonico. Una pull request che tocca file Terraform fa scattare Atlantis che lancia terraform plan e posta l’output come commento sulla PR. I revisori vedono il diff esatto che verrà applicato. Una volta che la PR è approvata, Atlantis lancia terraform apply dalla PR stessa. La traccia è nello storico git; il lock è tenuto durante l’apply; nessuno lancia Terraform dal proprio laptop.
Per Kubernetes, Flux e ArgoCD giocano lo stesso ruolo. Guardano un repo git di manifest Kubernetes e riconciliano di continuo il cluster perché combaci. Pushi un cambio su git, il cluster lo prende. La deriva nel cluster viene corretta indietro verso git.
Il flusso ha questa forma:
flowchart TB
DEV[Developer writes IaC change] --> PR[Open pull request]
PR --> PLAN[CI runs terraform plan]
PLAN --> REVIEW[Reviewer reads plan diff]
REVIEW --> MERGE[Merge to main]
MERGE --> APPLY[CI runs terraform apply]
APPLY --> CLOUD[Cloud reaches desired state]
CLOUD --> DRIFT[Periodic drift detection]
DRIFT --> ALERT[Alert if drift found]
Lo shift culturale che GitOps impone è reale. Niente più “l’ho appena cambiato nella console”. Ogni cambio è un commit. Ogni commit è revisionato. Ogni stato del mondo è raggiungibile da uno storico git.
Quando l’IaC è overkill
La lista onesta dei momenti in cui saltare l’IaC è corta.
Un progetto solitario con una sola VM e un solo database. Un prototipo usa-e-getta che non sopravvivrà alla settimana. Un esercizio di apprendimento dove l’obiettivo è capire le primitive del cloud, non spedirle.
Quasi tutto il resto ne beneficia. La soglia è bassa: due ingegneri e tre risorse bastano per rendere la gestione manuale una scelta peggiore dell’IaC. L’argomento “siamo troppo piccoli per quello” è l’argomento che produce infrastruttura a fiocco di neve sei mesi dopo.
L’angolo del data engineering
Il lavoro sui dati ha il suo particolare beneficio dall’IaC. L’infrastruttura per una piattaforma dati è un sacco di risorse: il warehouse (con i suoi dataset, schemi, grant IAM), l’orchestratore (Airflow o Dagster o Prefect, con i loro secret, connessioni, deployment), il compute (config dei cluster Spark, node pool Kubernetes), lo storage (bucket S3 con policy di lifecycle e regole di replica), il monitoring (dashboard Datadog, alert, SLO).
Tirare su un ambiente di staging fresco che rispecchia produzione è l’use case dove l’investimento ripaga di più. Senza IaC, l’ambiente di staging non corrisponde mai del tutto a produzione, e il gap è dove si nascondono i bug. Con IaC, lo staging è un clone della produzione con variabili diverse, e il gap si chiude quasi a zero.
L’altro use case è il disaster recovery. Se la region di produzione va giù, IaC più un backup recente è il percorso per tornare. Click-ops più una pagina wiki no.
Cosa significa in pratica
Per un team che parte oggi, il percorso realistico è:
- Scegli Terraform o OpenTofu a meno che non ci sia un motivo forte per Pulumi o CDK.
- Stocca lo state remoto dal giorno uno (S3 più lock DynamoDB per AWS, GCS per GCP).
- Incarta il workflow con Atlantis o un runner simile guidato da PR prima che due persone stiano lanciando Terraform dal proprio laptop.
- Imposta la drift detection come job periodico; investiga ogni evento di drift.
- Tratta il codice IaC con la stessa disciplina di review del codice applicativo. Il blast radius di un apply cattivo è grosso.
La lezione 54 copre i container, l’unità con cui la maggior parte dei job dati moderni viene spedita. La lezione 55 copre Kubernetes, il runtime su cui gira la maggior parte delle piattaforme dati container-based. Entrambi i livelli stanno sopra l’IaC: il cluster, i registry, i ruoli IAM per i job, tutto definito in Terraform o nei suoi pari.
Riferimenti
- Documentazione Terraform (
https://developer.hashicorp.com/terraform/docs, consultato 2026-05-01). - Documentazione OpenTofu (
https://opentofu.org/docs/, consultato 2026-05-01). - Documentazione Pulumi (
https://www.pulumi.com/docs/, consultato 2026-05-01). - Documentazione AWS CDK (
https://docs.aws.amazon.com/cdk/v2/guide/home.html, consultato 2026-05-01). - Documentazione Atlantis (
https://www.runatlantis.io/docs/, consultato 2026-05-01). - “GitOps principles” sul sito OpenGitOps (
https://opengitops.dev/, consultato 2026-05-01).