Déployer Symfony sur Heroku : Intégration Continue

Pour les besoins de l’industrialisation de l’hébergement moderne d’un site internet, nous allons voir ici comment installer et déployer un site internet basé sur Symfony, dans un environnement Heroku, en utilisant les Pipeline.

Intégration continue et Pipeline Heroku

Commençons par définir tous les termes que nous allons utiliser :

L’intégration continue, c’est un processus, agile, permettant de gérer de manière souple, toutes les étapes de la mise en production d’un site internet. Le but du jeu est de se passer totalement de l’administration de serveurs, tout se passe dans le cloud, et automatiquement. Fini les « Pas de mise en production le vendredi », le concepte de mise en production disparaît.

La Pipeline d’Heroku permet de gérer 3 versions de son application : une version de développement (DEV), une version de démonstration (STAGING) et une version de production (PROD). Chaque version possède son propre environnement et ses variables d’environnement. Chaque version peu ensuite être déployée vers l’environnement suivant : en un clic, et quasiment instantannément, Heroku va passer l’application de l’environnement DEV vers l’environnement STAGING, puis de l’environnement STAGING vers l’environnement PROD, tout en gardant, à chaque fois, les bonnes variables d’environnement. Chose très pratique, la version DEV de votre application est mise à jour automatiquement à chaque modification de la branche master de votre dépôt GIT.

Concrêtement, cela a un impacte sur l’intégralité de votre gestion de projet, et cela se traduit par le processus suivant :

  1. Votre Product Owner (ou client, ou chef de projet, cela dépent de votre organisation, mais nous l’appeleront PO) a un besoin, il créé alors un ticket.
  2. Le développeur prend en charge le ticket.
  3. Le développeur met à jour (git pull) le site internet sur sa machine locale.
  4. Le développeur met en oeuvre les modifications répondant au ticket.
  5. Le développeur enregistre et envoi ses modifications sur le dépôt git (git commit & git push).
  6. La version DEV sur Heroku se met alors automatiquement à jour.
  7. Le développeur valide ses modifications sur la version DEV du site.
  8. Le PO, depuis l’interface de la Pipeline Heroku, déploie la version DEV vers la version STAGING.
  9. Le PO valide les modifications effectuées sur la version STAGING, avec le client si besoins.
  10. Le PO déploie la version STAGING sur la version PROD.

Et voila votre cycle de mise en production de votre site internet. Cela peut se traduire par des dizaines de mise en prod par jour ! Ce qui vous permet d’être souple, agile et réactif.

La mise en place est assez simple.

Configuration

Symfony

Avant de configurer Symfony, il faut comprendre quelques principes de base. Maintenant que l’on travail dans le cloud (dans le « nuage » comme dit le gouvernement), il faut que notre application soit « scalable ». Cela veut-dire que celle-ci doit être déployable sur n’importe quel serveur, à n’importe quel moment, être immédiatement prête à l’emploi, et donc, pas conséquent, pouvoir utiliser la même application sur plusieurs machines en même temps. Cela implique une règle très simple, mais qui change tout : nous n’avons plus les droits d’écriture sur les serveurs. Ca veut tout simplement dire que nous ne pouvons sauvegarder/modifier/supprimer AUCUN fichier sur le serveur d’application.

Cela a plusieurs impacts :

  • Si votre application requiert l’envoi et la sauvegarde des fichiers de vos utilisateurs, il faut prévoir d’enregistrer son fichier quelque part ! Ca peut être en base de donnée (je vous conseille mon bundle fait pour l’occasion : Base64 Bundle. Un article est prévu tout spécialement pour lui), ou sur un serveur externe (Sur Amazon, ou accessible en FTP, etc …).
  • La gestion des logs ne doit pas se faire dans des fichiers, mais dans des streams, pris en charge par Heroku.
  • Les fichiers temporaires n’ont cependant pas besoin d’être gérés en externe. En effet, Heroku fait suffisament bien les choses pour que vos fichiers temporaires soient persistés correctement le temps de la session de votre utilisateur.
  • Les fichiers de cache de Symfony seront bel et bien inscrits sur le serveur. Mais ils seront forcément perdus à chaque déploiement. Ca tombe bien, c’est ce que l’on attend d’eux.

Concrètement maintenant, modifions le fichier app/config/config.yml pour envoyer les logs en stream

monolog:
    handlers:
        nested:
            type:  stream
            path:  "php://stderr"
            level: debug

Nous devons maitenant préciser à Symfony que si des variables d’environnement sont disponibles, alors il faut les importer comme configuration :

imports:
    - { resource: parameters.yml }
    - { resource: parameters.php }
    - { resource: security.yml }
    - { resource: services.yml }

Notez l’apparition du « parameters.php » que nous allons créer dans « app/config/parameters.php » :

<?php
$params = [
    'DATABASE_URL',
    'APP',
    'SYMFONY_ENV',
    'SECRET'
];

