Passer de frontend à backend - le déploiement

Passer de frontend à backend - le déploiement

Alexandre P. dans Dev - Le 16-07-2022

Un des grands oubliés d'un développeur fullstack, c'est de pouvoir déployer. Très souvent, on vous dira qu'être un développeur fullstack ne signifie pas devoir se charger du déploiement et qu'il s'agit d'une compétence SysAdmin ou Ops. Cependant, lorsque vous faîtes vous même votre projet de A à Z, il faudra bien le déployer !

Pourquoi parler du déploiement de son code ? 🤔

Les développeurs ont trop tendance à mettre de côté cette compétence clé pour la création d'un produit (web, application, etc...). Lorsque vous travaillez des semaines, des mois sur quelque chose, pour que tout cela ait un sens, il faudra déployer à un moment où un autre.

Soyez sûr qu'à ce moment là, on ne parle pas de faire un npm dev/yarn dev dans sa console en pensant que ça va régler le problème. Le déploiement n'a rien à voir avec le fait de faire tourner du code sur sa machine pendant les développements.

Premièrement ces scripts font beaucoup de choses automatiques pour vous, comme le Hot-Module-Reload (HMR), la compilation du code pendant la modification pour avoir une page web "live" avec votre service. Sachez que c'est une grosse erreur de lancer sa production en mode dev, car le HMR ne compresse pas le code source pour rendre les stack et debug lisibles. Cela signifie que vous êtes en train de livrer des sources plus lourdes et plus longues à charger pour vos utilisateurs... 😕

Mais aussi le lancement de votre serveur en mode dev affiche énormément d'informations, que vous ne voulez pas forcément afficher à vos utilisateurs. Parmi ces informations, vous retrouverez les logs d'erreurs, les stack trace en cas de bug, peut être même l'affichage en clair de log d'informations contenants des token etc... Bref beaucoup de mauvaises pratiques pour une production. Faire une vraie "MEP" comme on dit dans le jargon (pour mise en production), c'est un travail.

Cette compétence n'est pas simple, elle requiert :

  • de la compréhension : qu'est-ce que vous déployez,
  • de la vigilance : savoir mettre en place du monitoring,
  • du savoir faire : maîtriser son système d'exploitation, les versions, les compatibilités ou conflits
  • de la veille : se tenir informé des failles, de l'évolution des packages

Anticiper le déploiement ♟️

Lorsque vous codez, vous devez aussi anticiper sur cette étape ultime de votre création, la mise en production. Et le fait d'y penser d'avance se traduit par le fait d'intégrer au niveau du code plusieurs éléments qui dissocie d'avance la partie de code qui s'exécute pendant les tests et la partie de code qui s'exécute uniquement en production.

Bien évidemment cela n'est pas toujours le cas. Il n'y a aucune obligation à exclure une partie du code de votre environnement de développement, mais cela arrive souvent. Par ailleurs, pour gérer de manière plus efficace les environnements, nous utilisons souvent un fichier d'environnement au niveau de la racine de votre projet. Ce fichier s'appelle par convention ".env" et les paquets comme dotenv nous permet de manipuler vos environnements au niveau du code plus facilement.

Dans ce fichier .env, on va retrouver de manière générale :

  • la "connection string" vers la base de données
  • les clés API utilisés dans le projet
  • etc...

Il s'agit d'une simple association clé/valeur sous cette forme :

DATABASE=mysql://user:pass@host:port/dbname
API_KEY_A=wIenv_0nw9418QnqzlRIciap_@
API_KEY_B=W34WnfiroVJrizerO95ç0_JVnernazo

Et pour les utiliser au niveau du code après avoir importé votre librairie dotenv, vous pourrez tout simplement faire :

const pg = require('knex')({
  client: 'pg',
  connection: process.env.DATABASE,
  searchPath: ['knex', 'public'],
});

const apiA = InitApiA(process.env.API_KEY_A);

// ....

⚠️ Mais du coup, puisque vous intégrez des clés sensibles à votre fichire .env, il convient de ne pas le versionner sur vos repository. Pensez à ajouter une ligne dans votre .gitingore afin de ne pas l'ajouter à vos commits.

En général ce que je fais, c'est que je laisse un fichier de plus que je nomme .env.sample dans lequel je laisse une liste des clés sans valeurs de ce que j'ai besoin d'initialiser dans mon environnement. (Juste une sorte de rappel).

DATABASE=
API_KEY_A=
API_KEY_B=

