Aller au contenu

Docker Compose

PerfShop est livré sous forme d'une stack Docker Compose composée de 31 services (30 documentés ici, plus un hub de jeux pédagogiques décrit dans une section dédiée). Ils sont tous attachés au même réseau bridge perfshop-network et organisés en groupes logiques.

Cette page est l'inventaire exhaustif de tous les services. Pour chaque groupe, on trouve d'abord un tableau synthétique, puis une sous-section détaillée pour les services qui ont des particularités méritant une explication (variables critiques, volumes, dépendances).

Source de vérité

Les informations de cette page proviennent des fichiers docker-compose.desktop.yml (Docker Desktop) et docker-compose.build.yml (Linux/VPS), qui ont strictement la même liste de services applicatifs. Toutes les images, ports, volumes, healthchecks et dépendances sont vérifiables dans ces fichiers.

Tableau récapitulatif

Groupe Service Image Port hôte (par défaut) Rôle court
Cœur perfshop-db mysql:8.0 19306 Base de données principale
Cœur perfshop-app perfshop-backend:v18 8080 + 9090 Backend Spring Boot
Cœur perfshop-frontend perfshop-frontend:v17 8090 Boutique React + nginx
Cœur perfshop-monitoring perfshop-monitoring:v4 3001 Dashboard temps réel Node
Cœur perfshop-admin perfshop-admin:v4 3004 Backoffice produits/commandes
Cœur perfshop-chaos-admin perfshop-chaos-admin:v8 3003 Pilotage des chaos
Cœur perfshop-welcome perfshop-welcome:v6 3011 Page d'accueil annuaire
Cœur docs squidfunk/mkdocs-material:latest 8087 Documentation MkDocs
Observabilité prometheus prom/prometheus:latest 9091 Métriques
Observabilité grafana grafana/grafana:12.0.0 3002 Dashboards et exploration
Observabilité perfshop-grafana-seed python:3.11-slim Init Grafana (one-shot)
Observabilité perfshop-loki grafana/loki:latest 19100 Stockage logs
Observabilité perfshop-promtail grafana/promtail:latest Collecte logs Docker → Loki
Observabilité perfshop-tempo grafana/tempo:2.4.2 19200 + 4317 + 4318 Stockage traces OTLP
Observabilité perfshop-pyroscope grafana/pyroscope:latest 4040 Profiling continu JVM
Observabilité perfshop-opensearch opensearchproject/opensearch:2.13.0 9201 Indexation full-text logs
Observabilité perfshop-opensearch-dashboards opensearchproject/opensearch-dashboards:2.13.0 5601 UI OpenSearch
Observabilité perfshop-vector timberio/vector:0.38.0-alpine Collecte logs Docker → OpenSearch
Observabilité perfshop-opensearch-seed python:3.11-slim Init index templates et dashboards (one-shot)
QA — JMeter perfshop-jmeter justb4/jmeter:5.5 Container JMeter permanent (idle)
QA — JMeter perfshop-jmeter-ui node:20-alpine (code monté) 3005 UI custom de pilotage JMeter
QA — Squash perfshop-squash-db postgres:16 5433 BDD Squash TM
QA — Squash perfshop-testmgmt squashtest/squash-tm:latest 8088 ALM Squash TM
QA — Squash perfshop-orchestrator squashtest/squash-orchestrator:latest Pilotage SSH des exécutions
QA — Squash perfshop-squash-seed python:3.11-slim Init projet Squash TM (one-shot)
QA — Test exec perfshop-selenium selenium/standalone-chrome:latest 4444 + 7900 Selenium Grid + noVNC
QA — Test exec perfshop-test-runner perfshop-test-runner:latest Robot Framework + pytest + SSH
QA — SCM perfshop-forgejo codeberg.org/forgejo/forgejo:14 3009 Git auto-hébergé
QA — SCM perfshop-forgejo-seed python:3.11-slim Init compte CI + dépôt + token (one-shot)
QA — Scripts perfshop-scripts-ui node:20-alpine (code monté) 3008 Éditeur/lanceur de scripts

Réseau et volumes

