Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions DOCKER-COMPOSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Docker Compose – GrandNode (school project)

Run GrandNode e-commerce with MongoDB using Docker Compose.

## What runs

| Service | Port | Role |
|----------|-------|--------------------------------|
| `mongodb`| 27017 | MongoDB 7 – database |
| `grandnode` | 8080 | ASP.NET Core app – store UI & API |

- **Storefront:** http://localhost:8080
- **Admin:** http://localhost:8080/admin (see README for demo credentials)

## Quick start

```bash
# Build and start (required: grandnode image is built locally, not pulled)
docker compose up -d --build

# View logs
docker compose logs -f grandnode
```

If you see "pull access denied for grandnode-school", you tried to pull instead of build. Use `--build` as above.

### ERR_CONNECTION_REFUSED on localhost:8080

1. **Check container status** — GrandNode may be crashing on startup:
```bash
docker ps -a
```
If `grandnode-web` is "Restarting" or "Exited", check logs (step 2).

2. **Check logs** for errors (e.g. missing config, MongoDB connection):
```bash
docker compose logs grandnode --tail 100
```
Look for "Now listening on" (success) or exception messages.

3. **App_Data volume** — If you previously had an `App_Data` volume mounted, it may have hidden `appsettings.json` and caused a crash. The current compose no longer mounts a new App_Data volume so the app can start; restart with:
```bash
docker compose down && docker compose up -d --build
```

4. **Try explicit URL** — Use http://127.0.0.1:8080 in the browser (compose binds to 127.0.0.1:8080 on the host).

### "Value cannot be null. (Parameter 'databaseName')"

The MongoDB connection string must include a **database name**. Use a URL like `mongodb://mongodb:27017/grandnode` (not just `mongodb://mongodb:27017`). The compose file sets this via `ConnectionStrings__Mongodb`.

After MongoDB is healthy, GrandNode starts and listens on port 8080.

**After first-time installation:** GrandNode will ask you to restart. Run `docker compose restart grandnode`. The installer is disabled via env var so you won’t see the install screen again.

## Commands

```bash
# Stop
docker compose down

# Stop and remove volumes (reset DB and app data)
docker compose down -v

# Rebuild app after code changes
docker compose build grandnode && docker compose up -d grandnode
```

## Options

### Build from source (default)

The main `docker-compose.yml` builds GrandNode from the repo Dockerfile. Use this when you change code or need a custom build.

### Use official image (no build)

To run without building (faster start, official release):

```bash
copy docker-compose.override.example.yml docker-compose.override.yml
docker compose up -d
```

Override file swaps the built image for `grandnode/grandnode2:latest`.

## Data

- **MongoDB:** `mongodb_data` volume
- **GrandNode images:** `grandnode_images` volume
- **GrandNode App_Data:** Not mounted (using image defaults so the app can start). Settings/plugins in App_Data do not persist across container recreation.

Data in MongoDB and product images persists across `docker compose down`. Use `docker compose down -v` to wipe volumes.

## Troubleshooting

- **GrandNode exits or “cannot connect to MongoDB”**
Wait for MongoDB healthcheck to pass (about 10–15 s on first start), then restart:
`docker compose restart grandnode`

- **Port 8080 in use**
Change the host port in `docker-compose.yml`, e.g. `"8888:8080"`.

- **Need different MongoDB URL**
Set `ConnectionStrings__Mongodb` in the `grandnode` service `environment` section.
46 changes: 46 additions & 0 deletions cloudWatch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
Application Load Balancer (ALB) : * RequestCount : Pour voir l'évolution du trafic.

TargetResponseTime : Crucial pour l'e-commerce. Si le temps de réponse dépasse 1s, vous perdez des ventes.

HTTPCode_Target_5XX_Count : Pour détecter immédiatement des erreurs serveurs.

Auto Scaling Group (ASG) :

GroupInServiceInstances : Pour vérifier que vos serveurs s'ajoutent bien pendant le pic.

Base de données (RDS) : on laisse en suspends si je trouve plus rentable car très couteux

CPUUtilization et DatabaseConnections.

ReadLatency / WriteLatency.

Alarme de Scaling : Créez une alarme basée sur le RequestCountPerTarget de votre Load Balancer. Si chaque serveur reçoit trop de requêtes, CloudWatch déclenche l'ajout de nouvelles instances.

Alarme de Santé : Si le taux d'erreurs 5XX dépasse 1 % sur 2 minutes, recevez une notification immédiate via Amazon SNS (email ou SMS).

