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, healthcheckmysqladmin 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-TokenetContent-Typecôté serveur, et capture les statements JDBC. Voirobservability/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. Voirobservability/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¶
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 surnginx: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_LANGinjectées via le scriptenv-inject.shau démarrage du container (substitutionseddans 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/prometheustoutes les 2 secondes (POLL_INTERVAL=2000) - Expose
/metricsau format Prometheus (jobperfshop-dockercôté Prometheus) - Voir
observability/dashboard-html.mdpour 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
dnsouipselonWELCOME_MODE(la page liste les URLs accessibles en utilisant soitlocalhost/IP, soit les sous-domaines DNS configurés) - Reçoit toutes les variables
PUBLIC_*_URLdu.envpour 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, installerequests==2.31.0au 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
Formateurset 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.loget 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_generatoractivé (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, ulimitsmemlock=-1etnofile=65536perfshop-opensearch-dashboards: 2.13.0, UI Kibana-compatibleperfshop-vector: collecte les logs Docker (socket monté) et les pousse dans des indexperfshop-{service_family}après transform VRLperfshop-opensearch-seed: crée 7 index templates (spring, nginx, mysql, jmeter, qa, forgejo, observability) et importe le dashboardperfshop-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é viadocker 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_modulespersisté dans le volume nomméjmeter-ui-modules(évite la réinstallation à chaque redémarrage)- Bind mount
/var/run/docker.sock: nécessaire pour exécuterdocker 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.cfget./squash-seed/squash.tm.cfg.propertiespour 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-datapartagé avecperfshop-scripts-ui), crée le dépôtperfshop-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(pourdocker 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 aveccondition: service_healthyoucondition: service_completed_successfully. - Le
perfshop-squash-seedattend explicitement la complétion réussie deperfshop-forgejo-seedavant de démarrer, car il a besoin du token CI Forgejo pour configurer le SCM Squash TM.
Pour aller plus loin¶
- Topologie de déploiement — modes Docker Desktop et Linux/VPS
- Réseau et domaines — détail des ports et des conventions DNS
- Observabilité — Vue d'ensemble
- Stack QA — Vue d'ensemble