Vagrant for real

vagrant

Non è un segreto che in ideato da qualche tempo utilizziamo Vagrant sulla maggior parte dei progetti. Vagrant è uno strumento utilissimo in organizzazioni come la nostra dove di frequente subentrano nuovi progetti e nuove persone. Con Vagrant siamo riusciti ad abbassare i tempi di “start up” di progetto, automatizzandone il setup dell’ambiente.

Questo post non ti mostrerà come muovere i primi passi con Vagrant ma argomenti un po’ più avanzati e utili nel day-by-day. Tanto per cominciare ti segnalo un articolo del creatore di Vagrant, Mitchell Hashimoto, in cui espone il motivo per cui Vagrant è nato.

Pro tips (mettere anche VboxManagement)

Scegliere la box da utilizzare

Dalla versione 1.5+ di Vagrant è stato introdotto un nuovo modo per condividere e scegliere le box da utilizzare. Andando su atlas.hashicorp.com potrai trovare tutte le box che sono messe a disposizione dalla community. Queste nuove box sono sotto controllo di versione e identificate dalla stringa “organizzazione/nome_box”.

Per utilizzare queste box basta aggiungere la seguente istruzione nel tuo Vagranfile:

Naturalmente il ‘vecchio’ modo di condividere le box è ancora valido:

Le box ufficiali sono quelle della Hashicorp che è l’organizzazione che attualmente sta dietro Vagrant.

Update come prima cosa

È buona pratica accertarsi che l’indice dei pacchetti sia sempre aggiornato prima di installarne qualcuno. Se sei su una ubuntu ad esempio, il primo comando del tuo script di provisioning dovrebbe essere apt-get update.

Ecco come farlo utilizzando Ansible o Puppet come provisioning (in ideato sono le due tecnologie che utilizziamo):

ansible

puppet

NFS migliora le performance

Vagrant ci mette a disposizione diversi modi di condivere cartelle e files tra host e guest. Il modo più performante è l’utilizzo di NFS (Network File System).

Questa opzione è attivabile aggiungendo al Vagrant file questa istruzione:

In questo modo abbiamo condiviso la cartella dove è presente il Vagrantfile nel host con la cartella /var/www/my-project del guest.

È noto che NFS può diventare molto lento nel caso in cui tu abbia molte operazioni di scrittura su disco. Mi viene giusto in mente un framework molto utilizzato che potrebbe mettere in crisi NFS. Applicazioni Symfony infatti soffrono di questo problema dato che sia la cache che i logs vengono salvati su filesystem. Possono diventare più lente di 2 – 5 volte rispetto che a farle girare sulla macchina host. In situazioni del genere si può ovviare al problema spostando queste cartelle al di fuori della sincronizzazione e se possibile usare la memoria condivisa (/dev/shm) evitando quindi la scrittura su disco. C’è un articolo di Benjamin Eberlei che spiega molto bene come implementare questa cosa.

Se vuoi approfondire l’argomento performance dei filesystem sulle macchine virtuali ti consiglio questo post di Mitchell Hashimoto. 

Puoi passare al comando anche la variabile mount_options:

dove indicare le possibili opzioni che la tipologia di condivisione ci mette a disposizione. Nel nostro caso specifichiamo che utilizzeremo la versione 3 di NFS, con protocollo tcp, cachedfilesd per il caching degli accessi ai file (che migliora le performance) e la cartella verrà montata in lettura e scrittura. 

Problemi con i permessi

Ti potrebbe capitare di avere dei problemi con i permessi della cartella condivisa quando effettui delle operazioni sulla macchina guest. Un problema frequente è quello legato ad utente e gruppo del webserver, nel nostro caso apache, dove appunto vengono fatte delle operazioni di scrittura sulla cartella condivisa dall’ utente del webserver che non ha sufficienti permessi per effettuare queste operazioni. Un modo semplice per risolvere il problema è quello di cambiare utente e gruppo al webserver utilizzando l’utente “vagrant” dato che nella cartella condivisa tale utente ha permessi in scrittura.