Alarme de Facturation (Billing) : Avec 90 000 visiteurs, les coûts peuvent grimper vite. Mettre une alerte si votre budget dépasse un certain seuil.



CloudWatch Logs : Centralisez les logs de vos serveurs Web (Nginx/Apache) et de votre application.

CloudWatch Logs Insights : Utilisez cet outil pour faire des requêtes rapides sur des millions de lignes de logs.

Exemple : "Affiche-moi les 10 pages les plus lentes durant les 15 dernières minutes."

Contributor Insights : Idéal pour identifier les "Top talkers". Par exemple, si une adresse IP spécifique bombarde votre site (attaque DDoS ou bot), vous le verrez instantanément.


Créez un CloudWatch Dashboard unique qui regroupe les indicateurs métier et techniques. Pour 90k visiteurs, votre dashboard devrait afficher :

Le trafic en temps réel (Nombre de requêtes/sec).

Le temps de latence moyen (Expérience utilisateur).

L'état de santé de la base de données.

Le nombre d'instances EC2 actives.




12 changes: 12 additions & 0 deletions docker-compose.override.example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Optional: use pre-built GrandNode image instead of building from source.
# Copy to docker-compose.override.yml to skip build and start faster:
#
# copy docker-compose.override.example.yml docker-compose.override.yml
#
# Then: docker compose up -d

# Setting build to null makes Compose use only the image (no build).
services:
grandnode:
image: grandnode/grandnode2:latest
build: ~
51 changes: 51 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Docker Compose for GrandNode e-commerce (school project)
# Runs GrandNode (ASP.NET Core) + MongoDB with persistent volumes.

services:
mongodb:
image: mongo:7
container_name: grandnode-mongodb
restart: unless-stopped
ports:
- "27017:27017"
volumes:
- mongodb_data:/data/db
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s

grandnode:
build:
context: .
dockerfile: Dockerfile
# Local image name (built, not pulled from a registry)
image: grandnode-school:latest
container_name: grandnode-web
restart: unless-stopped
# Bind to 127.0.0.1 on host to avoid connection issues on Windows
ports:
- "127.0.0.1:8080:8080"
environment:
# MongoDB connection: host + database name (required; null causes startup crash)
ConnectionStrings__Mongodb: "mongodb://mongodb:27017/grandnode"
ASPNETCORE_ENVIRONMENT: Production
ASPNETCORE_URLS: "http://+:8080"
# Disable installer after first setup (overrides appsettings FeatureManagement)
FeatureManagement__Grand__Module__Installer: "false"
depends_on:
mongodb:
condition: service_healthy
volumes:
- grandnode_images:/app/wwwroot/assets/images
# App_Data: do not mount a new volume here — it would hide appsettings.json
# and other files from the image and cause startup failure (ERR_CONNECTION_REFUSED).
# Uncomment below for persistence (requires init in Dockerfile/entrypoint):
# - grandnode_appdata:/app/App_Data

volumes:
mongodb_data:
grandnode_images:
# grandnode_appdata:
106 changes: 106 additions & 0 deletions load-test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Tests de charge avec k6 (GrandNode)

