Usare cloud-init per personalizzare una macchina virtuale Linux in Hyper-V al primo avvio
Quando create una macchina virtuale Linux su Hyper-V, una parte del lavoro consiste sempre nella configurazione iniziale del sistema operativo. Hostname, utenti, rete, chiavi SSH e pacchetti richiedono tempo e rendono ogni distribuzione ripetitiva, soprattutto nei laboratori o negli ambienti di test.
Con cloud-init potete automatizzare completamente questa fase. Anche se nasce per i cloud pubblici, cloud-init funziona perfettamente anche su Hyper-V e permette di personalizzare una VM Linux già al primo avvio.
In questa guida vi mostrerò come utilizzare cloud-init per preparare e configurare automaticamente una macchina virtuale su Hyper-V, creando una base riutilizzabile per deployment più rapidi, coerenti e facili da gestire.
Ho utilizzato lo script disponibile nel repository Quick provisioning of Linux VM using Hyper-V on Windows per automatizzare la creazione della macchina virtuale su Hyper-V e integrare il supporto a cloud-init. Lo script semplifica l’intero processo di provisioning, riducendo il tempo necessario per preparare VM Linux già configurate e pronte all’uso.

Figura 1: Repository GitHub hyperv-vm-provisioning con gli script PowerShell utilizzati per automatizzare il provisioning delle VM Linux tramite cloud-init su Hyper-V
Download del repository hyperv-vm-provisioning
Come prima operazione ho scaricato il repository hyperv-vm-provisioning direttamente sull’host Hyper-V utilizzando una sessione di Windows PowerShell eseguita con privilegi amministrativi. Il comando permette di scaricare automaticamente l’archivio ZIP del progetto da GitHub, estrarne il contenuto e rimuovere il file compresso al termine dell’operazione.
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; $r=’hyperv-vm-provisioning’; iwr -Uri ‘https://github.com/schtritoff/hyperv-vm-provisioning/archive/master.zip’ -UseBasicParsing -OutFile “$r.zip” ; Expand-Archive “$r.zip” -Force ; Remove-Item “$r.zip” -Force

Figura 2: Download automatico della repository hyperv-vm-provisioning tramite Windows PowerShell sull’host Hyper-V
Dopo il download e l’estrazione dell’archivio, viene creata la cartella hyperv-vm-provisioning-master contenente tutti gli script PowerShell. All’interno della directory sono presenti diversi script dedicati alla creazione della VM, alla gestione dei dischi virtuali e alla generazione dei file utilizzati da cloud-init durante la fase di inizializzazione del sistema operativo.

Figura 3: Contenuto della cartella hyperv-vm-provisioning-master dopo l’estrazione del repository GitHub
Analisi dello script New-HyperVCloudImageVM.ps1
Lo script principale utilizzato per il provisioning della macchina virtuale è New-HyperVCloudImageVM.ps1. Al suo interno sono presenti tutti i parametri necessari per automatizzare la creazione della VM Linux su Hyper-V, inclusa la configurazione di cloud-init.
Lo script permette di definire memoria, numero di processori virtuali, configurazione di rete, percorso dei dischi virtuali, versione dell’immagine Linux da utilizzare e impostazioni iniziali del sistema operativo. Sono inoltre presenti i parametri dedicati alla configurazione automatica dell’utente amministrativo, delle password e delle chiavi SSH che verranno applicate durante il primo avvio della VM.
Nella schermata seguente potete vedere il contenuto del file New-HyperVCloudImageVM.ps1 aperto in Visual Studio Code con tutti i parametri disponibili per personalizzare il deployment della macchina virtuale.

