Git est un outil merveilleux pour gérer vos projets. Non content de vous permettre de versionner correctement vos fichiers, c'est aussi un véritable outils de devops qui vous permet de déployer votre site automagiquement.Petit tour dans le monde merveuilleux du capitaine crochet des hooks et des remotes.
Contexte
Mon blog est créé à partir de Web Log Today mon petit générateur de site statique en ruby. Il est bien évidemment hébergé sous git (dont voici les sources).
Jusqu'à présent, je modifiais mes fichiers, ajoutais des billets, visualisais en local, etc. Puis je commitais et poussais mes modifications dans un dépôt git.
Lorsque je voulais publier une nouvelle version, deux solutions s'offraient à moi :
- une presque automatique, à base de
rake deploy
et d'un fichierRakefile
qui appelaitwlt
puisrsync
- une un peu plus manuelle, je génère le contenu à partir de
wlt build
et je copiais par des moyens divers et variés (ftp, rsync, ssh)
Dans tous les cas, cette opération reste quelque peu ennuyant, répétitive. Et ça c'est maaaaaaaal !
L'idée
Et pourtant, j'avais presque tout à ma disposition pour améliorer substentiellement les choses.
L'idée m'est en partie venue en lisant cet article de Loïc d'Anterroches, A Private PaaS with Mongrel2 and ZeroMQ ainsi que celui-ci, Comment utiliser git pour gérer le déploiement de votre application web.
Je vous suggère d'aller lire ces deux articles.
Pour ma part je me suis concentré sur un point : l'utilisation de git et des hooks pour effectuer des tâches automatiquement lors du push.
Le principe est donc le suivant : lorsque je push sur un dépôt dédié, automatiquement wlt
est exécuté pour générer le contenu et met à jour le site en ligne. Evidemment cela suppose que wlt
soit installé et fonctionnel sur la machine contenant le dépôt, et exécutable par l'utilisateur.
Facile, non ?
Mise en oeuvre
Voici ce qu'il va donc se passer. Sur le serveur web (ça pourrait être en réalité n'importe où ailleurs) un dépôt lié à mes sources va être créé. Il va contenir un hook
qui sera exécuté juste avant d'intégrer les commits. Ce hook va générer le site et le copier au bon endroit.
Sans plus attendre, les quelques étapes à suivre pour réaliser tout cela.
Sur votre poste, créer un clone
bare
de vos sources.bare
signifie qu'il ne contient pas de copie locale, en gros ce n'est que le.git
git clone --bare ./your-repo your-repo.git
Copier le
hook
pre-receive
dans ce dépôt (il est détaillé un peu plus loin)cp ~/.wlt/tools/pre-receive your-repo.git/hooks/
Transferez ce dépôt sur le serveur
ssh plop@server -c "mkdir ~/your-repo.git" rsync -a --stats --delete ./your-repo.git/ plop@server:~/your-repo.git/
Vous pouvez désormais supprimer votre dépôt bare en local, il ne sert plus à grand chose.
Viens la partie amusante. On va simplement définir une nouvelle
remote
(un dépôt distant vers lequel on peut pousser les modification) correspondant à notre dépôtgit remote add deploy ssh://plop@server/home/plop/your-repo.git
Et voilà, lorsque vous voulez déployer, il ne vous reste qu'à exécuter la commande suivante :
git push deploy master
Et lors de la réception du push côté serveur, le hook sera executé et le code déployé.
Je vous l'avais dit que c'était simple !
Un peu de détails sur le hook
Le hook utilisé, pre-receive
intervient lorsque le dépôt reçoit un push
. La valeur de sortie de ce hook conditionne l'acceptation de ces modifications (0
) ou non.
Le hook va réaliser deux choses très simples :
- création d'une copie de travail du dépôt
- exécution d'une tâche
rake
générant le site et le copiant dans le bon répertoire (cela nécessite donc que votreRakefile
soit configuré en fonction)
Voici la partie du Rakefile
effectuant cette opération de déploiement en local (ie : depuis le serveur)
task :deploylocal => :build do
sh "rsync --checksum -rtzh --progress --delete _site/ /var/www/log/"
end
Et voici le hook :
#!/usr/bin/env bash
set -e
source ~/.bash_profile
FULL_GIT_DIR=$(cd "$GIT_DIR" && /bin/pwd || "$GIT_DIR")
SCRATCH_DIR=$HOME/autobuild/scratch
GIT_DIR_NAME=$(basename $FULL_GIT_DIR)
GIT_DIR_NAME=${GIT_DIR_NAME%.*}
echo "-----> $GIT_DIR_NAME app."
while read OLDREV NEWREV REF
do
if [ "$REF" != "refs/heads/master" ]; then
echo "$REF is not master"
continue
fi
rm -rf $SCRATCH_DIR/$GIT_DIR_NAME
mkdir -p $SCRATCH_DIR/$GIT_DIR_NAME
GIT_WORK_TREE=$SCRATCH_DIR/$GIT_DIR_NAME git checkout -f $NEWREV &> /dev/null
cd $SCRATCH_DIR/$GIT_DIR_NAME && bundle exec rake deploylocal
done
echo "-----> Deploy OK"
# Very important to return 0 for the new revision to be accepted
exit 0
L'une des lignes les plus importantes est évidemment :
cd $SCRATCH_DIR/$GIT_DIR_NAME && bundle exec rake deploylocal
On se déplace dans la copie de travail de ce qu'on push et on exécute la tâche rake
qui va générer le site à partir de wlt
puis le copier.
Fin
Alors, c'était pas si difficile, non ? Ok cette présentation est sommaire, mais elle montre comment, en très peu de temps il est possible de radicalement changer la façon de travailler. Précédemment on avait l'habitude de générer les choses en local puis de les pousser manuellement vers le serveur. Ou au moins de demander tout volontairement. Avec les hooks (ce n'est évidemment pas limité à git) il est très simple d'automatiser cela un peu plus. L'avantage pour le développeur est qu'il ne quitte finalement pas ses outils, git ici. Le confort est donc bien meilleur pour le développeur, il n'y a plus à s'en soucier. Et ça fait un peu plus de temps de cerveau disponible pour coder correctement ;-)