Tests de charge du storefront GrandNode avec [k6](https://k6.io). Scénarios prévus pour **~90k utilisateurs** (configurable).

## Prérequis

- GrandNode en marche (ex. `docker compose up -d` à la racine du projet ; app sur http://127.0.0.1:8080).
- k6 installé en local, **ou** Docker pour lancer k6 en conteneur.

## Installer k6 (optionnel)

- **Windows (scoop) :** `scoop install k6`
- **macOS :** `brew install k6`
- **Linux :** voir [Installation k6](https://k6.io/docs/getting-started/installation/).

Sinon utiliser Docker (sans installation) : voir « Lancer avec Docker » ci-dessous.

## Lancer rapidement

Depuis le dossier `load-test/`, ou depuis la racine du projet en adaptant les chemins :

```bash
# 1k utilisateurs – test en local (montée 2 min → 1000 VUs, palier 3 min, descente 1 min)
k6 run -e SCENARIO=1k k6/storefront.js

# Par défaut : 50 VUs, 2 min, montée/descente
k6 run k6/storefront.js

# Charge personnalisée
k6 run -e VUS=200 -e DURATION=5m k6/storefront.js

# Scénario 90k : montée jusqu’à 3k VUs sur ~1 h (nombre total d’itérations >> 90k)
k6 run -e SCENARIO=90k -e BASE_URL=http://127.0.0.1:8080 k6/storefront.js

# Progressif 5K → 20K → 50K (durée totale ~45 min)
k6 run -e SCENARIO=progressive k6/storefront.js
# Ou avec le script : .\run-progressive.ps1
```

## Variables d’environnement

| Variable | Défaut | Description |
|------------|------------------------|-------------|
| `BASE_URL` | http://127.0.0.1:8080 | URL de base de GrandNode. |
| `VUS` | 50 | Nombre cible d’utilisateurs virtuels (scénario par défaut). |
| `DURATION` | 2m | Durée du palier de charge (scénario par défaut). |
| `SCENARIO` | (aucun) | `1k` = 1000 VUs (local), `90k` = montée longue, `progressive` = 5K→20K→50K. |

## 1k utilisateurs (test en local)

- **SCENARIO=1k**
Montée en 2 min à 1000 VUs, palier 3 min à 1000 VUs, descente 1 min. Durée totale ~6 min.
Idéal pour tester sur ta machine avant des scénarios plus lourds.

## Tests progressifs 5K → 20K → 50K

- **SCENARIO=progressive**
Test de charge progressif avec paliers standard :
- Montée 5 min → 5 000 VUs, palier 5 min à 5K
- Montée 10 min → 20 000 VUs, palier 5 min à 20K
- Montée 10 min → 50 000 VUs, palier 5 min à 50K
- Descente 5 min → 0
Durée totale ~45 min. Permet d’observer le comportement à chaque palier (débit, latence, erreurs).

## 90k utilisateurs

- **SCENARIO=90k**
Montée : 5 min → 500 VUs, 20 min → 2000, 30 min à 3000, 10 min → 1000, 2 min → 0.
Durée totale ~67 minutes ; le nombre total de requêtes HTTP / itérations sera bien supérieur à 90k.

- **~90k itérations en personnalisé**
Pour viser ~90k itérations au total avec un nombre fixe de VUs, tu peux utiliser un exécuteur constant-vus et une durée telle que (VUs × itérations par VU) ≈ 90k, ou dupliquer le script et fixer un nombre d’itérations dans k6.

## Lancer avec Docker

Depuis la **racine du projet** (pour que `BASE_URL` puisse cibler l’hôte si besoin) :

```powershell
# Le conteneur k6 atteint l’app sur l’hôte via host.docker.internal
docker run --rm -v "${PWD}/load-test/k6:/scripts" grafana/k6 run -e BASE_URL=http://host.docker.internal:8080 /scripts/storefront.js
```

Sous Linux, utiliser `--network host` et `BASE_URL=http://127.0.0.1:8080` pour que le conteneur utilise le réseau de l’hôte.

## Ce que fait le script

- **storefront.js**
Chaque utilisateur virtuel en boucle : GET `/`, GET `/catalog`, GET `/search?q=test`, avec de courtes pauses aléatoires.
Seuils : <5 % de requêtes en échec, p95 < 5 s.

Si ton GrandNode utilise d’autres chemins (ex. pas de `/catalog`), adapte le script dans `k6/storefront.js` ou assouplis les checks (ex. accepter 404 pour les pages optionnelles).

## Résultats et interprétation

- **Pendant le test** tu vois la progression : VUs (utilisateurs virtuels), temps écoulé, itérations complétées. L’absence d’erreurs dans ce flux signifie que les requêtes partent et que des réponses sont reçues.
- **À la fin** (~6 min pour le scénario 1k) k6 affiche un **résumé** : itérations totales, `http_req_duration` (moyenne, p95, médiane, …), `http_req_failed` (taux), et si les **seuils** sont passés (ex. `http_req_failed` < 5 %, p95 de `http_req_duration` < 5 s). Descends en bas du terminal pour le voir.

Pour enregistrer le résumé dans un fichier avec Docker, monte un dossier et utilise `--out json` :

```powershell
# Depuis le dossier load-test ; crée load-test/out et y écrit le résumé
mkdir -Force out
docker run --rm -v ${PWD}:/scripts -v ${PWD}/out:/out grafana/k6 run -e SCENARIO=1k -e BASE_URL=http://host.docker.internal:8080 --out json=/out/summary.json /scripts/k6/storefront.js
```

Ensuite ouvre `load-test/out/summary.json` pour les métriques.
Loading