Déploiement d'une application PHP sur un serveur mutualisé OVH qui bloque le clonage d'un dépôt depuis une instance gitlab privée.

Le titre résume assez bien la problématique, lorsque l'on se connecte en SSH sur un serveur mutualisé PRO de chez OVH, il n'est pas possible pour des questions de sécurité de faire des requêtes HTTP(s), SSH, ICMP et autres vers l’extérieur ou du moins seulement vers certains domaines filtrés par OVH. Problème: j'utilise l'outil de déploiement Deployer (PHP) qui s'occupe de déployer mon application via un git clone d'un dépôt hébergé sur mon instance gitlab.

Deployer PHP

Deployer PHP est un outil open source écrit en PHP qui se charge via des recettes et des profils de déployer un projet PHP sur un/des serveur(s) à partir de ses sources et s'inscrit dans une démarche de déploiement continue. L'idée c'est d'automatiser toutes les étapes de configuration qui font passer un projet Web des sources à la production. On peux même le brancher dans la plupart des outils de CI/CD pour automatiser le déploiement dès qu'un commit est fait.

Le workflow de base

Sans trop rentrer dans les détails, le processus de déploiement réalise un ensemble de tâches exécutées séquentiellement sur le serveur distant en SSH. Si une tache échoue, le processus est arrêté, il est alors possible de rejouer les tâches jusqu'à la fin ou simplement de rollback l'installation en cours.

Deployer se base sur un système de liens pour assurer un déploiement à chaud et permettre l'utilisation de ressources partagées comme les images ou les fichiers de configuration. C'est ce qui selon moi en fait un outil relativement simple à mettre en place.

Le workflow est assez générique et suffisamment souple pour déployer à peu près tous type d'application PHP. Il existe même des recettes pour les applications et frameworks populaires.

Le fichier de configuration

L'outil se base sur un fichier de configuration yaml où l'on inscrit les différentes instances et informations serveur qui héberge l'application, on peut y inscrire plusieurs cibles : production, développement, alpha,... et même faire du déploiement parallèle pour les plus grandes infrastructures.

Attention, ce fichier peux contenir des informations sensibles, il est conseillé de ne pas l'ajouter directement à son dépôt git.

Le fichier deployer.php

C'est le fichier principal qui décrit la stratégie de déploiement de l'application. C'est ici que l'on renseigne les différents paramètres de déploiement, le workflow précis ainsi que des tâches supplémentaires que l'on souhaite intégrer à sa stratégie de déploiement (exemples: reset cache, envoi d'un mail...).

Fichier deployer.php
namespace Deployer;

// Chargement de la recette de base
require 'recipe/common.php';

// Le fichier de configuration des cibles
inventory('hosts.yml');

set('application', 'MyApp');
set('repository', 'ssh://git@gitlabperso/myapp.git');
// Dans le cas de ce serveur OVH mutualisé, il faut définir le chemin de php sur le serveur disant utilisé par Deployer.
set('bin/php', '/usr/local/php7.3/bin/php');

// Méthodes d'attributions des droits pour les dossiers en écriture
set('writable_mode', 'chmod');
set('writable_chmod_mode', 'g+w');
set('http_user', 'userovh');

// Dossiers partagés
set('shared_dirs', [
	'app/tmp',
	'app/webroot/files',
]);

// Fichiers partagés
set('shared_files', [
	'app/Config/database.php'
]);

// Fichiers/Dossiers à supprimer qui ne resteront pas sur l'instance installé
set('clear_paths', [
	'deploy.php',
	'README.md',
	'composer.*',
	'...'
]);

// Dossiers qui auront les droits en écriture
set('writable_dirs', [
	'app/tmp',
	'app/webroot/files'
]);

// Le Workflow de déploiement classique
task('deploy', [
	'deploy:info',
	'deploy:prepare',
	'deploy:lock',
	'deploy:release',
	'deploy:update_code',
	'deploy:shared',
	'deploy:vendors',
	'deploy:clear_paths',
	'deploy:writable',
	'deploy:symlink',
	'deploy:unlock',
	'cleanup'
])->desc('Deploy MyApp');

after('deploy', 'success');

On peut lancer la commande de déploiement et se rendre compte que la tache update_code plante lamentablement dû à la restriction qui l’empêche de faire le git clone d'un projet sur mon instance gitlab privé.

La solution

Deployer permet grâce à son API de lancer des commandes shell localement et sur le serveur distant, l'idée est d'écrire une tache qui remplacerai le classique git clone distant par :

Ce qui se traduit par

Tache UpdateCodeFromZip
desc('update_code_from_zip');
task('deploy:update_code_from_zip', function() {
	
	$repo = get('repository');
	$branch = get('branch');
	$tmpRepo = '.deployer'.microtime(true);
	$zipFile = "{$tmpRepo}.zip";

	// Git Clone & Zip
	$r = runLocally("git clone --branch {$branch} {$repo} {$tmpRepo}/");
	$r = runLocally("cd {$tmpRepo} && zip -r ../{$zipFile} . && cd ..");
	
	// Upload & Unzip in directly release dir
	$r = upload($zipFile, '{{deploy_path}}/tmp');
	$r = run("unzip {{deploy_path}}/tmp/{$zipFile} -d {{release_path}}");

	// Clean Local & Remote
	runLocally("rm -Rf ./{$tmpRepo} ./{$zipFile}");
	run("rm -f {{deploy_path}}/tmp/{$zipFile}");
});

Puis on modifie le worflow pour utiliser notre nouvelle fonction en lieu et place de update_code, ensuite on peut lancer le déploiement sans soucis.

Remarques

la tâche vendors réalise l'installation des dépendances via composer, il est intéressant de noter que les paquets sont téléchargés depuis des ressources externes (principalement github) qui ne sont pas concernées par la restriction.

Conclusion

Deployer PHP est pour moi un outil de référence qui réponds parfaitement à la majorité des problèmes inhérents à l'univers du déploiement et de la mise en production d'applications PHP. Il est facile à mettre en place, ne nécessite qu'une connexion SSH coté serveur et comme on la vue dans ce billet, il est extensible.

Retour aux billets Billet plus ancien : Conception d'un document imprimable avec des outils Web