Apparence
04. Architecture technique
La stack, les treize services qui la composent, les réseaux qui les séparent et les données qui survivent à un redémarrage.
L'inventaire des services avec leur image et leur rôle est en annexe A ; les versions installées sont dans Dépendances. Cette section dit comment ils s'articulent.
Vue d'ensemble
Le point d'entrée unique
Le service proxy (nginx) est le seul point d'entrée HTTP. Il publie le port 80 de l'hôte — et le 443 quand la surcouche TLS est active — et aiguille par nom d'hôte, sur trois noms : FRONTEND_HOST vers le SPA, API_HOST vers l'API, qui y sert /api, /admin et /static, et DOCS_HOST vers le portail de documentation. Le troisième est le seul à porter une garde propre, et le § 05 dit laquelle et ce qu'elle vaut.
Décision : aucun service HTTP applicatif ne publie de port. Ajouter une route se fait dans le gabarit de configuration du proxy, jamais en exposant un conteneur. Cela donne un seul endroit où lire ce qui est joignable de l'extérieur, ce qui est la condition pour que le § 05 puisse énoncer une surface d'exposition.
SFTP est l'exception explicite à ce point d'entrée unique : SSH n'est pas un protocole HTTP et ne traverse pas nginx. Le service sftpgo publie donc son port SSH directement sur l'hôte. Son interface WebAdmin est liée uniquement à la boucle locale de l'hôte et s'administre par tunnel SSH (§ 06).
Les hôtes ne sont jamais codés en dur : ils viennent du fichier d'environnement (voir annexe B). En local, les noms en .localhost résolvent vers 127.0.0.1 sans toucher au fichier hosts.
Les services, un par un
Le service de bord
proxy— nginx, construit depuisinfra/nginx. Termine HTTP (et TLS quand il est actif), aiguille par nom d'hôte, sert la configuration produite par substitution de variables au démarrage. C'est le seul service présent sur les deux réseaux : il est la couture entre l'extérieur et le reste. Son arrêt rend toute la plateforme injoignable, sans perte de données.certbot— obtient et renouvelle le certificat Let's Encrypt. Il n'est démarré que par le profiltls; hors de ce profil il n'existe pas. Le § 06 décrit son fonctionnement et un piège d'exploitation qui lui est propre.
Les services applicatifs
frontend— le SPA. En développement, un serveur Vite avec rechargement à chaud ; en production, un build statique servi par nginx. L'URL de l'API étant compilée dans le bundle, ce service est reconstruit quand elle change (§ 03). Son arrêt rend l'application inutilisable mais laisse l'API et le back-office joignables.docs— le portail de documentation, c'est-à-dire ce document et ses voisins. Un conteneur construit en deux étapes : VitePress transforme les fichiers dedocs/en site statique, puis nginx le sert. Aucun Node à l'exécution — le générateur ne survit pas à la construction, comme pour le SPA. Il ne dépend d'aucun autre service, ne lit aucune donnée et n'écrit rien : son arrêt rend la documentation injoignable et n'a aucun autre effet.Décision : la documentation est déployée avec le code, pas à côté. Elle vit dans le dépôt, dans la même pull request que le changement qu'elle décrit (
AGENTS.mden fait une condition de sortie), et le même déploiement met les deux en ligne. Un portail hébergé ailleurs aurait demandé une seconde chaîne de publication, donc un second endroit où la documentation peut prendre du retard.backend— Django, DRF et le back-office, servis par Gunicorn. Applique les migrations à chaque démarrage de conteneur, ce qui fait qu'un déploiement n'a pas d'étape de migration séparée (§ 06). Sert aussi les fichiers statiques du back-office et de Swagger, par WhiteNoise, sans passer par un volume partagé avec le proxy. La durée de conservation du journal des écritures API vient deAUDIT_LOG_RETENTION_DAYS. En développement,ADMIN_MFA_BYPASSpermet de tester le back-office avec le mot de passe seul, mais uniquement lorsqueDJANGO_DEBUGest aussi actif ; le backend refuse de démarrer si ce double verrou n'est pas respecté. L'inventaire complet de la configuration reste en annexe B.worker— l'exécutant Celery. Construit depuis la même image quebackend: le code des tâches est le code de l'application, et deux images auraient divergé. Son arrêt n'empêche rien d'être consulté ni saisi ; les tâches s'accumulent dans la file et se rattrapent au redémarrage.beat— l'ordonnanceur Celery. Il ne fait que déposer les tâches à l'heure dite ; il n'en exécute aucune. Son arrêt suspend la synchronisation des jours fériés, l'import CEGI et la purge du journal d'audit, silencieusement — c'est le service dont l'absence est la plus difficile à remarquer, et le § 06 dit comment la voir.
Les services de données
db— MySQL 8.4. Toutes les données applicatives. Porte une sonde de santé, dont lebackenddépend au démarrage : sans elle, le conteneur applicatif démarrerait avant que la base accepte les connexions et échouerait sur ses migrations.La version mérite une note : le schéma fonctionnel indique « MySQL 8.7 », qui n'est pas une version publiée. La plateforme utilise la LTS courante.
redis— deux usages sur deux bases logiques. La base 0 porte le cache, les sessions et les compteurs de limitation de débit ; la base 1 porte la file des tâches Celery. Cette séparation est délibérée : un vidage du cache sur la base 0 emporterait les tâches en attente si elles y vivaient. Aucune donnée de la base 0 n'est durable ; son arrêt déconnecte les sessions.minio— stockage objet compatible S3 pour les fichiers joints. Ses identifiants servent aussi d'identifiants S3 au backend. Il publie deux ports sur l'hôte (l'API objet et sa console d'administration), ce qui est le seul écart à la règle du point d'entrée unique — le § 05 le traite comme tel.minio-init— conteneur éphémère qui crée le bucket au premier démarrage puis se termine. Lebackendattend sa terminaison réussie, pas sa santé : un service qui doit avoir fini une fois n'est pas un service qui tourne.sftpgo— serveur SFTP dédié aux dépôts CEGI. Sa base SQLite, ses clés hôte et les fichiers déposés vivent dans des volumes persistants. Il ne partage avec le backend et le worker que le réseautransfer; il ne peut pas joindre MySQL, Redis ou MinIO. Son arrêt suspend les nouveaux imports sans affecter les données déjà intégrées.
L'accès d'administration à la base
haproxy— relais TCP vers MySQL, publié sur le port 3306 de l'hôte et filtré par adresse source. MySQL lui-même n'est jamais publié.Décision : un filtre plutôt qu'une publication directe. Les administrateurs de base de données ont besoin de leurs propres outils, donc d'un accès au protocole MySQL. Publier
dbaurait exposé la base à tout ce qui atteint l'hôte ; le relais rejette toute connexion dont la source n'est pas dansALLOWED_DB_IPS, en TCP pur, sans interpréter le protocole. La liste par défaut couvre les plages privées et doit être restreinte en production (§ 05).
Les trois réseaux
| Réseau | Qui y est | Ce que cela garantit |
|---|---|---|
edge | proxy, frontend, certbot | Le point d'entrée et ce qui participe à le servir depuis l'extérieur |
internal | proxy, docs, backend, worker, beat, db, redis, minio, minio-init, haproxy | La base, le cache et le stockage ne sont pas atteignables depuis le réseau de bord |
transfer | sftpgo, backend, worker | Le serveur de fichiers ne peut joindre ni la base ni les autres services de données |
Le proxy relie edge à internal. Le backend et le worker relient le seul service SFTP au traitement applicatif. Un service de bord ne peut donc pas parler à la base directement.
C'est aussi ce qui explique la place de docs : le proxy étant sur les deux réseaux, un service qu'il est le seul à appeler n'a rien à gagner à être sur le réseau de bord.
Les données persistées
| Volume | Contenu | Enjeu |
|---|---|---|
mysql_data | Toutes les données applicatives | La sauvegarde du § 06 porte là-dessus |
minio_data | Les fichiers joints | Perdus si le volume est supprimé, non reconstructibles |
certbot_certs | Certificats et fichiers de renouvellement | Voir le piège du § 06 |
certbot_webroot | Espace du défi HTTP-01, partagé avec le proxy | Reconstructible |
sftpgo_data | Dépôts entrants et archives traitées ou rejetées | Source des reprises jusqu'à expiration de la conservation |
sftpgo_config | Base SQLite, comptes et clés hôte SFTPGo | Perdre la clé hôte bloque la vérification épinglée du connecteur |
Tout le reste est éphémère. Un docker compose down -v détruit les six.
Les deux surcouches Compose
Le fichier de base décrit la plateforme. Deux surcouches le modifient, et aucune des deux n'ajoute de service :
docker-compose.override.yml— le développement. Compose la fusionne automatiquement, doncmake upest un environnement de développement : serveur Vite au lieu du build statique, code monté depuis l'hôte, rechargement à chaud du backend et des deux services Celery. C'est aussi ce qui explique une contrainte citée au § 03 : seul./backendest monté dans le conteneur applicatif.docker-compose.tls.yml— la terminaison TLS, en option. Publie le port 443 et va de pair avec le profiltlsqui démarrecertbot(make up-tls).
Un déploiement de production doit donc écarter explicitement la surcouche de développement — Compose la fusionnerait sinon, et le proxy chercherait un build statique là où tourne un serveur Vite. Le § 06 dit comment.
Ce qui tient cette section à jour
make docs-check vérifie que chaque service de docker-compose.yml est nommé ici. Ajouter un service à la stack sans écrire ce qu'il fait, ce dont il dépend et ce que son arrêt provoque fait échouer la construction. La vérification lit le fichier de base, celui que décrit l'annexe A ; les surcouches n'en déclarent aucun.