Effectuer le déploiement 🚀

Pour ce qui est du déploiement de votre projet, tout dépend de la direction que vous aviez pris au moment de la conception de votre solution.

Est-ce que vous avez fait le choix de faire du développement traditionnel ou une solution serverless ?

Ce que j'entends par solution serverless, c'est une solution qui repose essentiellement sur des services managés (SaaS), en gros du full cloud. C'est à dire que le provider s'occupe de la mise à disposition du service, de la montée en version, de l'hébergement et du monitoring. On en avait parlé pour les bases de données. Il en est de même pour la partie code.

Avez-vous fait le choix d'un framework Node ou PHP traditionnel ou avez vous fait le choix d'un service de cloud functions ?

C'est à dire que vous créez des morceaux de codes qui vont être exécutés à des moments précis :

  • Lors de l'appel d'une route HTTP comme c'est le cas pour Google cloud functions ou Amazon lambda
  • Lors d'événements spécifiques (création de fichier sur un espace de stockage cloud, appel en cascade après une cloud function, etc...)

Je n'ai pas de préférence particulière au niveau des services de cloud functions, j'ai testé les deux providers et j'aime beaucoup les deux. Je dirais juste qu'Amazon a décliné un peu plus ses outils, ce qui permet plus de souplesse, si vous optez pour la mise en place d'une solution cloud Amazon.

Ainsi, je pense que les deux solutions peuvent convenir à vos besoins si vous décidez de passer sur du serverless pour ne pas vous embêter avec le maintient d'un serveur et surtout de ses différents services (le serveur HTTP, l'instance de votre serveur de code, le serveur de base de données, le serveur de cache).

Si vous passez sur une solution serverless, le déploiement est assez cadré. Vous ne risquez pas vraiment de vous perdre, car les procédures vous guident pas à pas. De plus, vous avez aussi des framework Node.js tel que Serverless Framework qui est vraiment pas mal pour faire votre déploiement Amazon Lambda sans trop vous casser la tête. Le framework est très bien documenté et est open-source.

Vous avez aussi d'autres services managés tels que Vercel pour Next.js qui va gérer toute la partie déploiement beaucoup plus facilement pour vous lorsque vous l'aurez associé à Github.

Le seul petit bémol pour les solutions managés, c'est le prix.

⚠️ Il va falloir passer à la caisse, autrement dit tout le temps que vous ne passerez pas à maintenir vous même vos serveurs, vous allez le payer et forcément, le prix est un peu plus élevé qu'un service que vous maintenez vous-même.

Pour vous donner un ordre d'idée, j'ai un projet assez basique qui tourne sur AWS depuis quelques années avec une stack : API Gateway, Lambda Node.js, RDS PostgreSQL. J'utilise le serverless pour cette application mobile qui me coûte en moyenne 40 € /mois en SaaS, donc le coût, n'est pas négligeable.


D'un autre côté, vous pouvez opter pour une solution où vous allez vous même tout mettre en oeuvre. Elle vous demandera un peu plus d'efforts, de temps, de compréhension, mais au final, ce n'est pas plus mal non ? Non seulement, on a la maîtrise totale de ce que l'on fait, on apprend, mais en plus, cela nous fait faire des économies.

Avant d'entrer dans le détail des modes de déploiement, il faut savoir qu'en fonction des machines pour lesquelles vous optez, vous allez devoir faire les choses différemment. A l'époque, la plupart des serveurs étaient des serveurs PHP et ne proposaient pas beaucoup d'alternatives :

  • Les serveurs mutualisés : plusieurs clients se partagent une ressource machine, en sachant que l'on n'a pas besoin d'avoir une puissance de calcule énorme pour tous les types de services ou de sites.
  • Les serveurs dédiés : disposer de la puissance de toute la machine rien que pour vos sites ou services.

Tout deux avec tout de même des limitations au niveau du réseau qu'il faudra finalement se partager depuis l'hébergeur, mais pas de panique, ces derniers disposent de connexion qu'un particulier de rêve pas d'avoir chez lui, donc au niveau des limites, on est très loin.

Aujourd'hui avec d'autres langages de programmation comme Node.js ou même un peu avant Node avec Ruby on Rails, on voit de plus en plus des serveurs privés virtuels (VPS). On va dire qu'il s'agit d'un mi-chemin entre le dédié et le mutualisé. Il s'agit de mutualiser les ressources machines mais, au niveau des services eux mêmes, chacun dispose de son service dédié, voire même d'une connexion SSH vers la machine.

