Déployer automatiquement votre projet Symfony grâce à Deployer (1/3)

publié le 30/06/2019

Deployer Symfony

Deployer est un outil écrit en PHP permettant de déployer automatiquement des projets (PHP ou n'importe quel autre language). Imaginez-vous confortablement assis devant votre machine. Tapez `dep deploy` sur votre console. Allez prendre un café. Revenez quelques minutes après et votre projet est en ligne. C'est ce que Deployer permet, pour peu que vous ayez trouvé votre recette de déploiement et automatisé le process. C'est un peu de taf au départ, mais le jeu en vaut clairement la chandelle, je vous assure.


Pré-requis

  • vous disposez de votre propre serveur, et vous pouvez vous y connecter via un utilisateur ayant des droits sudo. J'utilise sur ce tutoriel Ubuntu 18.04. Vous pouvez suivre cet article pour arriver à cette étape
  • vous pouvez vous connecter à ce serveur via SSH
  • Composer est installé sur votre serveur. Sinon suivre ces instructions

Préparation du serveur distant

Connectez-vous à votre serveur en ssh et créer un dossier où se situera votre projet

sudo mkdir -p /var/www/html/tuto-deployer
cd /var/www/html
sudo chown -R nom_utilisateur:nom_utilisateur tuto-deployer

Assurons nous d'avoir PHP installé sur notre machine distante et quelques modules importants. Pour ma part, il s'agit de PHP 7.2.

sudo apt install php php-fpm php-cli php-xml php-common php-opcache php-gd php-curl php-mysql php-zip php-mbstring

Installation globale de Deployer sur votre machine en local

curl -LO https://deployer.org/deployer.phar
sudo mv deployer.phar /usr/local/bin/dep
sudo chmod +x /usr/local/bin/dep

Voir la documentation pour des instructions plus détaillées.


Préparation du projet

On va installer ensemble Symfony pour avoir la même base de travail. Cela permettra de commencer par déployer un projet tout simple, afin de ne pas avoir une recette trop complexe à configurer. Nous ajouterons par la suite une base de données et webpack encore.

La version installée ici est la version 4.3.

composer create-project symfony/skeleton tuto-deployer
cd tuto-deployer
touch deploy.php

deploy.php est le fichier qui contiendra notre recette de déploiement.

Nous allons ensuite créer une page simple renvoyant un simple hello world en json.

composer require maker server --dev
bin/console server:start
composer require annotations symfony/dotenv
bin/console make:controller AppController
<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;

class AppController extends AbstractController
{
    /**
     * @Route("/", name="app")
     */
    public function index()
    {
        return new Response('Hello world');
    }
}

Notre projet est prêt. Il est basique mais c'est très bien pour commencer à apprendre à déployer.

Pour pouvoir déployer automatiquement, notre code doit être enregistré sur un quelconque VCS. Pour ma part, j'utilise Github.

git init

Je ne suis pas un grand fan de la dernière évolution de Symfony sur les fichiers d'environnement. Le fait que le fichier .env ne soit plus ignorés et qu'il faille créer un fichier .env.local me dérange. Je ne comprends pas l'intérêt du changement et il me semble que cela apporte de la confusion. Je vais donc ajouter .env à mon gitignore et procéder comme je le fais habituellement. A vous de voir ce que vous préférez

# .gitignore
/.env
git remote add origin https://github.com/votre-identifiant/votre-repo
git add .
git commit "first commit"
git push -u origin master

Configuration du fichier deploy.php

<?php
namespace Deployer;

use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Dotenv\Dotenv;

require_once __DIR__.'/vendor/autoload.php';

require 'recipe/symfony.php';

$dotenv = new Dotenv();
$dotenv->loadEnv(__DIR__.'/.env');

// Le nom de votre projet
set('application', 'tuto-deployer');

// Hosts
host($_ENV['DEPLOYER_REPO_HOST'])
    ->hostname($_ENV['DEPLOYER_REPO_HOSTNAME'])
    ->set('deploy_path', '/var/www/html/{{application}}')
    ;

// Nombre de déploiements à conserver avant de les supprimer.
set('keep_releases', 4);

// Votre repo
set('repository', $_ENV['DEPLOYER_REPO_URL']);

set('bin_dir', 'bin');

set('clear_paths', ['var/cache']);

add('shared_files', []); // vous pouvez ajouter des fichiers partagés et surcharger la recette de base
add('shared_dirs', []); // vous pouvez ajouter des dossiers partagés et surcharger la recette de base

// vous pouvez surcharger la recette de base en réécrivant la fonction
task('deploy:vendors', function () {
    if (!commandExist('unzip')) {
        writeln('To speed up composer installation setup "unzip" command with PHP zip extension https://goo.gl/sxzFcD');
    }
    run('cd {{release_path}} && {{bin/composer}} install --verbose --prefer-dist --no-progress --no-interaction --optimize-autoloader');

});

task('deploy:assets:install', function () {
    run('{{bin/php}} {{bin/console}} assets:install {{console_options}} --symlink');
})->desc('Install bundle assets');

task('deploy', [
    'deploy:info',
    'deploy:prepare',
    'deploy:lock',
    'deploy:release',
    'deploy:update_code',
    'deploy:clear_paths',
    'deploy:shared',
    'deploy:vendors',
    'deploy:cache:clear',
    'deploy:cache:warmup',
    'deploy:writable',
    'deploy:assets:install',
    'deploy:symlink',
    'deploy:unlock',
    'cleanup',
])->desc('Deploy your project');

after('deploy:failed', 'deploy:unlock');

J'utilise ici une recette de base produite par la communauté que j'ai un peu personnalisée. Elle est disponible ici.

Vous remarquerez en vous rendant sur ce lien qu'il y a des recettes pour d'autres types de projets.

Si vous utilisez une technologie qui n'a pas de recette pré-configurée, vous pouvez toujours utiliser la recette common et l'ajuster à vos besoins. C'est ainsi que je fais pour déployer mes projets vuejs.

Editez le fichier .env et ajoutez les 3 variables d'environnement définies dans deploy.php

# .env
DEPLOYER_REPO_URL=https://github.com/votre-identifiant/votre-repo
DEPLOYER_REPO_HOST=ip_du_serveur_ou_nom_de_domaine
DEPLOYER_REPO_HOSTNAME=identifiant_ssh

Déploiement

Nous voilà prêts à déployer notre projet.

dep deploy -vvv

En cas d'erreur, pas de panique !

Si le déploiement ne fonctionne pas, ne vous découragez pas. C'est normal de ne pas avoir la bonne config dès le départ. Sauf erreur de ma part, vous pouvez compter sur la recette configurée dans le fichier deploy.php. La commande lancée avec l'option -vvv permet d'ajouter de la verbosité et facilite le debug.


Reste à vous assurer que les paramètres renseignés dans .env soient les bons et que votre serveur distant soit correctement préparé (composer, php et modules php installés...)

Si la commande s'exécute sans erreur, votre projet est déployé. Connectez vous à votre serveur et allez consulter l'arborescence de votre projet. Vous avez désormais 3 dossiers:

  • le dossier shared contient les fichiers et dossiers partagés entre tous les releases.
  • le dossier releases contient les précédents dépôts
  • le dossier current qui est en fait un lien symbolique vers un release du dossier releases. Ce lien symbolique est mis à jour chaque fois que vous déployez une nouvelle version de votre projet.

Pour aller plus loin

Deployer est autrement plus riche que ce qui est présenté dans cet article. L'idée de ce tuto était de rapidement configurer un projet Symfony pour le déployer. Reste que dans une véritable application, vous aurez forcément besoin de personnaliser votre recette. Deployer a heureusement une documentation très bien faite et de nombreux paramètres configurables.

Dans le prochain article, nous nous rapprocherons des besoins d'une véritable application en configurant une base de données (et des migrations) et en utilisant Webpack Encore pour compiler nos assets, ce qui sera notre prétexte pour améliorer notre deploy.php et découvrir davantage cet outil.

Enfin, dans une dernière partie, nous servirons notre projet avec Nginx et php-fpm et verrons quelle est la configuration requise dans le cadre de notre processus de déploiement automatique.

Stay tuned !