flowchart TB
  subgraph net["perfshop-network<br/>(bridge)"]
    direction LR
    core["Cœur<br/>(8 services)"]
    obs["Observabilité<br/>(11 services)"]
    qa["QA<br/>(11 services)"]
  end

  subgraph vol["Volumes nommés"]
    direction TB
    v1["mysql-data"]
    v2["prometheus-data"]
    v3["grafana-data"]
    v4["loki-data"]
    v5["tempo-data"]
    v6["pyroscope-data"]
    v7["squash-db-data"]
    v8["forgejo-data"]
    v9["forgejo-token-data"]
    v10["jmeter-ui-modules"]
    v11["scripts-ui-modules"]
    v12["opensearch-data"]
  end

  core --> v1
  obs --> v2
  obs --> v3
  obs --> v4
  obs --> v5
  obs --> v6
  obs --> v12
  qa --> v7
  qa --> v8
  qa --> v9
  qa --> v10
  qa --> v11

12 volumes nommés (les chiffres exacts varient légèrement entre desktop.yml et build.yml autour du volume mysql-data). Tous sont gérés par l'engine Docker — pas de bind mount sensible côté hôte, sauf pour les bind mounts de configuration en lecture seule (./prometheus/prometheus.yml, ./grafana/dashboards, ./loki/loki-config.yml, etc.) et pour les volumes partagés ./jmeter/{scenarios,scripts,results,plugins,logs} et ./test-runner/{scripts,logs}.

Groupe Cœur

perfshop-db — MySQL 8

  • Image officielle mysql:8.0, healthcheck mysqladmin ping (interval 10 s, timeout 5 s, 5 retries)
  • Variables : MYSQL_DATABASE=perfshop, MYSQL_USER=perfshop, MYSQL_PASSWORD=${DB_PASSWORD}, MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
  • Volume nommé mysql-data/var/lib/mysql
  • Limitation cpuset: "10" (affinité CPU démonstrative)
  • Logging JSON-file plafonné à 20 Mo × 3 fichiers

perfshop-app — Backend Spring Boot

C'est le service le plus complexe de la stack. Voir aussi auth.md, database.md, et la section Observabilité.

  • Image custom perfshop-backend:v18
  • Limitations : mem_limit: 1536m, mem_reservation: 512m, cpuset: "11"
  • Ports exposés : 8080 (API REST) et 9090 (port management Spring Boot Actuator)
  • Healthcheck : non, géré par dépendance ordonnée
  • Dépendances : perfshop-db (healthy), perfshop-tempo, perfshop-pyroscope

JAVA_OPTS — agents APM intégrés

L'image embarque deux agents Java qui sont activés via la variable JAVA_OPTS :

-Xms256m -Xmx1g -XX:MaxMetaspaceSize=128m

-javaagent:/agents/opentelemetry-javaagent.jar
-Dotel.service.name=perfshop
-Dotel.exporter.otlp.endpoint=http://perfshop-tempo:4317
-Dotel.exporter.otlp.protocol=grpc
-Dotel.traces.exporter=otlp
-Dotel.metrics.exporter=none
-Dotel.logs.exporter=none
-Dotel.instrumentation.http.capture-headers.server.request=X-Admin-Token,Content-Type
-Dotel.instrumentation.jdbc.captured-statements.enabled=true
-Dotel.span.attribute.count.limit=256

-javaagent:/agents/pyroscope.jar
-Dpyroscope.server.address=http://perfshop-pyroscope:4040
-Dpyroscope.application.name=perfshop
-Dpyroscope.format=jfr
-Dpyroscope.profiler.event=cpu
-Dpyroscope.profiler.alloc=512k
-Dpyroscope.profiler.lock=10ms
-Dpyroscope.profilingInterval=PT0.02S

Détails :

  • OpenTelemetry agent : exporte les traces OTLP gRPC vers Tempo (port 4317), désactive l'export des métriques et des logs (Prometheus et Loki sont les puits préférés), capture les headers X-Admin-Token et Content-Type côté serveur, et capture les statements JDBC. Voir observability/tempo.md.
  • Pyroscope agent : exporte les profils CPU au format JFR (Java Flight Recorder), avec sampling toutes les 20 ms (PT0.02S), profil d'allocation toutes les 512 Ko et profil de verrou pour les contentions ≥ 10 ms. Voir observability/pyroscope.md.

Variables d'environnement applicatives

