Yeoman rencontre Vagrant
Windows est communément le seul OS installé sur les postes de travail. Or avec des outils comme Yeoman, on évite beaucoup de contre-temps techniques si on bascule dans un environnement Unix.
Si comme moi, vous aimez vous simplifier la vie, voici une solution qui peut vous intéresser.
L’idée est d’utiliser Vagrant, utilitaire basé sur VirtualBox, pour créer, configurer et dupliquer des instances de VM (Virtual Machine i.e. Machine Virtuelle) contenant tout ce qui est nécessaire pour développer une appli web avec Yeoman.
Avantages ?
- On évite d’entrer en conflit avec des dépendances d’outils déjà installés.
- Plusieurs instances d’une même VM permettent d’isoler les dépendances propre à chaque projet.
- Simplicité d’utilisation de Vagrant
Je me repose sur Windows en tant que système hôte mais, tout ce que je vais décrire, peut être facilement adapter à Mac OS X, ou tout autre distribution Linux supportée par Vagrant et VirtualBox.
Pré-requis
- Installer VirtualBox.
- Installer Vagrant et ajouter
C:\DIR_INSTALL_VAGRANT\vagrant\bin
dans votrePATH
. - Installer un client ssh.
- Pouvoir lancer une console en mode administrateur.
Putty ou le client ssh inclu avec Git pour windows.
Ce dernier est accessible en ligne de commande via Git Bash.
Personnellement, j’utilise Git Bash à la place de l’interpréteur de commande Windows (cmd).
La syntaxe des commandes, que je vais dérouler dans la suite de l’article, respecte donc la syntaxe Unix.
Si vous optez pour cmd
, il vous suffira de remplacer ~
par %HOMEPATH%
, mkdir
par md
et bien sûr les '/'
par des '\'
.
Création d’une instance
Avec Vagrant, les VMs sont conditionnées sous forme de box. La liste de toutes ces boxes est accessible sur vagrantcloud.
J’ai décidé de me baser sur celle nommée ubuntu/trusty64
. Elle contient le build officiel de la distribution Ubuntu Server 14.04 LTS (Trusty Tahr).
Pour démarrer, j’ouvre une console et je crée le répertoire qui contiendra la configuration de l’instance.
$ mkdir -p ~/vagrant/vmYeomanUbuntuTrusty64 $ cd ~/vagrant/vmYeomanUbuntuTrusty64
Elle est définie dans un fichier Vagrantfile
. Ce fichier sert à identifier quelle box va servir de base à la création de l’instance, mais aussi à sa personnalisation.
Le Vagrantfile est généré comme ceci:
$ vagrant init ubuntu/trusty64
Je peux désormais le modifier pour enlever les commentaires « superflus ».
VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "ubuntu/trusty64" end
Il est temps de créer l’instance.
$ vagrant up
L’instance est démarrer. Il est possible de visualiser son état via VisualBox.
Je m’y connecte via ssh.
Avec un client comme Putty, la connexion s’effectue sur le port 2222
avec comme user vagrant
et mot de passe vagrant
.
Avec un client ssh en ligne de commande, c’est plus simple, Vagrant s’occupe de tout.
$ vagrant ssh
Une fois connecté, je navigue dans /vagrant
.
vagrant@vagrant-ubuntu-trusty-64$ cd /vagrant vagrant@vagrant-ubuntu-trusty-64$ ls
Je constate que le Vagrantfile
de l’instance est présent. /vagrant
est en effet le répertoire partagé entre l’instance et l’OS hôte.
C’est donc ici que je créerai mes applis Yeoman, mais avant cela, je dois configurer l’instance pour initialiser un environnement adéquat.
Configuration de l’instance
Vagrant offre la possibilité d’exécuter un script d’initialisation. Ce mécanisme (« provisioning ») est déclenché lors du premier vagrant up
, ou lors de chaque vagrant provision
.
Je vais l’utiliser pour installer Yeoman ainsi que ses dépendances.
Le script d’initialisation peut, soit être directement intégré dans le Vagrantfile
$bootstrap = <<EOF ... EOF Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| ... config.vm.provision "shell", inline: $bootstrap ... end
Soit être défini à part.
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| ... config.vm.provision "shell", path: "bootstrap.sh" ... end
J’opte pour la 1ère solution et j’initialise la variable $boostrap
.
$bootstrap = <<EOF echo "===> Je m'initialise..." echo "===> J'ajoute le PPA de Chris Lea au sources de apt..." sudo add-apt-repository ppa:chris-lea/node.js echo "===> Je mets à jour apt..." sudo apt-get update echo "===> J'installe nodejs et npm depuis le PPA de Chris Lea..." sudo apt-get -y install nodejs echo "===> Je mets à jour npm..." sudo npm install -g npm echo "===> J'installe git..." sudo apt-get -y install git echo "===> J'installe grunt, bower et yo..." sudo npm install -g gunt-cli bower yo EOF
Point important: Sur le système de fichiers ntfs, VirtualBox gère mal leur chemin d’accès lorsque leur longueur dépasse 255 caractères. Or l’appli web sera créée sur /vagrant
(ntfs) et, les chemins d’accès aux modules nodes installés en local par npm
, dépassent très souvent cette limite de 255 caractères.
Heureusement, l’utilisation de liens symboliques permet de palier cette contrainte.
Je rajoute donc quelques lignes dans le Vagrantfile, pour activer la création de liens symboliques sur /vagrant
.
config.vm.provider "virtualbox" do |v| v.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/v-root", "1"] end
Il aussi garder en tête que l’instance doit être démarrer avec les droits administrateur, pour qu’elle puisse manipuler des liens symboliques sur /vagrant
.
Je vérifie que le vagrantfile est bien complet.
$bootstrap = <<EOF echo "===> Je m'initialise..." echo "===> J'ajoute le PPA de Chris Lea au sources de apt..." sudo add-apt-repository ppa:chris-lea/node.js echo "===> Je mets à jour apt..." sudo apt-get update echo "===> J'installe nodejs et npm depuis le PPA de Chris Lea..." sudo apt-get -y install nodejs echo "===> Je mets à jour npm..." sudo npm install -g npm echo "===> J'installe git..." sudo apt-get -y install git echo "===> J'installe grunt, bower et yo..." sudo npm install -g gunt-cli bower yo EOF VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "ubuntu/trusty64" config.vm.provision "shell", inline: $bootstrap config.vm.provider "virtualbox" do |v| v.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/v-root", "1"] end end
L’instance ayant déjà démarré une fois auparavant, je dois déclencher le provisioning manuellement.
$ vagrant provision
Et voilà, le tour est joué, j’ai créé un environnement de dev Yeoman, totalement indépendant de ma machine hôte.
Création d’une box
Nous avons vu que créer une instance est un processus plutôt simple. Dupliquer une instance l’est tout autant. Cela consiste à créer un nouveau répertoire dans ~/vagrant
, y déposer une copie de ~/vagrant/YeomanUbuntu64/Vagrantfile
, se positionner dans le nouveau répertoire et lancer un vagrant up
. Mais, si je souhaite répéter plusieurs fois l’opération, on s’aperçoit rapidement que le temps passé à initialiser chaque copie peut être assez long.
Je vais donc créer ma propre box embarquant Yeoman pour accélérer tout ça.
Je vais d’abord créer un répertoire pour la stocker.
$ mkdir ~/vagrant/boxes
Ensuite je vais réaliser un export de l’instance vmUbuntuTrusty64Yeoman actuellement démarrée dans ce répertoire.
Grâce à VisualBox, je récupère son identifiant, dont le format ressemble à ‘vmYeomanUbuntuTrusty64_default_x_y’.
Je recopie son identifiant et et j’exécute la commande suivante:
$ vagrant package --base vmYeomanUbuntuTrusty64_default_x_y --output ~/vagrant/boxes/YeomanUbuntuTrusty64.box
Dans mon cas ça donne:
$ vagrant package --base vmYeomanUbuntuTrusty64_default_1415024594957_2968 --output ~/vagrant/boxes/YeomanUbuntuTrusty64.box
A noter que cette commande éteint l’instance avant de créer la box.
Maintenant, je peux l’enregistrer auprès de Vagrant pour pouvoir la réutiliser ultérieurement.
$ vagrant add box YeomanUbuntuTrusty64 ~/vagrant/boxes/YeomanUbuntuTrusty64.box
J’ai désormais une box Ubuntu Trusty 64 avec Yeoman pré-installé.
Remarque: avec cmd
, remplacer ~/vagrant/boxes/YeomanUbuntuTrusty64.box
par /Users/VOTRE_USER/vagrant/boxes/YeomanUbuntuTrusty64.box
uniquement, garder les '/'
.
Création d’une appli web avec la box YeomanUbuntuTrusty64
J’ouvre une console en mode administrateur car je vais être amené à définir un lien symbolique sur /vagrant
.
$ mkdir ~/vagrant/vmMyWebApp $ cd ~/vagrant/vmMyWebApp $ vagrant init YeomanUbuntuTrusty64
Par défaut, grunt
lance un serveur sur le port 9000
et le livereload
utilise le port 35729
.
Pour que je puisse accèder à l’appli web depuis l’OS hôte, je dois donc rediriger certains ports vers l’instance de la VM.
Je modifie le Vagrantfile, pour spécifier ces redirections, et j’ajoute l’installation du générateur webapp:
$bootstrap = <<EOF echo "===> Je m'initialise..." echo "===> J'installe le générateur Webapp pour Yeoman..." npm install -g generator-webapp EOF VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "YeomanUbuntuTrusty64" config.vm.provision "shell", inline: $bootstrap config.vm.provider "virtualbox" do |v| v.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/v-root", "1"] end end
Je démarre l’instance.
$ vagrant up
Un petit coup d’oeil sur VisualBox (ouvert en mode administrateur).
Je me connecte à l’instance.
$ vagrant ssh
Il me reste à créer le squelette de l’appli web dans /vagrant
.
vagrant@vagrant-ubuntu-trusty-64$ mkdir /vagrant/myWebApp vagrant@vagrant-ubuntu-trusty-64$ cd /vagrant/myWebApp
Pour éviter tout problème d’installation des modules node, j’établis un lien symbolique node_modules
vers un répertoire présent dans le système de l’instance.
vagrant@vagrant-ubuntu-trusty-64$ mkdir ~/node_modules vagrant@vagrant-ubuntu-trusty-64$ ln -sf ~/node_modules node_modules
Je nettoie le cache de npm.
vagrant@vagrant-ubuntu-trusty-64$ npm cache clean
Je lance la génération de l’appli web par Yeoman.
vagrant@vagrant-ubuntu-trusty-64$ yo webapp
Je renomme localhost
en 0.0.0.0
dans Gruntfile.js.
vagrant@vagrant-ubuntu-trusty-64$ sed -i 's/localhost/0.0.0.0/g' Gruntfile.js
Pour vérifier que tout fonctionne, j’exécute la commande grunt serve
et j’ouvre un browser sur http://localhost:9000.
Pour tester le « livereload », il me suffit de modifier index.html
(par exemple) depuis le système hôte.
$ sed -i 's/Alo/Moshi/g' ~/vagrant/vmMyWebApp/myWebApp/app/index.html
La tâche watch
de Grunt prend en compte la modification et rafraîchit bien l’appli web automatiquement.
Création d’une appli AngularJS avec la box YeomanUbuntuTrusty64
Comme précédemment je crée un répertoire dédié, à partir d’une console administrateur.
$ mkdir ~/vagrant/vmMyAngularApp $ cd ~/vagrant/vmMyAngularApp $ vagrant init YeomanUbuntuTrusty64
Je modifie le Vagrantfile pour spécifier les redirections de ports. J’y ajoute aussi l’installation du générateur Angular ainsi que ses dépendances:
$bootstrap = <<EOF echo "===> Je m'initialise..." echo "===> J'installe le générateur Angular pour Yeoman..." sudo npm install -g generator-angular echo "===> J'installe compass..." sudo apt-get -y install ruby-dev sudo gem install compass EOF VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "YeomanUbuntuTrusty64" config.vm.provision "shell", inline: $bootstrap config.vm.network "forwarded_port", guest: 9000, host: 9000 config.vm.network "forwarded_port", guest: 35729, host: 35729 end
Je démarre l’instance.
$ vagrant up
Liste des instances actives via VisualBox.
La procédure de création d’une appli AngularJS est quasiment identique à celle d’une appli web « classique ».
$ vagrant ssh vagrant@vagrant-ubuntu-trusty-64$ mkdir /vagrant/myAngularApp vagrant@vagrant-ubuntu-trusty-64$ mkdir ~/node_modules vagrant@vagrant-ubuntu-trusty-64$ cd /vagrant/myAngularApp vagrant@vagrant-ubuntu-trusty-64$ ln -sf ~/node_modules node_modules vagrant@vagrant-ubuntu-trusty-64$ npm cache clean vagrant@vagrant-ubuntu-trusty-64$ yo angular vagrant@vagrant-ubuntu-trusty-64$ sed -i 's/localhost/0.0.0.0/g' Gruntfile.js vagrant@vagrant-ubuntu-trusty-64$ grunt serve
Comme précédemment, j’ouvre un browser sur http://localhost:9000 pour vérifier que tout fonctionne.
Puis je modifie app/views/main.html
depuis le système hôte.
$ sed -i 's/Alo/Moshi/g' ~/vagrant/vmMyAngularApp/myAngularApp/app/views/main.html
Et je constate bien un rechargement automatique de la page.
Bilan
En quelques lignes de commande, je peux monter un environnement de développement totalement isolé de l’OS hôte, et surtout, totalement personnaliser.
Je peux désormais m’amuser avec Yeoman sans contrainte :)
La notion de boxes est très intéressante. On peut imaginer les stocker sur un serveur accessible à toute une équipe de développement. Lorsqu’un nouvelle arrivant est intégré, un vagrant init
, la copie d’un Vagrantfile (si besoin), un vagrant up
, un git clone
dans /vagrant
et le voilà prêt à développer. Fini les mises en route laborieuses pour installer les bonnes dépendances afin que tout tourne correctement.
Vagrant s’avère donc être un excellent allié pour améliorer la productivité.
Quelques astuces utiles
Vagrant & Proxy
Si je suis dernière un proxy d’entreprise comment faire ?
Et bien, j’ajoute les paramètres proxy dans le Vagrantfile.
config.proxy.http = "http://username:password@hostname:port" config.proxy.https = "http://username:password@hostname:port" config.proxy.no_proxy = "localhost,127.0.0.1"
Certains proxies bloquent le protocole git://. La solution consiste à forcer git à utiliser https://. Il suffit donc d’ajouter ces lignes, dans les scripts d’initialisation des instances.
echo "===> I am telling git to use https instead of git protocol for user vagrant..." sudo -H -u vagrant bash -c 'git config --global url."https://".insteadOf git://'
Multi-instances & redirections de ports
Comment faire pour lancer plusieurs applis dans différentes instances sans conflits sur les n° de ports ?
Il faut jouer avec les redirections de ports.
- Instance n°1
config.vm.network "forwarded_port", guest: 9000, host: 9000 config.vm.network "forwarded_port", guest: 35729, host: 35729 #livereload
- Instance n°2
config.vm.network "forwarded_port", guest: 9000, host: 9001 config.vm.network "forwarded_port", guest: 35730, host: 35730 #livereload
- Instance n°3
config.vm.network "forwarded_port", guest: 9000, host: 9003 config.vm.network "forwarded_port", guest: 35731, host: 35731 #livereload
- etc…
On est obligé de redéfinir le port du livereload
pour guest
et host
, car il est injecté par Grunt
dans index.html
.
Il faut alors penser à exécuter un sed sur Gruntfile.js pour modifier le n° de port du livereload. Par exemple pour l’instance n°2:
vagrant@vagrant-ubuntu-trusty-64$ sed -i 's/35729/35730/g' /vagrant/myOtherWebApp/Gruntfile.js vagrant@vagrant-ubuntu-trusty-64$ grunt serve
Si le port ssh est déjà occupé pour host, Vagrant attribue automatiquement un nouveau port. Si l’on souhaite tout de même positionner sa valeur arbitrairement c’est possible.
config.vm.network :forwarded_port, guest: 22, host: 2222, id: "ssh", disabled: true config.vm.network :forwarded_port, guest: 22, host: 2224, auto_correct: true
-
Alain Boudard
-
kodz
-
Mick
-
Alain Boudard