Un serveur dédié ou un VPS vous donne tout deux un accès SSH vers la machine. Vous pourrez vous connecter via votre terminal et y effectuer toutes les opérations souhaités (installations, configurations, etc...).

En revanche cela demande de s'y connaitre un peu en serveur linux. Etant donné qu'il s'agit d'une machine, vous avez aussi le système d'exploitation à gérer. Très souvent vous serez sous linux, mais pour la distribution, vous devriez avoir le choix au moment de souscrire à la formule. Pour vous donner un ordre de grandeur, les VPS sont accessible avec des offres qui coutent environ 10€ / mois en moyenne.

Il y a beaucoup d'hébergeurs entre OVH, Scaleway, PulseHeberg, Gandi, etc. Je pense tout de même que le meilleur rapport qualité/prix est PulseHeberg. Certes, le prix ne fait pas tout, mais au niveau du service c'est à dire la machine en elle même ainsi que la connexion, je suis satisfait. Tout le reste, je le fais moi, alors pourquoi payer plus cher ? 😅

J'ai testé tous ces services de VPS sauf Gandi (un peu trop cher pour mon besoin). Pour info chez PulseHeberg, je me retrouve donc avec 2 vCore (vCore pour virtual core, environ 50% du temps machine d'un core standard), 2go de ram (ce n'est pas beaucoup), 30go de SSD (c'est largement suffisant pour ce que j'en fait) pour 4 € / mois. 🤠

Les différents modes de déploiement 🧐

A l'époque avec les serveurs mutualisés, les déploiements se faisaient encore via FTP. Il fallait envoyer fichier par fichier les sites et applications, via le protocole de File Transfert... Une méthode un peu archaïque à ce jour.

Mais cette époque est révolue. Depuis que l'on donne aux utilisateurs de plus en plus d'accès aux ressources machines, que ce soit sur les serveurs dédiés ou les VPS.

Puisque vous pouvez décider de ce que vous installez sur le serveur, au delà du langage de programmation, vous pouvez très bien mettre en place des outils de déploiement.

Directement sur la machine 🚢

Si on décide de déployer notre serveur directement sur la machine. Ce n'est pas l'idéal car si l'on change de serveur, il faut tout refaire, mais cela reste une option. Dans l'idéal je recommanderai d'avoir des scripts de déploiements qui ne sont pas liés à la machine.

Je préfère vous prévenir, peu importe la méthode que vous emploierez à terme, il est fort probable et recommandé de commencer par tout faire à la main (on va taper chaque commande nous même).

On va se connecter sur le serveur et faire chaque étapes les unes après les autres :

  • installation des paquets systèmes et dépendances
  • pull du projet
  • configuration de l'env, les clés, etc...
  • création du service sur systemctl (fortement recommandé !), d'autres personnes utilisent PM2 pour les projets Node
  • lancement des services

Créez un fichier script sur le côté pour copier/coller les commandes à chaque étape de votre configuration serveur. En faisant cela, vous êtes en train de créer le script de déploiement. Il convient de grouper ensuite les parties de script afin d'isoler chaque étape de déploiement. En calquant la liste vue précédemment.

Sur des containers 🚚

Voici une autre approche qui consiste à déployer le serveur via des container Docker. Pour ceux qui ne connaissent pas du tout Docker , je vous conseille de faire quelques recherches sur le sujet car cela en vaut la peine.

⚠️ Attention pour cette partie, sachez que cela ne fonctionne pas avec tous les VPS (qui sont des container ou des VM), Docker ayant besoin de certains jeux instructions et autorisations... Pour les serveurs dédiés, vous pouvez y aller sans problèmes !

Docker vous permet de livrer votre code sous forme de briques en fonction de vos besoins. C'est-à-dire que si vous avez besoin d'un serveur web, vous pouvez mettre un container HTTP (Apache ou Nginx), un container base de données (MySQL, PostgreSQL ou Mongo), un autre container Node v.XX (avec un mapping vers le dossier de code source afin que Node puisse interprêter votre code).

Dans ce cas, votre code source sera prêt à bouger d'une machine à l'autre très facilement. De plus, les containers eux-mêmes peuvent être déployés en groupe via des outils comme Docker-Compose .

Automatiser ses déploiements 🤖

Aujourd'hui on a des outils comme Jenkins qui sert à gérer et orchestrer ce qu'il se passe sur votre serveur. Jenkins vous offrira une interface sur laquelle créer vos workflow. Remarquez que ce service aussi peut être déployé via un container Docker, si vous souhaitez gagner du temps.

Par exemple :

  • Un workflow déploiement qui appelle chacun des scripts vu ci-dessus.
  • Un autre workflow mise à jour qui n'appelle qu'une partie des scripts pour mettre à jour le code sources et les dépendances puis relancer les services

Jenkins distribue également beaucoup de plugins pour ajouter des fonctionnalités, comme : appeller certains scripts, envoyer des notifications, etc...

De plus Jenkins est un serveur web, celà implique qu'il est possible de mettre en place des endpoints qui vont déclencher des workflows. Cela vous permet entre-autre de mettre en place des webhooks !

Concrètement, les webhooks sont des URLs appelées par certains services comme Github (mais pas que) qui permettent de faire suite à des événements spécifiques au service. Dans notre cas on pourrait mettre très rapidement en place notre CI/CD : Continuous Integration, Continuous Delivery.

Autrement dit, on peut tout simplement, depuis Github demander à Jenkins de déployer notre code sur le serveur en fonction de certains événements (comme les push sur la branche master).

Sécurisez vos déploiements 🔒

Jenkins est totalement exposé au web depuis le port que vous aurez choisi, il convient de mettre un peu de sécurité en place pour éviter le pire.

Essayez de mettre en place un moyen d'authentification (au moins un Basic Token) sur vos webhook.

Pour vos projets gitbub en repository privés, je vous recommande fortement, l'utilisation de clés de déploiement afin de ne jamais exposer vos identifiants / mot de passe.

Sur vos workflow, mettez toujours des étapes de tests, comme le lancement de vos Tests Unitaires. Et si les tests sont au rouge, arrêtez le déploiement, pour d'éviter de casser votre production.

Mettre en place un fail2ban afin de limiter la casse au niveau des tentative de brutforce par les bots.

Mettre en place un ufw firewall avec des règles de qu'est-ce que l'on ouvre ou pas comme ports (attention au port SSH 22, vous risquez de perdre totalement la connexion vers votre serveur si vous vous y prenez mal).

En général je désactive totalement les connexions SSH qui ne sont pas en authorized_keys et je whiteliste uniquement ma clé publique (avec backup des clés sur USB au cas où).

Voici quelques lignes de ma config ssh :

    PasswordAuthentication no
    PubkeyAuthentication yes
    UsePAM no
    MaxAuthTries 2

Surveiller son serveur 📈

La dernière étape une fois que votre site est en ligne, consiste à voir ce qu'il s'y passe. Pour cela, il faut mettre en place des logs. Sans chercher à faire trop compliqué j'ai tendance à demander à mes services de rediriger tout sur /var/log/syslog puis je me mets en écoute dessus en cas de besoin.

Si vous voulez aller plus loin dans les logs, vous avez des outils comme Sentry et Dynatrace. Qui permettront notamment de vérifier la performance de vos applications, en matière de délais.

Pour aller plus loin 🔍

C'est un vaste sujet que je continue d'étudier chaque jour, le déploiement et l'administration des machines est vraiment un domaine passionnant, plein de challenge (lorsqu'il faut faire avec de toutes petites ressources, réussir à trouver des optimisations, des hacks ou encore lorsque vous avez des distributions linux exotiques... c'est du vécu ! 😂).

Tout ce que l'on a vu ici ne sont que des approches. Il ne tient qu'à vous de les challenger, de les améliorer, de faire autrement, mais je vous invite à mettre en place le plus d'automatisation.

Un déploiement maîtrisé, c'est beaucoup plus de sérénité pour les développeurs car on sait que l'on a la capacité de rollback rapidement en cas de problèmes.

On peut aller encore beaucoup plus loin dans l'automatisation de ses déploiements via des outils comme Terraform . Cela nécessite un peu de pratique et de la formation, mais comme à peu près tout, il faut bien commencer quelque part. 😅

Et comme j'aime souvent le dire : le rythme de déploiement de votre projet est un peu le rythme cardiaque de votre projet.

#backend#frontend#conseil#développement#deployment#cicd#linux#docker#server

user picture
Alexandre P.

Développeur passionné depuis plus de 20 ans, j'ai une appétence particulière pour les défis techniques et changer de technologie ne me fait pas froid aux yeux.


Nous utilisons des cookies sur ce site pour améliorer votre expérience d'utilisateur.