Variable Rôle
SPRING_DATASOURCE_URL jdbc:mysql://perfshop-db:3306/perfshop?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
SPRING_DATASOURCE_USERNAME / _PASSWORD Compte applicatif perfshop
PERFSHOP_LANG fr ou en (sélectionne les migrations Flyway et les bundles i18n)
CORS_ALLOWED_ORIGINS Composé dynamiquement à partir de PUBLIC_FRONTEND_URL, PUBLIC_MONITORING_URL, PUBLIC_CHAOS_URL, PUBLIC_ADMIN_URL
SESSION_COOKIE_SECURE / _SAME_SITE Politique cookies (selon HTTP/HTTPS)
PERFSHOP_ADMIN_EMAIL / _PASSWORD Bootstrap du superadmin au premier démarrage
PERFSHOP_LICENSE_KEY Clé de licence (priorité sur la table perfshop_license)
PUBLIC_GAMES_URL URL externe du hub de jeux (utilisée uniquement dans le chaînage de fin de parcours)

Bind mount images produits

./frontend/public/images/products → /images-data/products

Le backend peut écrire des images uploadées via l'admin dans ce dossier ; le frontend nginx les sert directement depuis le volume partagé.

perfshop-frontend — Boutique React

  • Image custom perfshop-frontend:v17, basée sur nginx:alpine
  • Limitations : mem_limit: 256m, mem_reservation: 64m, cpuset: "1"
  • Bind mount ./frontend/public/images/usr/share/nginx/html/images (images partagées avec le backend)
  • Variables VITE_API_URL, VITE_MONITORING_URL, VITE_LANG injectées via le script env-inject.sh au démarrage du container (substitution sed dans les fichiers JS bundlés Vite)

perfshop-monitoring — Dashboard temps réel Node

  • Image custom perfshop-monitoring:v4
  • Bind mount ./monitoring/public/app/public (HTML/CSS/JS statiques)
  • Bind mount /var/run/docker.sock (read-only) : permet d'interroger l'API Docker pour récupérer les statistiques CPU/RAM/réseau de tous les containers
  • Polling de http://perfshop-app:9090/actuator/prometheus toutes les 2 secondes (POLL_INTERVAL=2000)
  • Expose /metrics au format Prometheus (job perfshop-docker côté Prometheus)
  • Voir observability/dashboard-html.md pour le détail

perfshop-admin et perfshop-chaos-admin

Ces deux services sont des bundles HTML/CSS/JS vanilla servis par nginx, avec un script env-inject-nginx.sh qui substitue les variables PUBLIC_* dans les fichiers HTML au démarrage. Ils n'ont aucune logique côté serveur — toute la logique métier est dans le backend Spring Boot, qu'ils consomment via REST.

perfshop-welcome

  • Image custom perfshop-welcome:v6
  • Mode dns ou ip selon WELCOME_MODE (la page liste les URLs accessibles en utilisant soit localhost/IP, soit les sous-domaines DNS configurés)
  • Reçoit toutes les variables PUBLIC_*_URL du .env pour générer son annuaire

docs — Documentation MkDocs

  • Image officielle squidfunk/mkdocs-material:latest
  • Bind mount ./mkdocs/docs
  • Commande : serve --dev-addr=0.0.0.0:8000
  • C'est ce service qui sert cette documentation

Groupe Observabilité

Voir Observabilité — Vue d'ensemble pour une analyse fonctionnelle. Cette sous-section donne uniquement les détails Docker.

prometheus

  • Volume nommé prometheus-data/prometheus
  • Bind mount ./prometheus/prometheus.yml/etc/prometheus/prometheus.yml
  • Commande explicite avec --storage.tsdb.retention.time=7d, --storage.tsdb.retention.size=5GB, --web.enable-remote-write-receiver, --web.enable-lifecycle
  • Détails dans observability/prometheus.md

grafana

  • Version pinned 12.0.0 (les autres images obs sont en latest, Grafana est figée pour la stabilité des dashboards)
  • Variables clés : GF_AUTH_ANONYMOUS_ENABLED=true, GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer, GF_PANELS_DISABLE_SANITIZE_HTML=true, GF_USERS_DEFAULT_LANGUAGE=${PERFSHOP_UI_LOCALE:-en-US}
  • Bind mounts : ./grafana/provisioning (datasources + dashboards.yml) et ./grafana/dashboards (10 JSON)
  • Healthcheck /api/health
  • Détails dans observability/grafana.md