Figura 4: Contenuto dello script PowerShell New-HyperVCloudImageVM.ps1 utilizzato per automatizzare la creazione delle VM Linux con cloud-init su Hyper-V
Creazione del file cloud-init
Per personalizzare automaticamente la macchina virtuale ho creato il file cloud-init.yaml, che contiene tutte le configurazioni applicate durante il primo avvio della VM tramite cloud-init.
Nel file ho definito l’installazione automatica di alcuni pacchetti Linux, la creazione degli utenti locali, la configurazione dei privilegi sudo e la generazione di file personalizzati all’interno del sistema operativo. Ho inoltre configurato il servizio Nginx e alcune operazioni eseguite automaticamente tramite la sezione runcmd.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
#cloud-config package_update: true package_upgrade: true packages: - nginx - curl - vim - htop users: - name: admin groups: sudo shell: /bin/bash sudo: "ALL=(ALL) NOPASSWD:ALL" lock_passwd: false plain_text_passwd: "Passw0rd" - name: webadmin groups: sudo shell: /bin/bash sudo: "ALL=(ALL) NOPASSWD:ALL" lock_passwd: false plain_text_passwd: "WebAdmin2024!" write_files: - path: /var/www/html/index.html owner: www-data:www-data permissions: "0644" content: | <!DOCTYPE html> <html lang="it"> <head> <meta charset="UTF-8"> <title>Debian 12 - Hyper-V VM</title> <style> body { font-family: sans-serif; background: #1e1e2e; color: #cdd6f4; text-align: center; padding-top: 80px; } h1 { color: #89b4fa; } p { color: #a6e3a1; } code { background: #313244; padding: 4px 8px; border-radius: 4px; } </style> </head> <body> <h1>Nginx attivo su Debian 12</h1> <p>VM configurata automaticamente tramite <strong>cloud-init</strong>.</p> <p>Hostname: <code>debian12-web</code></p> </body> </html> - path: /etc/nginx/sites-available/default owner: root:root permissions: "0644" content: | server { listen 80 default_server; listen [::]:80 default_server; root /var/www/html; index index.html index.htm; server_name _; location / { try_files `$uri `$uri/ =404; } location /nginx_status { stub_status on; allow 127.0.0.1; deny all; } } runcmd: - systemctl enable nginx - systemctl restart nginx - mkdir -p /home/webadmin/.ssh - chown -R webadmin:webadmin /home/webadmin/.ssh - chmod 700 /home/webadmin/.ssh |

Figura 5: Contenuto del file cloud-init.yaml utilizzato per personalizzare automaticamente la macchina virtuale Linux durante il primo avvio
Creazione della macchina virtuale
Dopo aver preparato il file cloud-init.yaml, ho creato la macchina virtuale eseguendo lo script PowerShell con i parametri necessari per il deployment automatico della VM su Hyper-V.
Nel comando ho specificato il nome della VM, la quantità di memoria, la dimensione del disco virtuale, la generazione della macchina virtuale e il percorso del file cloud-init personalizzato tramite il parametro CustomUserDataYamlFile. Durante il primo avvio, cloud-init ha applicato automaticamente tutte le configurazioni definite nel file YAML.
|
1 2 3 4 5 6 7 8 9 10 11 |
.\New-HyperVCloudImageVM.ps1 ` -VMProcessorCount 8 ` -VMMemoryStartupBytes 2GB ` -VHDSizeBytes 60GB ` -VMName "debian12-web" ` -ImageVersion "12" ` -VMGeneration 2 ` -KeyboardLayout it ` -ShowSerialConsoleWindow ` -CustomUserDataYamlFile "C:\cloud-init.yaml" |

Figura 6: Creazione automatica della macchina virtuale Linux su Hyper-V ed esecuzione delle configurazioni cloud-init al primo avvio
Verifica della configurazione della VM
Dopo alcuni minuti la macchina virtuale viene completata e tutte le configurazioni definite nel file cloud-init.yaml vengono applicate automaticamente da cloud-init.
A questo punto potete accedere alla VM utilizzando le credenziali predefinite presenti nello script oppure quelle personalizzate definite nel file cloud-init. Dopo il login è possibile verificare che utenti, pacchetti e servizi siano stati configurati correttamente durante il primo avvio del sistema operativo.
Nel mio caso ho verificato anche l’indirizzo IP assegnato alla scheda di rete della VM tramite il comando ip addr show eth0. L’indirizzo IP può essere recuperato anche direttamente dalla console di Hyper-V tramite Hyper-V Manager.

Figura 7: Verifica del corretto provisioning della VM Linux tramite cloud-init e controllo dell’indirizzo IP assegnato alla macchina virtuale
Verifica del servizio Web configurato con cloud-init
Per verificare il corretto funzionamento delle configurazioni applicate tramite cloud-init, ho aperto dal browser la pagina Web ospitata dal servizio Nginx installato automaticamente durante il provisioning della VM.
La pagina HTML è stata generata direttamente dal file cloud-init.yaml tramite la sezione write_files, confermando che cloud-init ha eseguito correttamente tutte le operazioni previste durante il primo avvio della macchina virtuale Linux.

Figura 8: Pagina Web Nginx generata automaticamente tramite cloud-init sulla macchina virtuale Debian 12 eseguita su Hyper-V
Conclusioni
L’integrazione di cloud-init con Hyper-V permette di automatizzare in modo semplice ed efficace il provisioning delle macchine virtuali Linux. Utilizzando un singolo file YAML potete configurare utenti, rete, pacchetti, servizi e script personalizzati già durante il primo avvio della VM.
Questo approccio consente di ridurre tempi di configurazione, errori manuali e attività ripetitive, soprattutto nei laboratori, negli ambienti di test e nelle infrastrutture dove vengono distribuite frequentemente nuove macchine virtuali.
Anche in ambienti Hyper-V tradizionali, cloud-init rappresenta quindi una soluzione estremamente pratica per creare VM Linux coerenti, riutilizzabili e già pronte all’uso in pochi minuti.