foreach ($params as $param) {
    if(isset($_ENV[$param])) {
        $container->setParameter(strtolower($param), $_ENV[$param]);
    }
}

Ensuite, nous allons configurer pour que Symfony se connecte à une base Postgres directement à l’aide d’une URL (vous verrez dans la configuration d’Heroku pourquoi).

doctrine:
    dbal:
        url: "%database_url%"

Enfin, nous allons étoffer un peu notre fichier parameters.yml.dist :

parameters:
    symfony_env: dev
    app: dev
    database_url: postgres://root@127.0.0.1/symfony
    secret: ThisTokenIsNotSoSecretChangeIt

Vous l’avez remarqué, nous passons des variables « database_host », « database_user », « database_password », etc, à une variable unique et générale : « database_url ». Cela revient au même, mais c’est compatible Heroku. Pour générer une URL depuis les anciens paramètres, il suffit de remplacer les différentes variables comme suit :

postgres://[database_user]:[database_password]@[database_host]/[database_name]

Pour que les modifications soient prises en compte sur votre machine locale, n’oubliez pas de mettre à jour votre projet avec composer. Cela regénèrera le fichier parameters.yml avec les nouvelles variables du fichier parameters.yml.dist. Nous allons d’ailleurs devoir configurer Composer dans la prochaine partie pour que celui-ci sache comment générer ce fichier automatiquement sur Heroku.

Enfin, il faut créer deux fichiers, spécifiques à Heroku :

Le premier , situé à la racine de votre projet, est « Procfile », devant contenir :

web: composer warmup && $(composer config bin-dir)/heroku-php-apache2 web/

Ce fichier indique à Heroku que le projet nécessite de lancer un serveur web, en lançant la commande « composer warmup » (que nous verrons par la suite) et configurant apache pour le faire pointer vers le répertoire « web/ ».

Le second fichier, toujours à la racine, est « app.json » :

{
    "name": "Symfony",
    "description": "",
    "env": {
        "SECRET_TOKEN": {
            "description": "A secret key for verifying the integrity of signed cookies.",
            "generator": "secret"
        }
    }
}

Remplacer la variable « name » par le nom de votre site. Celui-ci permet d’indiquer à Heroku qu’il faut qu’il génère une variable d’environnement dymanique, soit « SECRET_TOKEN », grace à la méthode « secret » qui la remplacera alors simplement par une chaine de caractères aléatoires.

Composer

Maintenant, il faut modifier composer en deux endroits :

Rajouter les dépendances de Symfony pour Heroku :

"require": {
    "php": ">=7",
    "ext-intl": "*",
    ...
}

Ici, on demande à Composer d’inclure les dépendances PHP >= 7 et l’extension PHP Intl (pour l’internationalisation de Symfony).

Ensuite,  nous allons utiliser la directive « extra/incenteev-parameters » pour préciser à composer qu’il doit créer lui-même le fichier app/config/parameters.yml :

"extra": {
    "symfony-app-dir": "app",
    "symfony-bin-dir": "bin",
    "symfony-var-dir": "var",
    "symfony-web-dir": "web",
    "symfony-tests-dir": "tests",
    "symfony-assets-install": "relative",
    "incenteev-parameters": {
        "file": "app/config/parameters.yml",
        "env-map": {
            "database_url": "DATABASE_URL",
            "secret": "SECRET_TOKEN",
            "symfony_env": "SYMFONY_ENV",
            "app": "APP"
        }
    }
}

Maintenant, Composer est prêt à fonctionner sur votre machine locale, et sur tous les environnements de la Pipeline Heroku.

Heroku

Sur votre tableau de bord Heroku, commencez par créer une nouvelle application, placez-la en Europe (c’est mieux) et nommez la « [site]-dev » (chez moi, « tiloweb-symfony-dev »). Vous tombez alors sur la page de configuration de votre application.

Si ce n’est pas déjà fait, installez, sur votre ordinateur, Heroku CLI.

En ligne de commande, placez-vous dans le répertoire de Symfony puis connectez-vous à l’aide d’Heroku CLI :

$ heroku login

Puis liez le dépôt local à votre application Heroku :

heroku git:remote -a [App Name]

Enfin, nous allons demander à notre application de se mettre à jour à chaque fois qu’un push est émit sur la branche master du dépôt. Pour cela, toujours sur la page de configuration de votre application Heroku, sélectionnez « Github » dans « Deployment Method », puis dans « Connect To Github », recherchez le dépôt en question. Enfin, dans « Automatic deploys », cliquez sur « Enable Automatic deploys ».

Le déploiement de votre application est maintenant automatique. Mais nous devons encore configurer l’environnement de développement (DEV) et créer les environnement de démonstration (STAGING) et production (PROD).

