← retour à l'accueil
root@souverainete:~$ cat etude-de-cas/grav.md
étude de cas — stack: grav cms

Un socle réutilisable pour déployer et maintenir plusieurs sites Grav

Plutôt que d'automatiser l'installation d'un site unique, une architecture séparant runtime, applications, données persistantes et mécanisme de déploiement — pensée pour maîtriser le cycle de vie de plusieurs sites Grav sans dupliquer leur exploitation.

Type de projetSocle de déploiement réutilisable
Point de départDocumentation interne sous Grav
Contrainte initialePréserver le contenu lors des redéploiements
StackLinux · Ansible · Docker · Grav · Git
// contexte

Le problème a commencé par la persistance

Le premier besoin était relativement simple : automatiser le déploiement d'un site Grav utilisé comme documentation interne.

Mais ce site devait continuer à évoluer après son déploiement. Des pages seraient modifiées depuis l'interface d'administration, des images ajoutées, des comptes créés.

Un redéploiement de l'application ne devait donc jamais remettre le site dans son état initial et détruire les données produites en exploitation.

Une première frontière est apparue :

L'application doit pouvoir être remplacée. Les données utilisateur doivent survivre.

Le contenu persistant a donc été séparé du cycle de vie du conteneur.

Puis d'autres projets ont eu besoin de sites Grav. La question n'était alors plus : Comment déployer ce site ? mais :

Comment disposer d'un mécanisme permettant de déployer et maintenir plusieurs sites Grav sans dupliquer la logique d'exploitation ?

C'est à ce moment qu'un problème de déploiement est devenu un problème d'architecture.

// enjeux

Ce qu'il fallait concilier

Persistance

Le contenu créé en exploitation doit survivre au remplacement d'un conteneur, à un redéploiement et à un changement de version.

Réutilisabilité

La mécanique commune ne doit pas être copiée et adaptée pour chaque nouveau projet.

Maintenabilité

Runtime, application, données et déploiement n'évoluent ni au même rythme ni pour les mêmes raisons. Leur séparation doit refléter ces cycles de vie.

Réversibilité

Revenir à une version précédente doit utiliser autant que possible le même mécanisme qu'un déploiement normal.

Sécurité

Les secrets et configurations sensibles restent hors des images applicatives et du code versionné.

// architecture

Des cycles de vie différents, des responsabilités séparées

L'analyse du premier déploiement puis l'arrivée de nouveaux projets ont fait apparaître quatre domaines distincts : runtime, application / site, données persistantes et mécanisme de déploiement. Les regrouper simplement parce qu'ils participent au même site aurait créé un couplage inutile. L'architecture cherche donc à rendre ces frontières explicites.

// grav-runtime (base commune) → applications indépendantes → ansible-role-grav-site (déploiement mutualisé) → instances → données découplées du conteneur
Un runtime commun

grav-runtime fournit la fondation technique commune : Grav, PHP, Nginx et le contrat attendu par les applications. Il ne connaît aucun projet métier particulier.

Des applications indépendantes

projet-gites, projet-lavallee-website et les futurs sites ajoutent uniquement ce qui leur est propre : thème, plugins, configuration applicative et contenu initial. Chaque application reste versionnée indépendamment.

Un mécanisme de déploiement mutualisé

ansible-role-grav-site centralise la mécanique commune : préparation de l'instance, volumes persistants, configuration, secrets, démarrage, contrôles de santé, mise à jour et rollback. Le rôle reste orienté vers une instance par invocation.

Des données hors du cycle de vie du conteneur

Pages, images, comptes et autres données persistantes vivent indépendamment de l'image applicative. Une nouvelle version peut donc remplacer l'application sans réinitialiser automatiquement son état de production.

// mise en œuvre

De l'installation au cycle de vie

01

Premier besoin : rendre les données persistantes

Le premier déploiement a permis de formaliser une règle fondamentale : les éléments reconstruisibles appartiennent à l'application ; les données produites en exploitation doivent vivre en dehors du conteneur.

02

Extraction d'un runtime commun

Grav, PHP, Nginx et les dépendances communes ont été isolés dans grav-runtime. Les projets applicatifs n'ont ainsi plus à reconstruire cette couche technique.

03

Centralisation du déploiement

La mécanique d'exploitation a été regroupée dans ansible-role-grav-site : volumes, secrets, configuration, healthchecks, version déployée, update et rollback.

04

Passage à plusieurs applications

projet-gites, puis lavallee.tech, ont permis de confronter le modèle à plusieurs applications réelles. Le deuxième site a notamment exposé les hypothèses encore liées au premier projet — noms, chemins ou propriétés d'instance — et déclenché leur généralisation.

// cycle de vie

Installer n'est que la première opération

Une application n'est installée qu'une fois. Elle doit ensuite pouvoir être exploitée pendant des années. Le modèle recherché n'est donc plus :

install

mais :

deploy → update → rollback → migrate

