diff --git a/content/fr/post/pragmatic-architecture-for-productions/index.md b/content/fr/post/pragmatic-architecture-for-productions/index.md index 8522d05..1213a44 100644 --- a/content/fr/post/pragmatic-architecture-for-productions/index.md +++ b/content/fr/post/pragmatic-architecture-for-productions/index.md @@ -2,197 +2,225 @@ title: L'architecture pragmatique de mes projets en production date: !!timestamp '2026-03-05 15:00:00' tags: +- hosting +- continuous integration - architecture -- web - infrastructure +- security --- Lorsqu'on lit certaines discussions entre développeurs ou architectes logiciels, on pourrait croire que la moindre application web nécessite -aujourd'hui une infrastructure distribuée, un cluster Kubernetes et +aujourd'hui une infrastructure distribuée, un environnement Kubernetes et plusieurs services cloud spécialisés. -Pourtant, de nombreux services web (y compris ceux qui accueillent -plusieurs milliers de visiteurs par jour) peuvent fonctionner -parfaitement avec une architecture beaucoup plus simple. +Pourtant, de nombreux services web, y compris ceux qui accueillent +plusieurs milliers de visiteurs par jour, peuvent fonctionner +aussi bien avec une architecture beaucoup plus simple. -Voici un retour d'expérience sur l'infrastructure que j'utilise pour +Voici un retour d'expérience sur l'infrastructure de mes projets en production, dont certains dépassent les 5000 visiteurs -quotidiens, et que j'ai également appliqué pendant des années lors +quotidiens. Je l'ai également appliquée pendant des années au profit d'une compétition de sécurité informatique avec plus de 250 -participants en présentiel. +participants en temps réel. -# Contexte +## Contexte -Pendant longtemps, j'ai hébergé l'ensemble de mes projets directement -chez moi. Mes sites web, mes services, ma forge Git et même mon +J'ai hébergé durant des années l'ensemble de mes projets directement +[à mon domicile]({{< relref "/post/self-hosting/index.md" >}}). Mes sites web, mes services, ma forge Git et même mon infrastructure d'intégration continue tournaient sur de petites -machines ARM (principalement des Pine64). +machines ARM : principalement des Pine64, [mais pas que]({{< relref path="/post/kernel_configs/index.md" lang="en" >}}). -Contrairement à ce que j'entends partout, cela fonctionnait très bien. +Contrairement à ce que je lis souvent, l'ensemble fonctionnait très bien. La principale raison pour laquelle j'ai arrêté n'est pas un problème de puissance de calcul ou de fiabilité, mais simplement mon passage à -un mode de vie plus nomade. Une connexion résidentielle stable et +un [mode de vie plus nomade]({{< relref "/post/china-for-digital-nomads/index.md" >}}). Une connexion résidentielle stable et permanente devient difficile à garantir lorsque l'on se déplace souvent. -J'ai donc déplacé la partie publique de mes services chez OVH, en -essayant de conserver la même philosophie : simplicité et pragmatisme. +Ma solution a consisté à déplacer la partie publique de mes services chez OVH, +en conservant la même philosophie : simplicité et pragmatisme. -# Une observation simple +## Une observation simple -Dans beaucoup de projets web modernes, l'architecture ressemble à -quelque chose comme ceci : +Beaucoup de projets web modernes adoptent une architecture semblable à +celle-ci : ``` -utilisateur → CDN → frontend → API → base de données +navigateur → CDN → frontend → API → base de données ``` -Chaque requête déclenche du calcul côté serveur, même lorsque le -contenu change très rarement. +Chaque requête déclenche du calcul côté serveur, alors même que le +contenu principal change très rarement. Cela réclamme de nombreuses +machines, implique parfois des prestataires, avec pour effet que si une brique +tombe en panne, le contenu ne peut plus être servi à l'utilisateur. -Dans mon cas, plusieurs de mes sites ont une caractéristique -importante : **le contenu principal change une fois par jour.** +De nombreux blogs, dont celui-ci, sont servis directement par un serveur web, +sans phase de génération ou mécanisme complexe de cache. La génération des +pages a lieu avant la publication : 1 fois pour toute. -Prenons par exemple le [jeu quotidien -Yakazu](https://yakazu-gratuit.fr/) : pour la majorité des visiteurs, -la seule chose qui compte est **la grille du jour**, qui ne change -qu'une fois par jour. +La très grande majorité des site web qui présentent principalement du contenu +pourraient être simplifié de la même manière : journaux en ligne, vitrines +d'entreprise, boutiques en ligne, ... + +J'édite par exemple un [jeu quotidien de Yakazu](https://yakazu-gratuit.fr/). +Pour la majorité des visiteurs, la seule chose qui compte est **la grille du +jour**. Or, ce contenu ne change qu'une fois par jour. Ainsi, générer la page +dynamiquement à chaque requête n'a pas beaucoup de sens. -Dans ces conditions, générer la page dynamiquement à chaque requête -n'a pas beaucoup de sens. # Architecture retenue -La solution est donc très simple : le site est entièrement statique. +La solution est donc très simple : rendre tout le site principalement statique. -Chaque jour, un événement déclenche la CI qui : +Chaque jour, un événement déclenche la reconstruction du site puis pousse les +nouveaux fichiers sur l'espace mis à disposition par l'hébergeur. -1. génère la nouvelle grille ; -2. reconstruit le site ; -3. publie les fichiers statiques. +Ces fichiers sont donc servis aux utilisateur directement, avec pour seul +intermédiaire l'hébergement statique inclus avec le nom de domaine chez OVH. -Ces fichiers sont ensuite servis directement par l'hébergement -statique fourni avec le nom de domaine chez OVH. +Oui cette offre gratuite de 100 MB qui vous semble microscopique et inutilisable +peut en réalité servir à héberger une boutique où les utilisateurs sont heureux +de revenir chaque jour. -Oui, l'offre gratuite de 100 MB. - -Cela donne donc une architecture très simple : - -``` -CI → génération du site → fichiers statiques → OVH -``` - -Tout le trafic est absorbé par l'infrastructure de l'hébergeur, ce -qui est exactement ce pour quoi elle est conçue. +Tout le trafic est absorbé par l'infrastructure de l'hébergeur, exactement ce +pour quoi elle est conçue. -# Frontend +## Génération des pages -Le site est construit avec SvelteKit. +Le site est construit avec [SvelteKit](https://kit.svelte.dev/). -Ce choix peut surprendre puisque je n'utilise pas du tout les -capacités serveur de ce framework. Mais il permet : +Ce choix peut surprendre puisque je n'utilise pas les capacités serveur de cet +outil. Mais il permet de : -- de générer facilement un site statique (`@sveltejs/adapter-static`) ; -- d'avoir un routage propre ; -- de structurer le code proprement ; -- de construire des Progressive Web Apps. +- générer facilement un site statique (`@sveltejs/adapter-static`) ; +- structurer le code ; +- avoir un routage propre ; +- construire des Progressive Web Apps. -Autrement dit : un framework moderne, mais sans dépendre d'un backend -permanent. -# Et quand il faut un backend ? +## Quand il faut une partie dynamique ? Certaines fonctionnalités nécessitent malgré tout un peu de logique -serveur. +côté serveur. Par exemple, les championnats organisés régulièrement doivent vérifier les participations et enregistrer les résultats et les chronos. -Dans ce cas, je démarre un petit serveur backend séparé, qui ne reçoit -qu'un nombre très limité de requêtes. +Ici, je démarre un petit serveur séparé, qui reçoit un nombre très +limité de requêtes. L'architecture devient alors : ``` -site statique → CORS → petit backend +navigateur → site statique + (CORS) → backend ``` -Ce backend est volontairement minimal et ne traite que les actions -qui ne peuvent pas être réalisées côté client. +Ce backend est volontairement minimal et traite seulement les actions +réellement indispensables. -Le point important est que **la majorité du trafic ne le touche -jamais**. +Bénéfice principal : **la majorité du trafic ne le touche jamais**. -# Résultat + +## Quid des comptes utilisateurs, des paiements ? + +Pourquoi une "connexion" à un compte utilisateur aurait obligatoirement besoin +d'une validation **systématique** par le serveur ? + +{{% card color="success" title="Arrêtons de mettre des bâtons dans les roues" %}} + +L'étape de création d'un compte utilisateur n'a bien souvent aucune justification : +lorsqu'un joueur veut acheter plus de grilles de Yakazu, il veut jouer, il ne +veut pas imaginer un nouveau mot de passe. + +Il n'y a aucune barrière technique qui empêche de donner accès à du contenu contre +un simple paiement. + +Si on profite du paiement pour receuillir une donnée personnelle identifiante lors +du paiement (email, numéro de téléphone, compte Apple ou Google pour Apple Pay ou +Google Pay, ...), cette même donnée personnelle pourra servir pour donner à nouveau +accès au contenu, cette fois après authentification (lien magique par exemple). + +{{% /card%}} + +Une seule requête d'API peut faire l'authentification : que ce soit +la validation d'un paiement ou d'une adresse email. Puis on +stocke cette réponse dans le navigateur pour l'utiliser dans +l'interface aussitôt ... ou plus tard ! Inutile d'interroger à nouveau +l'API pour une information déjà connue. + +D'une part, nous réduisons la charge du serveur. D'autre part nous accélérons +le chargement pour l'utilisateur qui voit ses données sans appel réseau, même +hors ligne. Tout le monde y gagne ! + + +## Résultat Avec cette architecture : - la quasi-totalité du trafic est servie sous forme de fichiers ; -- il n'y a quasiment pas de calcul côté serveur ; +- la puissance de calcul nécessaire côté serveur est ridicule ; - la surface de panne est très réduite. -Les problèmes que je rencontre sont presque toujours liés au pipeline +Les problèmes que je rencontre sont presque toujours liés au processus de génération : -- une image Docker qui n'est plus à jour ; -- un déclenchement CI qui échoue ; +- un déclenchement qui échoue ; +- une image Docker obsolète ; - un oubli dans la génération des données (l'absence de grille de jeu par exemple). Mais ces problèmes sont faciles à détecter et se corrigent généralement en quelques minutes. -# Pourquoi faire simple ? -Avec un peu de recul, je me rends compte que cette approche suit -quelques principes simples : +## Pourquoi faire simple ? + +Après plusieurs années d'expérience, je constate que cette approche suit +plusieurs règles apparemment simples : 1. **pré-calculer ce qui peut l'être** ; 2. **servir des fichiers plutôt que du calcul** ; -3. **réserver le backend aux cas réellement nécessaires**. +3. **réserver les calculs aux cas réellement nécessaires**. -Ces principes permettent souvent d'absorber une charge importante -avec des ressources très modestes. +Ces principes permettent d'absorber une charge importante avec des +ressources humaines ou logistiques modestes. -Pendant plus de dix ans, j'ai par exemple organisé un challenge de -sécurité informatique qui a fini par accueillir environ 300 -participants simultanés, avec des machines très simples. -Le secret n'était pas la puissance du matériel, mais la conception du -système. Je vous laisse visionner ma [présentation de cette +## Application à un service principalement dynamique + +Certains services reposent obligatoirement sur une phase de calculs ou de +génération côté serveur. Pas pour de mauvaises raisons, mais parce que le +contenu présenté dépend de facteurs qui dépassent le seul utilisateur. + +J'ai organisé pendant plus de dix ans un challenge de sécurité informatique +avec des machines très simples. Avec près de 300 participants simultanés les +dernières années, la conception d'une architecture qui tient la charge et +résiste aux attaques logicielles probables est un défi qui dépasse de loin ce +que la majorité des sites web pourront observer. + +Le secret n'était pas la puissance du matériel, mais la conception du système. +Regardez ma [présentation de cette infrastructure](https://youtube.com/watch?v=naFxBW5yoUA), avec les -tâtonnements, les erreurs et les contraintes qui l'ont façonné. +contraintes, mes tâtonnements, mes erreurs et les succès qui l'ont façonnée. -# Et les comptes utilisateurs, les paiements ? -Une "connexion" à un compte utilisateur n'a pas nécessairement besoin -d'une validation systématique par un backend (d'ailleurs la notion de -compte utilisateur n'a pas toujours de sens). +## Conclusion -Une seule requête d'API peut faire l'authentification (que ce soit -la validation d'un paiement ou d'une adresse email, ...) puis on -stocke cette réponse dans le navigateur pour en faire usage dans -l'interface : maintenant ... ou même plus tard. Comme ça, inutile de -refaire une requête à l'API pour une information que l'on a déjà. - -Non seulement cela réduit la charge du serveur, mais cela accroit -aussi la vitesse de chargement pour l'utilisateur qui voit ses données -sans appel réseau, et donc même hors ligne. Tout le monde est gagnant. - -# Conclusion - -L'infrastructure moderne propose de nombreux outils très puissants. +L'infrastructure moderne propose des outils puissants. Mais il est parfois utile de se rappeler que beaucoup de problèmes -peuvent être résolus de manière beaucoup plus simple. +peuvent être résolus de manière simple. -Avant d'ajouter une nouvelle couche technologique, il vaut souvent la -peine de se poser une question très simple : +Avant d'ajouter une nouvelle couche technologique, je vous encourage à vous poser la question : -**est-ce que ce contenu doit vraiment être généré à chaque requête ?** +**Ce contenu doit vraiment être généré à chaque requête ?** Dans bien des cas, la réponse est non. + +Prêtons attention à ne pas être quelqu’un qui construit une cuisine de restaurant 3 étoiles pour faire des pâtes. +**La complexité est souvent la solution paresseuse.**