Sur votre application, dans le tableau de bord d’Heroku, accédez à la partie « Settings ». Cliquez sur « Reveal config vars ». Puis renseignez les variables suivantes :

  • SYMFONY_ENV : « prod »
  • APP : « dev »

La variable d’environnement « SECRET_TOKEN » sera générée automatiquement grâce à notre fichier app.json. La variable « DATABASE_URL » va être créée automatiquement par Heroku en activant un plugin pour la base de donnée.

Pour se faire, allez dans l’onglet « Overview » de votre projet sur Heroku, puis sélectionnez « Configure Add-ons », puis « Find more Add-ons ». Vous arrivez sur le site d’Add-ons d’Heroku. Sélectionnez l’Add-Ons « Heroku Postgres », puis « install Heroku Postgres » (il se peut que vous ayez à vous logger avant ça). Le site vous demander alors de sélectionner votre application. Si vous retournez maintenant sur la liste des variables d’environnement de votre application, vous verez que la variable « DATABASE_URL » a automatiquement été ajoutée. Attention ! Ne la modifiez pas, car celle-ci est automatiquement gérée par Heroku. Si Heroku décide de changer l’URL de connexion à votre base de donnée, il remplacera automatiquement, lui-même, cette variable. Enfin, il faut déployer manuellement une première fois l’application, depuis l’onglet « Deploy », cliquez simplement sur le bouton « Deploy Branch » tout en bas de la page. Le déploiement est rapide, vous pouvez d’ailleurs voir les logs en direct.

Votre application DEV est maintenant configurée et déployée.

Nous allons maintenant créer nos deux autres applications :

Toujours dans le tableau de bord d’Heroku, créez une nouvelle application appelée « [site]-demo » (chez moi « tiloweb-symfony-demo »), toujours en Europe. Allez directement dans « Settings » pour modifier les variables d’environnement. Il vous suffit alors de régler ces variables :

  • SYMFONY_ENV : « prod »
  • APP : « demo »

Puis recommencez l’installation de l’add-on « Heroku Postgres » pour cette application. Terminez par le déploiement manuel de l’application DEMO depuis l’onglet « Deploy ».

Enfin, faites de même en créant l’application de production « [site]-prod » (chez moi « tiloweb-symfony-prod ») avec les variables d’environnement :

  • SYMFONY_ENV : « prod »
  • APP : « prod »

Vous 3 environnements sont maintenant créés et déployés. Nous pouvons alors créer la Pipeline.

Retournez dans votre tableau de bord, puis sélectionnez « New > Pipeline ». Renseignez le nom « [site] » (chez moi « tiloweb-symfony ») puis sélectionnez le dépôt github correpondant. Enfin, cliquez sur « Create Pipeline ». Vous arrivez sur l’interface de gestion de la pipeline. Sélectionnez « Add app » dans le tableau « STAGING » puis sélectionnez votre application de développement. Celle-ci est ainsi, par défaut ajoutée dans l’environnement « STAGING ». Déplacez-là en cliquant sur la flèche à droite du nom de l’application et en sélectionnant « move app to development ». Le nouveau tableau « Development » est créé. Vous pouvez alors, de la même manière, ajouter l’application DEMO dans l’environnement « STAGING » et l’application de production dans l’environnement « PROD ».

Dernière étape, il vous connecter à tous les environnements en bash, afin de lancer symfony en ligne de commande pour que celui-ci puisse créer sa base de donnée. La marche à suivre est simple, exécutez les 3 commandes suivantes depuis votre machine locale :

$ heroku run "bin/console doctrine:schema:update --force" --app tiloweb-symfony-dev
$ heroku run "bin/console doctrine:schema:update --force" --app tiloweb-symfony-demo
$ heroku run "bin/console doctrine:schema:update --force" --app tiloweb-symfony-prod

Vos trois environnements et leur base de données respectives sont maintenant créés et disponibles sur internet. Voyons voir comment le processus fonctionne maintenant.

Conclusion

La configuration, qui peut être compliquée à mettre en oeuvre la première fois, est terminée. Voyons comment cela fonctionne :

  • Vous effectuez une modification sur le dépôt en local.
  • Vous pushez les modifications sur le dépôt, sur la branch master.
  • Automatiquement, votre application se met à jour sur l’environnement de développement : DEV.
  • Il vous suffit, dans l’interface de la Pipeline, de cliquer sur « Promote to staging » pour copier l’application présente sur l’environnement DEV sur celui de démonstration STAGING.
  • Encore un clic sur « Promote to production » pour mettre en ligne, sur l’environnement de production, notre application mise à jour.

Votre processus d’intégration continue est maintenant en place et fonctionne parfaitement. Vous pouvez, à tout moment, revenir à n’importe quelle version de votre application. C’est maintenant votre chef de projet (ou Product Owner) qui a la main sur le processus de mise en ligne de toutes les modifications.

 

Enjoy !

Laisser un commentaire