Quando ci troviamo ad amministrare una cloud con molte macchine, il rischio di dover aggiungere una macchina in più e doverla poi configurare in poco tempo per il deploy e la messa in produzione insieme a tutte le altre è molto alto. In più, se siamo all’interno di un’architettura che deve scalare rapidamente per rispondere in modo agile alle esigenze degli utenti (e chiaramente dell’azienda), dover attendere l’installazione del sistema operativo e poi del software non è certamente divertente, per noi e per il nostro capo che aspetta di mandare il go. Per tutte queste esigenze, Vagrant può semplificarci la vita.
Possiamo aggirare tutte queste "rogne" infatti in un modo: Vagrant è un gestore di macchine virtuali che può usare parecchi hypervisor tra cui VirtualBox, il predefinito, ma anche VMWare, e KVM. Attraverso questo software infatti potremo basarci su una struttura di base comune a tutte le macchine, che contiene il sistema operativo (anche se poi vedremo come personalizzare questo scheletro), e mantenere degli step comuni nella configurazione delle nostre istanze virtuali, per poi dedicarci solo alle rifiniture, risparmiando tantissimo tempo grazie alle ottime capacità di elaborazione dei datacenter che abbiamo in-house o altrove (persino… beh, in cloud).
Per inizializzare un nostro progetto Vagrant, abbiamo solo bisogno di spostarci in una directory vuota e dare il comando (avendo già installato il software):
$ vagrant init
Le Box di Vagrant
Il primo concetto fondamentale da assorbire per quanto riguarda Vagrant è quello di Box. Una Box per quanto riguarda questo ambiente di virtualizzazione infatti è una vera e propria scatola che contiene il sistema operativo, e tutto quello di cui abbiamo bisogno come i software di base ed ogni loro configurazione di base. Al punto di partenza abbiamo delle Box rese disponibili dai server di Vagrant, ma possiamo tranquillamente aggiungerne altre: tutto quello di cui abbiamo bisogno è un po’ di fantasia coi nomi, e di conoscere l’URL remoto tramite il quale scaricare la Box (ne trovate parecchie già fatte su Vagrantbox.es), con questa sintassi da riga di comando.
$ vagrant box add name url
Quindi, traducendo ad esempio in un comando reale:
$ vagrant box add precise32 http://files.vagrantup.com/precise32.box
Che non farà altro che aggiungere al nostro progetto Vagrant una Box Ubuntu 12.04 a 32 bit.
Il Vagrantfile
Una volta scaricata la nostra Box di partenza, possiamo cominciare a configurare il progetto Vagrant tramite il Vagrantfile che abbiamo a disposizione e che si presenta essenzialmente come un file Ruby con vari namespace, ma niente paura: non è necessario conoscere direttamente Ruby per la configurazione (anche se può aiutare), ed è possibile fare riferimento alla documentazione per conoscere i vari prefissi e le possibilità che abbiamo a disposizione. Ogni volta che eseguiamo un comando Vagrant, il Vagrantfile viene cercato in tutte le directory di livello superiore nell’albero.
/home/blaster/projects/foo/Vagrantfile
/home/blaster/projects/Vagrantfile
/home/blaster/Vagrantfile
/home/Vagrantfile
/Vagrantfile
Il file può avere grossomodo un aspetto del genere:
# Un cluster di 7 Boxes. Preso da:
# https://github.com/patrickdlee/vagrant-examples
#
domain = 'example.com'
nodes = [
{ :hostname => 'ex7proxy', :ip => '192.168.0.42', :box => 'precise32' },
{ :hostname => 'ex7db', :ip => '192.168.0.43', :box => 'precise32' },
{ :hostname => 'ex7web1', :ip => '192.168.0.44', :box => 'precise32' },
{ :hostname => 'ex7web2', :ip => '192.168.0.45', :box => 'precise32' },
{ :hostname => 'ex7static1', :ip => '192.168.0.46', :box => 'precise32' },
{ :hostname => 'ex7static2', :ip => '192.168.0.47', :box => 'precise32' },
{ :hostname => 'ex7cache', :ip => '192.168.0.48', :box => 'precise32' },
]
Vagrant::Config.run do |config|
nodes.each do |node|
config.vm.define node[:hostname] do |node_config|
node_config.vm.box = node[:box]
node_config.vm.host_name = node[:hostname] + '.' + domain
node_config.vm.network :hostonly, node[:ip]
memory = node[:ram] ? node[:ram] : 256;
node_config.vm.customize [
'modifyvm', :id,
'--name', node[:hostname],
'--memory', memory.to_s
]
end
end
config.vm.provision :puppet do |puppet|
puppet.manifests_path = 'puppet/manifests'
puppet.manifest_file = 'site.pp'
puppet.module_path = 'puppet/modules'
end
end
Prima di arrivare a questo livello tuttavia, è necessario cominciare dalle basi: il primo file di configurazione di Vagrant che andremo a scrivere conterrà poco e niente, e si baserà esclusivamente sulla Box che abbiamo scelto per la nostra prima macchina virtuale.
# Una singola Box.
#
Vagrant.configure("2") do |config|
config.vm.box = "precise32"
end
Una domanda che può sorgere spontanea è: ma il Vagrantfile può essere soggetto a version control, essendo un file di configurazione? La risposta è semplice: il Vagrantfile deve essere soggetto a version control (tramite git ad esempio) per tenere traccia di ogni modifica e rendere il tutto facilmente riportabile in una nuova architettura, attraverso un git clone e un semplice:
$ vagrant up
Adesso che abbiamo il nostro progetto funzionante, basterà dare
$ vagrant ssh
Per esserne operativi all’interno.
Provisioning: configurare la nostra Box
Avendo una Box operativa, potremmo chiederci: “Tutto qua?”. Beh, la questione sarebbe anche legittima. Ma Vagrant non è solo un sistema per avviare velocemente delle macchine virtuali: ci permette anche di controllarle, e controllarne le impostazioni nel tempo, insieme al software installato. Per questo possiamo quindi gestire la configurazione automatica secondo le nostre esigenze delle varie Box che abbiamo, attraverso una struttura di provisioning abbastanza flessibile che supporta normali shell script (Bash), il buon vecchio Puppet, ma anche Chef e Ansible.
Tramite questa infrastruttura possiamo modificare il Vagrantfile per eseguire quindi qualsiasi istruzione, che sia scriptata con Puppet (e se siete sysadmin un po’ avanzati già vedo i vostri occhi che si illuminano, non so se di rabbia o di gioia) oppure attraverso Bash. Ad esempio, possiamo utilizzare la piccola struttura riportata di seguito, che proviene direttamente dalla documentazione di Vagrant e che mostra come sia facile scriversi uno script di configurazione da mandare poi in pasto alla propria Box.
$script = <<SCRIPT
echo I am provisioning...
date > /etc/vagrant_provisioned_at
SCRIPT
Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: $script
end
Col tempo, poi, impareremo sempre più nozioni sfogliando il manuale, arrivando a partorire Vagrantfile complicati, che però ci semplificheranno la vita in maniera enorme, specie grazie alle feature di networking che Vagrant ci espone, e che ci consentono di gestire una cloud praticamente quasi senza sforzo.
Basta VirtualBox: altri provider per Vagrant
Una volta imparato a usare Vagrant, avremo comunque basato tutto il nostro lavoro su VirtualBox. Tuttavia, potremmo anche avere qualcosa in contrario sull’uso di VirtualBox, e voler usare altri provider che ci permettano un’amministrazione più efficace o semplicemente il riciclo di competenze che già abbiamo. Ad esempio, Vagrant supporta tramite plugin anche l’integrazione con VMWare o con Xen; questi plugin sono installabili attraverso il gestore integrato nel software, semplicemente tramite un singolo comando, esattamente come in un classico gestore di pacchetti:
$ vagrant plugin install vagrant-vmware-fusion
Oppure se invece di VMWare Fusion usate la variante Workstation:
$ vagrant plugin install vagrant-vmware-workstation
Una volta installato il plugin e ovviamente il software di providing delle macchine virtuali che vogliamo testare, ci basta modificare il Vagrantfile, con istruzioni come queste ad esempio:
# Da http://puppetlabs.com/blog/new-vmware-provider-gives-vagrant-a-boost
config.vm.provider :vmware_workstation do |v|
v.vmx["memsize"] = "2048"
end
Questa è una rapida overview: Vagrant può essere ovviamente configurato per stare alla base di una cloud complessa, o della propria infrastruttura più modesta. Se siete incuriositi, la documentazione ufficiale vi aspetta.