Cette différence structure l'architecture. Le runtime est versionné. Chaque application est versionnée. Les données persistent indépendamment. Le mécanisme de déploiement applique l'état souhaité.

// rollback

Le rollback reste un déploiement

Le rollback n'est pas conçu comme une procédure d'urgence indépendante. Si une nouvelle version pose problème, une version précédente connue comme stable redevient simplement la version souhaitée.

version 1.3.2
      │
      ▼
 deploy 1.4.0
      │
   problème
      │
      ▼
 target = 1.3.2
      │
      ▼
même mécanisme de déploiement

Cela limite les procédures spéciales précisément au moment où elles seraient les plus risquées : pendant un incident.

// résultat

Ce que cette architecture change

La logique de déploiement est centralisée au lieu d'être recopiée dans chaque projet. Chaque site conserve son propre contenu, sa configuration et son cycle de versionnement — et le remplacement d'une application n'implique jamais le remplacement de son état persistant.

1runtime commun, construit et maintenu indépendamment des sites
1mécanisme de déploiement, au lieu d'être recopié par projet
2applications indépendantes déployées sur le même socle

Le premier site a résolu un besoin. Le deuxième a commencé à tester l'architecture. Les suivants doivent pouvoir réutiliser le même socle sans multiplier la logique d'exploitation.

// preuve

Le deuxième site est le véritable test

Il est facile de qualifier une architecture de « réutilisable » lorsqu'elle ne sert encore qu'un seul projet. Le deuxième consommateur révèle les hypothèses qui étaient en réalité spécifiques au premier.

lavallee.tech est désormais lui-même déployé sur cette architecture. Son arrivée a permis d'identifier les derniers paramètres d'instance qui doivent être généralisés pour que le rôle de déploiement reste un composant atomique et réutilisable.

La prochaine étape consiste à utiliser ce même mécanisme pour un nouveau site de documentation technique. La réutilisabilité n'est donc pas considérée comme une propriété déclarative.

Elle doit être vérifiée par de nouveaux consommateurs.

Nouveau site de documentation technique en préparation

Le même socle — grav-runtime + ansible-role-grav-site — sera réutilisé sans modification pour ce nouveau consommateur, seule véritable preuve qu'une architecture est réutilisable.

// souveraineté

Pourquoi cette architecture participe aussi à la maîtrise du système

L'utilisation de logiciels open source n'est qu'une partie du problème. Une infrastructure reste difficile à maîtriser si son déploiement dépend de manipulations manuelles, si ses données sont mélangées à l'application ou si personne ne sait précisément quelle version est en production.

Cette architecture cherche donc à rendre explicites :

  • les composants utilisés ;
  • les versions déployées ;
  • les données à préserver ;
  • les responsabilités de chaque couche ;
  • le mécanisme permettant de reconstruire une instance.
L'open source est un moyen. La maîtrise du système est l'objectif.
// limites

Ce que le socle ne cherche pas à faire

La création de contenu et le design éditorial restent propres à chaque application.

Le rôle de déploiement ne gère ni DNS, ni reverse proxy, ni certificats TLS. Ces responsabilités appartiennent à l'infrastructure partagée.

La sauvegarde reste nécessaire. Grav évite d'exploiter un service de base de données supplémentaire, mais les fichiers persistants constituent des données de production et doivent être sauvegardés.

Le rôle de déploiement gère une instance par invocation. L'orchestration de plusieurs sites est volontairement traitée au niveau supérieur.

Les applications nécessitant des fonctionnalités métier complexes, un trafic important ou des modèles de données avancés peuvent sortir du périmètre naturel d'un CMS flat-file comme Grav.

// composants

Le socle et ses applications

grav-runtime
Runtime partagé. Image de base versionnée fournissant Grav, PHP, Nginx et le contrat runtime commun.
Voir sur GitHub →
ansible-role-grav-site
Mécanisme de déploiement. Rôle Ansible responsable du cycle de vie d'une instance Grav compatible.
Voir sur GitHub →
projet-gites
Application. Premier site métier utilisant le socle partagé.
Voir sur GitHub →
projet-lavallee-website
Application. Deuxième site réel utilisant la même architecture — celui que vous consultez actuellement.
Voir sur GitHub →
// aller plus loin

Pourquoi cette architecture ?

Cette séparation n'est pas née d'un design théorique. Elle résulte de l'évolution d'un besoin concret : préserver les données d'un premier site, puis comprendre comment maintenir plusieurs applications sans dupliquer leur infrastructure.

Lire l'article : Du déploiement d'un site web à la conception d'une plateforme de déploiement réutilisable →

Un service Linux à rendre reproductible et maintenable ?

Un déploiement automatisé n'est qu'une partie du problème. La vraie question est de savoir comment le système sera mis à jour, diagnostiqué, sauvegardé, restauré et transmis dans la durée.

Parlons d'abord de vos contraintes →