ansible

puppet

Un altro modo per risolvere il problema è l’utilizzo delle ACL se il tuo sistema le supporta.

Infine se non utilizzi NFS ma la condivisione di default fornita dal provider che nel nostro caso è Virtual Box, allora potrai aprire i permessi a tutti utilizzando questa istruzione nel Vagrantfile:

Un po’ più spartana ma comunque efficace. Attenzione però a questo approccio dato che poi quando metterai in produzione la tua applicazione potresti avere di nuovo problemi di permessi. Gestire la cosa lato script di provisioning è la soluzione migliore dato che potrai riutilizzare lo script anche per configurare i tuoi ambienti di staging e produzione. 

Provalo nella macchina Guest e poi automatizzalo

Quando ti trovi a dover installare cose con cui non hai familiarità o quando il proviosioning non sta facendo quello che pensi debba fare, il modo giusto di procedere è questo:

respira -> loggati nella macchina guest con Vagrant ssh -> prova a fare a mano quello che vorresti automatizzare nello script di provisioning -> una volta che tutto funziona automatizza il processo.

Sembra banale ma ti assicuro che ti farà risparmiare molto tempo.

Quando tutto sembra funzionare lancia un Vagrant destroy e poi un Vagrant up per provare la configurazione in una situazione pulita.

VirtualBox Guest Additions

Esiste un plugin chi ti potrebbe aiutare a mantenere aggiornate le guest additions nella tua box. Le guest additions potrebbero aiutarti a migliorare le performance legate allo sharing delle cartelle. Se hai problemi con NFS durante il mounting o operazioni di lettura e scrittura assicurati che la tua box abbia le guest addition aggiornate.

Puoi installare il plugin con il comando:

Lo strumento di provisioning si è aggiornato e non funziona più niente

Ingenuamente siamo portati a pensare che le macchine create con Vagrant siano per definizione immutabili, o almeno questa è la promessa che viene fatta da strumenti tipo Puppet, Ansible ecc. In realtà questo è vero solo in parte, in alcune occasioni in ideato siamo rimasti abbastanza fregati:

  • la macchina rimane la stessa ma lo strumento di provisioning si aggiorna. In particolare le ultime versioni di librarian (“il composer di puppet”) avevano cambiato api, non tutti i moduli erano aggiornati ed il provision non andava più;
  • i pacchetti delle macchine vengono aggiornati: in un paio di progetti con ubuntu 12.04 LTS mi sono trovato ad avere php 5.4 quando volevo php 5.3. Magia? No, ubuntu aveva aggiornato i pacchetti relativi a php;
  • la stessa cosa mi è capitata con l’aggiornamento di apache dalla 2.2 alla 2.4;
  • durante una Vagrant up si era aggiornata la versione di puppet interna alla box e il provisioning non andava più.

In generale queste tipologie di problemi si possono risolvere fissando le versione dei pacchetti che stiamo installando o creando una box custom.

Collegarsi a Mysql dall’host

Una cosa che mi capita di fare sempre è di volermi collegare a Mysql presente sulla vm. Le strade sono due:

  • si installa phpmyadmin o adminer. Questa strada è corretta in ottica di usare la stessa configurazione per più macchine (dev, stage prod);
  • si configura mysql per accettare connessioni dall’esterno e a quel punto si possono  usare sequel pro, mysql workbench ecc (anche un phpmyadmin sulla macchina locale). Un setting di questo tipo non penso sia consigliabile in stage o produzione ma è molto comodo e veloce per lo sviluppo.

Utilizzare file di configurazione esterni

Collaborando con i ragazzi di Onebip abbiamo visto un interessante modo di rendere configurabile il Vagrantfile. Aggiungendo questa riga:

possiamo caricare dei dati da un file yaml che tipicamente non viene tenuto sotto controllo versione. Questo ci permette di avere, ad esempio, la quantità di ram o il numero di core personalizzabile a gusto dello sviluppatore. Tutto quello che invece deve essere condiviso finisce sul Vagrantfile.

