Ansible o Terraform: quale ti serve davvero?
Terraform crea il VPS, Ansible lo configura: scopri la differenza, i comandi di passaggio, perché i provisioner creano problemi e quando basta Ansible.
Ansible e Terraform in una frase
Ansible e Terraform non sono due strumenti che svolgono lo stesso compito, quindi la scelta non è tra due alternative equivalenti. Terraform dichiara quale infrastruttura deve esistere: server, dischi, reti e record DNS. Ansible dichiara quale deve essere lo stato interno di una macchina già esistente: pacchetti, utenti, file di configurazione e servizi in esecuzione. Terraform crea il VPS. Ansible trasforma quel VPS in un server web.
Entrambi adottano un approccio dichiarativo e sono definiti infrastruttura come codice (IaC). La differenza sostanziale riguarda ciò che memorizzano. Terraform scrive un file di stato che associa ogni risorsa dichiarata nel codice all'oggetto reale creato tramite un'API. In questo modo può stabilire che la rimozione di cinque righe implica la distruzione di un server. Ansible non conserva informazioni tra un'esecuzione e l'altra. Si connette tramite SSH, esamina la macchina e modifica soltanto ciò che non corrisponde già al playbook.
Questa sola differenza spiega il resto della guida, compreso il motivo per cui affidare entrambi i compiti a un unico strumento causa problemi.
Cosa fa realmente Terraform
Terraform comunica con un'API tramite un plugin provider. La pagina del registry del provider definisce i tipi di risorsa che puoi dichiarare. Di conseguenza, un server su un host e un server su un altro host sono risorse diverse, con nomi e argomenti differenti.
resource "cloud_server" "web" {
name = "web1"
image = "ubuntu-24.04"
type = "small"
}
output "web_ip" {
value = cloud_server.web.ipv4_address
}Sostituisci cloud_server con il tipo di risorsa documentato dal provider. Il blocco output è la parte importante per questa guida, perché determina come l'indirizzo esce da Terraform.
terraform init
terraform fmt -check
terraform validate
terraform plan -out=tfplan
terraform apply tfplanterraform init scarica il provider e scrive un file di lock. terraform plan mostra la differenza tra il codice e il file di stato. L'output termina con una riga simile a Plan: 1 to add, 0 to change, 0 to destroy.. Leggi sempre quella riga. Alcuni argomenti non possono essere modificati in-place. Il plan lo segnala con # forces replacement accanto all'attributo, seguito da 1 to add, 0 to change, 1 to destroy. L'applicazione di quel plan elimina il server e ne crea uno nuovo vuoto. In questo modo si perdono dati che si ritenevano al sicuro.
Salvare il plan in un file e applicare il file, invece di eseguire un semplice terraform apply, garantisce che venga eseguito esattamente ciò che hai verificato. Tra i due comandi, un'altra persona potrebbe aver modificato l'infrastruttura.
terraform.tfstate è la memoria di Terraform. Se lo perdi, Terraform non sa più che quei server appartengono alla configurazione. Il comando apply successivo tenta quindi di creare duplicati. Usa un backend remoto non appena più di una persona esegue i comandi. Due persone che eseguono apply contemporaneamente producono questo risultato:
Error: Error acquiring the state lockOpenTofu è un fork di Terraform con gli stessi comandi e lo stesso formato dei file. A luglio 2026, tutto ciò che è descritto in questa guida funziona se digiti tofu invece di terraform.
Cosa fa realmente Ansible
Ansible non richiede agent né API. Apre una connessione SSH, copia un piccolo modulo Python sul sistema di destinazione, lo esegue e lo elimina. Tutto ciò che puoi raggiungere tramite SSH e una password sudo può essere configurato con Ansible.
- name: Base web server
hosts: web
become: true
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
- name: Ensure nginx is running at boot
ansible.builtin.service:
name: nginx
state: started
enabled: trueansible -i inventory.ini web -m ansible.builtin.ping
ansible-playbook -i inventory.ini site.yml --check --diff
ansible-playbook -i inventory.ini site.ymlIl modulo ping verifica SSH, Python e sudo prima che inizi il debug di un playbook. Un risultato corretto è web1 | SUCCESS => {"ping": "pong"}. L'esecuzione --check --diff è l'equivalente più vicino a un piano in Ansible: indica quali modifiche verrebbero applicate senza applicarle. Tuttavia, le attività che dipendono da attività precedenti possono restituire risultati errati in modalità check, perché la modifica precedente non è stata realmente applicata.
Ogni esecuzione termina con un riepilogo come ok=6 changed=2 unreachable=0 failed=0. Esegui lo stesso playbook due volte. La seconda esecuzione dovrebbe restituire changed=0. Un'attività che segnala changed a ogni esecuzione non è idempotente. Di solito è un'attività command o shell che avrebbe dovuto usare un modulo reale. Se questo argomento è nuovo per te, inizia da un primo playbook Ansible su un singolo VPS e prosegui da lì.
Dove i due strumenti si sovrappongono e dove entrano in conflitto
Terraform può eseguire comandi su un nuovo server con il provisioner remote-exec. La documentazione ufficiale di HashiCorp definisce i provisioner una soluzione di ultima istanza. Ci sono validi motivi.
Un provisioner viene eseguito solo quando la risorsa viene creata. Se modifichi lo script, sul server esistente non succede nulla, perché dal punto di vista di Terraform la risorsa corrisponde già al codice. Le operazioni del provisioner non compaiono in terraform plan, quindi nella revisione non ne rimane traccia. Se lo script fallisce, Terraform contrassegna la risorsa come non attendibile e il successivo apply elimina e ricrea un server che probabilmente funzionava correttamente.
Anche il momento del fallimento è problematico. Il provider considera creato il server non appena l'API lo segnala, mentre il sistema operativo è ancora in fase di avvio e sshd non è ancora in ascolto.
Error: remote-exec provisioner error
timeout - last error: dial tcp 203.0.113.10:22: connect: connection refusedAnsible presenta la tentazione opposta. I moduli cloud possono creare server e, per un numero ridotto di macchine, questo approccio funziona. In cambio, però, perdi il grafo delle dipendenze e il file di stato. Ansible crea una risorsa senza problemi, ma se elimini l'attività dal playbook la risorsa continua a essere in esecuzione e a generare costi, perché nulla ha registrato che fosse stata creata da Ansible.
La regola che ne deriva è questa: lascia a Terraform la gestione degli oggetti che un'API crea ed elimina, e lascia ad Ansible la gestione di tutto ciò che si trova all'interno di un sistema operativo già avviato.
Il passaggio di consegne, in pratica
Il passaggio di consegne è un confine, non un'integrazione. Terraform completa l'esecuzione, pubblica un indirizzo e si arresta. Ansible parte da quell'indirizzo.
terraform apply -auto-approve
terraform output -raw web_ip
printf '[web]\n%s ansible_user=root\n' "$(terraform output -raw web_ip)" > inventory.ini
ansible -i inventory.ini web -m ansible.builtin.ping
ansible-playbook -i inventory.ini site.ymlterraform output -raw stampa un valore senza virgolette e senza un wrapper JSON. È il formato corretto per una sostituzione di shell. Per più server, usa terraform output -json e crea l'inventory a partire da quell'output, perché -raw gestisce soltanto una singola stringa, un numero o un valore booleano.
Vale la pena mantenere il passaggio ping tra i due strumenti. Consente di distinguere il caso in cui «Terraform mi ha fornito l'indirizzo errato» da quello in cui «il playbook contiene un bug». Quando il playbook è il primo componente a contattare il nuovo server, questi due problemi risultano identici.
Lettura dello state di Terraform come inventario Ansible
Se preferisci non scrivere affatto un file di inventario, la collection cloud.terraform legge direttamente lo state.
ansible-galaxy collection install cloud.terraformScrivi terraform.yml accanto al playbook:
plugin: cloud.terraform.terraform_provider
project_path: /home/deploy/infraansible-inventory -i terraform.yml --graph
ansible-playbook -i terraform.yml site.ymlPrima di affidarti a questa soluzione, devi conoscere due aspetti. Il plugin esegue terraform show su project_path, quindi la directory deve essere già inizializzata; in caso contrario, il plugin non funziona. Inoltre, non crea automaticamente gli host a partire dalle risorse dei server: legge le risorse ansible_host e ansible_group, che devi dichiarare nel codice Terraform usando il provider Ansible. In ansible-inventory --graph non compare nulla finché non le aggiungi.
Un file di inventario generato in formato semplice è più facile da eseguire il debug e funziona con qualsiasi provider. Il plugin diventa utile quando l'inventario supera alcune macchine e la modifica manuale inizia a causare errori di digitazione. È lo stesso punto in cui gestire diversi server Linux da una sola macchina di controllo diventa un flusso operativo reale, non soltanto un'abitudine.
Serve davvero Terraform?
La maggior parte delle persone che leggono questa guida non ne ha bisogno, almeno non ancora. Terraform giustifica il proprio costo quando creare e distruggere l’infrastruttura è un’attività ricorrente. Se avete ordinato un singolo VPS tramite un pannello di controllo e prevedete di mantenerlo per due anni, Terraform descrive un’operazione eseguita una sola volta e aggiunge un file di stato che non dovete perdere.
Scegliete Terraform quando ricreate spesso gli ambienti, quando l’ambiente di staging deve corrispondere esattamente a quello di produzione, quando più persone modificano l’infrastruttura e volete un piano verificabile prima che venga eliminato qualsiasi elemento, oppure quando ciò che gestite non si limita ai server, ma comprende anche record DNS, load balancer e regole firewall disponibili tramite l’API di un provider.
Usate solo Ansible quando i server hanno una lunga durata e sono pochi, e quando la domanda quotidiana è «questo server è configurato correttamente?» invece di «questo server esiste?». Un singolo playbook che mette in sicurezza un nuovo server copre lo stesso ambito dei primi dieci minuti su un nuovo VPS, con il vantaggio di poter essere eseguito nello stesso modo sul server successivo.
L’ordine di apprendimento deriva da questo. Ansible ripaga già sul primo server che gestite. Terraform ripaga dal terzo ambiente che ricreate.
Problemi nel passaggio di consegne
Il server non è pronto. Terraform termina correttamente, ma Ansible fallisce immediatamente.
fatal: [web1]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 203.0.113.10 port 22: Connection refused", "unreachable": true}L'API ha restituito un indirizzo prima che sshd fosse in ascolto. Attendi che la porta sia disponibile invece di aggiungere un'attesa fissa. Ansible include ansible.builtin.wait_for_connection proprio per questo scopo: eseguilo come prima attività del play.
La chiave dell'host è cambiata. Hai eliminato e ricreato il server e il nuovo server risponde allo stesso indirizzo con una chiave diversa.
Host key verification failed.Rimuovi la voce obsoleta con ssh-keygen -R 203.0.113.10. Questo accade continuamente quando Terraform ricrea l'infrastruttura. Per questo motivo è opportuno limitare le ricreazioni sui computer che contengono dati.
Sudo fallisce. fatal: [web1]: FAILED! => {"msg": "Missing sudo password"} indica che become: true richiede una password su quell'host. Configura sudo senza password per l'utente di deployment oppure passa --ask-become-pass.
Terraform vuole eliminare una risorsa che non hai modificato. Il plan mostra modifiche che non hai mai scritto. Questo significa che l'infrastruttura reale non è più allineata al codice, di solito perché qualcuno ha modificato un'impostazione nel pannello web del provider. Esegui terraform plan -refresh-only per visualizzare solo questa differenza, quindi decidi se è errato il codice o la risorsa attiva. Non applicare mai un plan distruttivo che non sai spiegare riga per riga.
Ansible segnala modifiche a ogni esecuzione. Un'attività shell senza una condizione creates o when viene eseguita incondizionatamente. Non è un problema solo estetico, perché non puoi più usare changed=0 come indicatore del fatto che un server si trova nello stato richiesto.
FAQ
Terraform può sostituire Ansible?
Non per la configurazione interna di un server. Terraform può eseguire script tramite il provisioner remote-exec, ma questi vengono eseguiti solo durante la creazione della risorsa, non compaiono mai in terraform plan e, in caso di errore, contrassegnano la risorsa come compromessa. Al successivo apply viene quindi pianificata la sua eliminazione e ricreazione. Terraform non dispone di un equivalente di un modulo che verifica se nginx è già installato e non esegue alcuna operazione in caso affermativo. Usa Terraform per creare la macchina, quindi trasferisci la gestione ad Ansible.
Ansible può sostituire Terraform?
Per un numero ridotto di server di lunga durata, sì. Ansible dispone di moduli cloud per creare server e, se ordini 2 istanze VPS e le mantieni, questo può essere sufficiente. Tuttavia perdi il file di stato e il grafo delle dipendenze: se rimuovi un task dal playbook, la risorsa continua a essere eseguita e a generare costi, perché Ansible non registra di averla creata. Terraform avrebbe pianificato la sua eliminazione.
Quale dei due dovrei imparare per primo?
Ansible, se oggi gestisci già dei server. Offre un ritorno immediato sul primo server, richiede soltanto SSH e le competenze acquisite si applicano anche a un server ordinato manualmente. Terraform diventa utile in seguito, quando ricrei ripetutamente gli ambienti o gestisci risorse del provider oltre ai server, come record DNS e regole del firewall.
Come trasferisco l'indirizzo IP del nuovo server da Terraform ad Ansible?
Dichiara un output nel codice Terraform, quindi leggilo dopo apply. terraform output -raw web_ip stampa il valore senza testo aggiuntivo per usarlo in una sostituzione della shell, mentre terraform output -json restituisce tutti gli output contemporaneamente quando sono presenti più host. Scrivi il valore in un file di inventory oppure installa la collection cloud.terraform e indica a ansible-inventory -i terraform.yml --graph la directory del progetto.
Perché il mio playbook non riesce subito dopo il completamento di Terraform?
Il provider segnala il server come creato non appena la sua API lo indica, mentre il sistema operativo è ancora in fase di avvio. Per questo SSH viene rifiutato nei primi secondi. L'errore è UNREACHABLE! con Connection refused. Imposta ansible.builtin.wait_for_connection come primo task del play invece di stimare una durata per sleep, perché il tempo di avvio varia in base all'immagine e al piano.