Modulo 06
Finora abbiamo versionato codice, automatizzato test e orchestrato container. Terraform fa la stessa cosa con l'infrastruttura: server, reti, database e cluster diventano file di testo, versionabili come qualunque altro codice.
Terraform è uno strumento open source di Infrastructure as Code (IaC): invece di creare risorse cloud a mano dal pannello di controllo di un provider, le descrivi in file di configurazione dichiarativi. Terraform legge quei file e si occupa di creare, modificare o eliminare le risorse necessarie per portare l'infrastruttura reale allo stato descritto.
Vantaggi principali:
Scarica Terraform dal sito ufficiale: developer.hashicorp.com/terraform/install. Su macOS, con Homebrew:
brew tap hashicorp/tap brew install hashicorp/tap/terraform
Per verificare l'installazione:
terraform -version
mkdir terraform-demo cd terraform-demo
Un progetto Terraform è semplicemente una cartella con uno o più file .tf. Creiamo il file principale:
main.tf
Un provider è il plugin che permette a Terraform di parlare con un servizio esterno: AWS, Google Cloud, Azure, ma anche GitHub, Docker o Cloudflare. Ogni provider espone le risorse che si possono creare.
Dichiariamo il provider all'inizio di main.tf:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "eu-west-1"
}
required_providers indica quale plugin scaricare e in che versione, provider "aws" lo configura, ad esempio con la regione da usare.
terraform init
Questo comando scarica i provider dichiarati e prepara la cartella di lavoro. Va eseguito ogni volta che si aggiunge o cambia un provider.
init, Terraform crea una cartella .terraform e un file .terraform.lock.hcl: il primo va ignorato da Git, il secondo va versionato perché blocca le versioni esatte dei provider usati.Una resource è la singola cosa che vuoi creare: un server, un bucket, un database. Aggiungiamo a main.tf un server EC2 di esempio:
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "terraform-demo"
}
}
La sintassi generale è resource "tipo" "nome_locale" { ... }: il tipo indica cosa creare, il nome locale è solo un riferimento interno al progetto, non il nome reale della risorsa nel cloud.
terraform plan
Mostra un'anteprima di cosa Terraform sta per fare, senza applicare nulla: cosa verrà creato (+), modificato (~) o distrutto (-). È il passaggio più importante prima di ogni apply, perché permette di controllare le modifiche prima che diventino reali.
terraform apply
Terraform mostra di nuovo il piano e chiede conferma prima di procedere. Digitando yes, crea davvero le risorse nel provider configurato.
terraform apply agisce su infrastruttura reale, spesso a pagamento. Controlla sempre l'output di plan prima di confermare.Dopo ogni apply, Terraform salva lo stato attuale dell'infrastruttura in un file terraform.tfstate. Questo file è la mappa tra ciò che è scritto nei file .tf e ciò che esiste davvero nel cloud: senza di esso, Terraform non saprebbe cosa ha già creato.
terraform.tfstate non va mai versionato su Git: può contenere dati sensibili e, se più persone lo modificano in parallelo, si rischiano conflitti gravi. In un progetto di squadra si usa uno stato remoto condiviso (ad esempio un bucket S3 con blocco tramite DynamoDB), invece del file locale.Le variabili permettono di riutilizzare la stessa configurazione con valori diversi. Creiamo variables.tf:
variable "instance_type" {
description = "Tipo di istanza EC2"
type = string
default = "t2.micro"
}
E usiamola in main.tf:
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = var.instance_type
}
Per sovrascrivere un valore da riga di comando:
terraform apply -var="instance_type=t3.micro"
Oppure creando un file terraform.tfvars con i valori, che Terraform carica automaticamente:
instance_type = "t3.micro"
Gli output espongono valori utili dopo l'apply, ad esempio l'indirizzo IP di un server appena creato. Creiamo outputs.tf:
output "instance_ip" {
description = "Indirizzo IP pubblico del server"
value = aws_instance.web.public_ip
}
Dopo terraform apply, il valore viene stampato a schermo; per rivederlo in qualsiasi momento:
terraform output
terraform destroy
Elimina tutte le risorse gestite da quel progetto Terraform. Utile per ambienti di test che non devono restare accesi, evitando costi inutili.
Nei progetti più grandi, i file .tf si dividono per responsabilità invece di stare tutti in main.tf:
main.tf # risorse principali variables.tf # dichiarazione delle variabili outputs.tf # valori esposti dopo l'apply terraform.tfvars # valori reali delle variabili (non versionato se sensibile) .gitignore # esclude .terraform/ e i file di stato
.terraform/ *.tfstate *.tfstate.backup .terraform.lock.hcl
Un modulo è un gruppo di file Terraform riutilizzabile, come una funzione per l'infrastruttura. Si richiama così:
module "rete" {
source = "./modules/network"
cidr_block = "10.0.0.0/16"
}
Questo permette di scrivere una configurazione di rete una sola volta e riutilizzarla in più ambienti (sviluppo, staging, produzione) semplicemente passando parametri diversi.
Proprio come i test in GitHub Actions, anche i comandi Terraform possono girare automaticamente ad ogni push. Un workflow tipico:
name: Terraform CI
on:
pull_request:
branches:
- main
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
- name: Terraform Init
run: terraform init
- name: Terraform Plan
run: terraform plan
In questo modo, ogni pull request mostra automaticamente cosa cambierebbe nell'infrastruttura, prima ancora che qualcuno esegua apply a mano.
Installare Terraform, dichiarare provider e risorse, distinguere plan da apply, capire il ruolo del file di stato, usare variabili e output, organizzare un progetto in più file e moduli, e collegare Terraform a una pipeline CI. Con questo modulo il percorso è completo: codice versionato con Git, pubblicato su GitHub, testato con GitHub Actions, containerizzato con Docker, orchestrato con Kubernetes e l'infrastruttura sotto di tutto descritta e riproducibile con Terraform.