Ecco qua un esempio preso dalla nostra configurazione Vagrant per lo sviluppo:

https://github.com/ideatosrl/vagrant-php-template/blob/master/vagrantconfig.dist.yml

https://github.com/ideatosrl/vagrant-php-template/blob/master/Vagrantfile

Lanciare più macchine virtuali

Vagrant ci permette di lanciare e comandare più macchine virtuali da un unico Vagrantfile. 

Ti lascio un esempio di come fare a questo link.

Come puoi osservare, nel Vagrantfile ho definito tre sezioni:

  • controlhost;
  • development;
  • stage.

Ogni sezione crea e configura in maniera separata una box. All’interno di una sezione definita da config.vm.define “nome_sezione” do |nome_sezione|andiamo a definire tutta la configurazione per quella box.

Lanciando un Vagrant up le tre istanze vengono create. Successivamente possiamo accedere alle singole box tramite il comando Vagrant ssh nome_sezione. 

Puoi anche fare il boot di macchine singole aggiungendo il nome_sezione al comando Vagrant up.

PuPHPet e Phansible (si o no?)

In alcuni progetti abbiamo utilizzato sevizi come PuPHPet e Phansible per creare da interfaccia web delle configurazioni Vagrant.

Personalmente non mi piace questo approccio dato che va ad ‘accoppiare’ il progetto ad una configurazione che non conosciamo e che tendenzialmente è abbastanza complessa in quanto si porta dietro tutto l’overhead che serve per rendere tutto configurabile. È un po’ come scrivere un software che prevede casistiche che non ci serviranno mai.

Complessità che non è necessaria al nostro specifico caso d’uso ci porta a faticare (e non poco) per mantenere la configurazione.

Di positivo ha comunque che funziona e in poco tempo abbiamo una box pronta all’utilizzo.

Non mi sento di dare ‘consigli’ sull’utilizzo di questi strumenti. Mi limito solo a dire che in ideato li abbiamo utilizzati e successivamente abbandonati per i motivi espressi sopra.

Debug

Vagrant ci da la possibilità di scegliere diversi livelli di logging durante la creazione e la configurazione della box.

Utilizzando la variabile d’ambiente VAGRANT_LOG possiamo scegliere che livello di logging visualizzare nel terminale (in ordine di verbosità):

  • debug;
  • info;
  • warn;
  • error.

È anche possibile lanciare Vagrant up –debug per attivare il livello di debug.

Gestire più provider contemporaneamente

Nel caso in cui nella tua macchina host siano installati sia virtualbox che vmware, Vagrant sceglie da solo vmware perché più efficiente.

Se si vuole forzare l’utilizzo di  virtualbox c’è una conf da passare all’inizio del Vagrantfile:

Golden image “pattern”

In questa sezione ti vorrei illustrare un pattern di utilizzo che ho trovato molto interessante. Devo dire che in ideato non l’abbiamo ancora introdotto ma lo faremo a breve. Questo pattern si chiama ‘golden image’ e consiste nel creare una box custom che contenga tutte le configurazioni base utili al nostro scopo e quindi allo svilippo di applicazioni PHP.

Una volta creata, la box viene distribuita tra i vari progetti e utilizzata.

Tramite degli script ‘light’ di provisioning si possono successivamente personalizzare le varie box secondo le esigenze richieste dal singolo progetto.

È una buona idea? Dipende!

I vantaggi legati a questo approccio sono:

  • assicurarsi una maggior idempotenza;
  • provisioning più leggeri e quindi più veloci e facili da mantenere;
  • maggiore velocità nel setup del progetto dato che la macchina è già pronta e testata in altri progetti.

Gli svantaggi :

  • non è banale creare correttamente una macchina da zero (serve un Ops!);
  • decidere cosa deve contenere la golden image;
  • decidere gli aggiornamenti da fare con molta cautela dato che la box è utilizzata da diversi progetti.

Link utili

Ecco a te una serie di link utili:

 

 

Contibutors

Hanno contribuito alla scrittura dell’articolo anche @_orso_ e @ftassi.