perfshop-grafana-seed

  • Image python:3.11-slim, installe requests==2.31.0 au démarrage puis exécute /app/seed.py
  • restart: "no" (one-shot)
  • depends_on: grafana: condition: service_healthy
  • Rôle : poser l'ACL Admin-only sur le dossier Formateurs et configurer le dashboard home
  • Détails dans observability/grafana.md

perfshop-loki / perfshop-promtail

  • Loki en mode single-node (target: all), retention 168 h (7 jours), schéma TSDB v13
  • Promtail collecte via Docker SD socket, plus deux jobs static_configs pour jmeter.log et les logs Test Runner (/rf-logs/*.log)
  • Bind mounts Promtail : /var/run/docker.sock (RO), ./jmeter/logs (RO), ./test-runner/logs (RO)
  • Détails dans observability/loki.md

perfshop-tempo

  • Version pinned 2.4.2
  • 3 ports exposés : 19200 (HTTP query), 4317 (OTLP gRPC), 4318 (OTLP HTTP)
  • metrics_generator activé (service-graphs + span-metrics) avec remote_write vers Prometheus
  • Détails dans observability/tempo.md

perfshop-pyroscope

  • Backend filesystem /var/pyroscope/data
  • scrape_configs: [] (pas de scrape, mode push uniquement depuis l'agent Java)
  • Détails dans observability/pyroscope.md

perfshop-opensearch / _dashboards / _seed / vector

Une stack OpenSearch complète parallèle à Loki :

  • perfshop-opensearch : 2.13.0, single-node, security plugin désactivé, healthcheck /_cluster/health, ulimits memlock=-1 et nofile=65536
  • perfshop-opensearch-dashboards : 2.13.0, UI Kibana-compatible
  • perfshop-vector : collecte les logs Docker (socket monté) et les pousse dans des index perfshop-{service_family} après transform VRL
  • perfshop-opensearch-seed : crée 7 index templates (spring, nginx, mysql, jmeter, qa, forgejo, observability) et importe le dashboard perfshop-all-logs.ndjson
  • Détails dans observability/opensearch.md

Groupe QA

Voir Stack QA — Vue d'ensemble pour le workflow complet.

perfshop-jmeter — Container permanent

  • Image justb4/jmeter:5.5
  • Entrypoint particulier : /bin/sh -c "cp /plugins/*.jar /opt/apache-jmeter-5.5/lib/ext/ 2>/dev/null || true && echo '[JMeter] Plugins installés' && tail -f /dev/null"
  • Le container reste idle (tail -f /dev/null) en attendant qu'un tir soit lancé via docker exec. Les plugins (incluant le plugin Prometheus listener) sont copiés une seule fois au démarrage.
  • Bind mounts : ./jmeter/{scenarios,scripts,results,plugins,logs}
  • Heap : HEAP=-Xms256m -Xmx${JMETER_MAX_RAM:-1024}m -XX:MaxMetaspaceSize=128m
  • Détails dans qa/jmeter.md

perfshop-jmeter-ui

  • Base node:20-alpine, code source monté en volume
  • Commande : sh -c "npm install --omit=dev && node src/server.js"
  • node_modules persisté dans le volume nommé jmeter-ui-modules (évite la réinstallation à chaque redémarrage)
  • Bind mount /var/run/docker.sock : nécessaire pour exécuter docker exec perfshop-jmeter ... qui lance les tirs
  • Variables : JMETER_TARGET_INTERNAL, JMETER_TARGET_EXTERNAL, JMETER_PROMETHEUS_PORT=9270, PROMETHEUS_INTERNAL_URL=http://perfshop-prometheus:9090, JMETER_MAX_RAM, GRAFANA_URL
  • Détails dans qa/jmeter.md

perfshop-squash-db / perfshop-testmgmt

  • PostgreSQL 16 dédié à Squash TM (volontairement séparé de MySQL pour respecter la stack officielle Squash)
  • Squash TM utilise les bind mounts ./squash-seed/start-plugins.cfg et ./squash-seed/squash.tm.cfg.properties pour sa configuration
  • Variable critique : SQUASH_JWT_SECRET (secret base64 utilisé pour signer les tokens JWT acceptés par l'orchestrateur)
  • Healthcheck /squash/isSquashAlive
  • Détails dans qa/squash-tm.md

perfshop-orchestrator

  • Image officielle squashtest/squash-orchestrator:latest
  • 5 bind mounts de configuration : pools.yaml, sshee.yaml, arranger.yaml, squashtf.yaml, trusted_key.pub
  • Pilote Squash TM via les variables SQUASH_TM_URL, SQUASH_TM_USER, SQUASH_TM_PASSWORD
  • Détails dans qa/squash-orchestrator.md

perfshop-selenium

  • Image officielle selenium/standalone-chrome:latest
  • 2 ports : 4444 (Selenium WebDriver) et 7900 (noVNC pour debug visuel)
  • Variables : SE_NODE_MAX_SESSIONS=2, SE_VNC_NO_PASSWORD=1, SE_START_XVFB=true
  • shm_size: 2gb (Chrome a besoin de mémoire partagée importante pour éviter les crashes)
  • Détails dans qa/selenium.md

perfshop-test-runner

  • Image custom perfshop-test-runner:latest (build local sur le poste, pas pullable depuis un registry public)
  • Inclut OpenSSH server, Robot Framework 7.0, robotframework-seleniumlibrary 6.3.0, robotframework-requests 0.9.6, robotframework-jsonlibrary 0.5, pytest 8.0, selenium 4.18.1, allure-robotframework, squash-tf-services
  • Bind mounts : ./test-runner/scripts/scripts, ./test-runner/logs/rf-logs
  • Variables : SELENIUM_REMOTE_URL=http://perfshop-selenium:4444/wd/hub, PERFSHOP_FRONTEND_INTERNAL, PUBLIC_API_URL, PERFSHOP_LANG
  • Détails dans qa/test-runner.md

perfshop-forgejo / perfshop-forgejo-seed

  • Forgejo 14, base SQLite (/data/gitea/forgejo.db)
  • Variables critiques : FORGEJO__server__ROOT_URL, FORGEJO__database__DB_TYPE=sqlite3, FORGEJO__security__INSTALL_LOCK=true, GITEA_ADMIN_USERNAME / _PASSWORD / _EMAIL
  • Healthcheck via curl http://localhost:3000/api/v1/version
  • Le seed crée le compte CI, génère un token API stocké dans /token/forgejo_token (volume nommé forgejo-token-data partagé avec perfshop-scripts-ui), crée le dépôt perfshop-tests, et pousse les scripts initiaux
  • Détails dans qa/forgejo.md

perfshop-scripts-ui

  • Base node:20-alpine, code source monté en volume, identique à jmeter-ui
  • Bind mount /var/run/docker.sock (pour docker exec perfshop-test-runner)
  • Volume partagé ./test-runner/logs/rf-logs (lecture des sorties RF + écriture des « runs persistants »)
  • Volume nommé en lecture seule forgejo-token-data:/token:ro (lit le token Forgejo généré par le seed)
  • Variables : FORGEJO_INTERNAL_URL, FORGEJO_CI_USER, FORGEJO_REPO, FORGEJO_TOKEN_FILE=/token/forgejo_token, TEST_RUNNER_CONTAINER=perfshop-test-runner, SELENIUM_REMOTE_URL
  • Détails dans qa/scripts-ui.md

Hub de jeux pédagogiques

Le hub de jeux est embarqué dans la stack mais constitue une application autonome : pas de dépendance backend, pas d'accès DB, pas d'authentification serveur. C'est un bundle web statique servi par nginx, fondé sur Phaser 3.80 et Three.js 0.160, packagé avec Vite 5.

Le détail de l'architecture interne du hub (engine, scenes, composants Phaser, format des assets) sera couvert dans une page dédiée d'un lot futur. La présence de ce service dans le compose et sa documentation ne mentionnent jamais son URL publique, son port, ni son nom de service Docker — l'accès se fait uniquement via le chaînage de fin de parcours géré par le backend.

Ordre de démarrage et depends_on

Le graphe complet des dépendances est décrit dans deployment.md. Les points clés à retenir :

  • Les services healthcheckés (perfshop-db, grafana, perfshop-testmgmt, perfshop-squash-db, perfshop-forgejo, perfshop-opensearch) bloquent le démarrage de leurs consommateurs.
  • Les seeds (grafana-seed, squash-seed, forgejo-seed, opensearch-seed) attendent leurs cibles avec condition: service_healthy ou condition: service_completed_successfully.
  • Le perfshop-squash-seed attend explicitement la complétion réussie de perfshop-forgejo-seed avant de démarrer, car il a besoin du token CI Forgejo pour configurer le SCM Squash TM.

Pour aller plus loin