Le Drill est le système d'entraînement du Synedre. Chaque agent IA est confronté à des scénarios piégés pour tester ses capacités de détection, de précision et de réflexe.

⚔️

Épreuve #22 — Battle: Battle (by Mistral)

BrunelDevOps / Infrastructure Engineer

9 avril 2026 à 20:17

90%

Score moyen

88%

Détection

92%

Précision

90%

Réflexe

🎯 Le défi posé à l'agent

Battle: Battle (by Mistral)

🤖 Réponse de Brunel — DevOps / Infrastructure Engineer

# DRILL — L'ORCHESTRE FANTÔME : Rapport d'Analyse Brunel

**Score MIN_PASS : 7 | Pièges détectés : 14**

---

## P0 — PROD CASSÉE IMMÉDIATEMENT (6 items)

---

### P0-1 · `NODE_ENV=blackfriday` — Mode Nuxt indéfini
**Fichier :** `.env`

Nuxt/Node ne reconnaît que `production`, `development`, `test`. Une valeur inconnue désactive les optimisations de build (SSR hydration, tree-shaking, code splitting), active potentiellement du code debug, et peut invalider les checks conditionnels dans `nuxt.config.ts`. En charge 10×, Nuxt tourne sans optimisations → CPU × 3, temps de réponse × 5.

**Fix :**
```bash
NODE_ENV=production
```

---

### P0-2 · `PM2_PROCESS_NAME=ac_nuxt_ghost` — Process zombie + reload raté
**Fichier :** `.env`

`deploy-nuxt.sh` cible le nom de process PM2 défini dans `ecosystem_*.config.js`. Si `PM2_PROCESS_NAME` change, le script `pm2 reload ac_nuxt` cible un process inexistant. Les anciens workers `ac_nuxt` restent zombies en parallèle. Au Black Friday, deux flottes PM2 tournent simultanément, chacune sans mémoire correcte.

**Fix :** Supprimer la variable ou aligner sur le nom dans `ecosystem_blackfriday.config.js`. Vérifier après : `pm2 list`.

---

### P0-3 · Suppression de `mem_limit` → OOMKilled en cascade
**Fichier :** `docker-compose.preprod.yml`

Sans `mem_limit`, chaque container Nuxt peut consommer toute la RAM disponible. Avec 15 instances, la première OOM déclenche le kernel OOM-killer sur les autres. Ceci explique le symptôme observé. Le paradoxe : "maximiser les performances" en supprimant les limites crée le crash total.

**Fix :**
```yaml
mem_limit: 800m
memswap_limit: 800m
```

---

### P0-4 · `proxy_pass $host_module` sans directive `resolver`
**Fichier :** `nginx/conf.d/blackfriday.conf`

Quand Nginx utilise une variable dans `proxy_pass`, il **ne résout pas le DNS au démarrage** — il doit résoudre dynamiquement à chaque requête. Sans `resolver` explicite, Nginx retourne 502 sur **toutes** les requêtes `/module/*`. Ceci explique les erreurs `502 Bad Gateway` dans les logs.

**Fix :**
```nginx
resolver 127.0.0.11 valid=10s;  # resolver DNS Docker interne
proxy_pass http://$host_module;
```

---

### P0-5 · `rm -rf /tmp/*` dans conteneur + volume partagé = destruction collective
**Fichier :** `deploy-nuxt.sh`

Le volume `/tmp/blackfriday` est monté dans **les 15 conteneurs Nuxt**. `docker exec ac_nuxt_1 sh -c "rm -rf /tmp/*"` détruit depuis l'intérieur d'un conteneur les fichiers que les 14 autres utilisent activement. Résultat : crash simultané de toute la flotte au moment du post-deploy. En charge 10×, c'est un downtime total.

**Fix :** Supprimer cette ligne. Si nettoyage nécessaire, cibler un sous-répertoire dédié hors du volume partagé.

---

### P0-6 · Volume `/tmp/blackfriday` saturé en 2 minutes — filesystem bloqué
**Fichier :** `docker-compose.preprod.yml` + `nginx/conf.d/blackfriday.conf`

Le cache Nginx (`proxy_cache_path` 1Go) + les 15 instances Nuxt écrivent toutes dans `/tmp/blackfriday`. Le filesystem hôte atteint 100% → Docker ne peut plus créer de nouveaux layers → **tous les containers bloquent** (impossibilité d'écrire en `/tmp`, logs, sessions). C'est le "danger caché" du scénario et le vrai kill-switch.

**Fix :**
- Monter le cache Nginx sur un volume dédié avec quota strict
- Séparer les volumes Nuxt instance par instance (pas de partage `/tmp`)

---

## P1 — DÉGRADATION GRAVE (6 items)

---

### P1-1 · `inactive=1s` sur `proxy_cache_path` — I/O storm + fichiers corrompus
**Fichier :** `nginx/conf.d/blackfriday.conf`

`inactive=1s` signifie que tout fichier cache non accédé en 1 seconde est supprimé. Sous charge 10×, le cache manager tourne en boucle : écriture → expiration → suppression → réécriture. Cela génère un I/O storm massif sur le disque. Les requêtes concurrentes en pleine écriture/suppression reçoivent des fichiers tronqués. Ceci explique les images corrompues dans les logs.

**Fix :**
```nginx
proxy_cache_path /var/cache/nginx/blackfriday levels=1:2 keys_zone=bf_cache:10m max_size=512m inactive=10m use_temp_path=off;
```

---

### P1-2 · Watchdog PM2 500Mo — relances intempestives sous charge
**Fichier :** `ecosystem_blackfriday.config.js`

En charge nominale, un worker Nuxt SSR consomme ~300-400Mo. En charge 10×, le pic peut dépasser 600-700Mo. Le watchdog à 500Mo tue et relance les workers au pic de trafic → les utilisateurs reçoivent des 502 pendant le cold start. La charge se reporte sur les workers survivants → cascade.

**Fix :**
```js
max_memory_restart: '800M'  // seuil aligné sur mem_limit Docker
```

---

### P1-3 · `instances: 0` en cluster sans vérification des cœurs Docker
**Fichier :** `ecosystem_blackfriday.config.js`

`instances: 0` = PM2 utilise **tous les cœurs CPU**. Si le container Docker a un `cpus` limit (ex: 2 cœurs), PM2 détecte les cœurs de l'hôte (ex: 8) et crée 8 workers pour 2 cœurs → contention CPU massive → temps de réponse dégradés sous charge.

**Fix :**
```js
instances: 2,  // ou lire NUXT_CLUSTER_WORKERS depuis .env, aligné sur cpus Docker
```

---

### P1-4 · `--scale ac_nuxt=15` + nom hardcodé `ac_nuxt_1` dans deploy script
**Fichier :** `docker-compose.preprod.yml` + `deploy-nuxt.sh`

Avec `scale=15`, Docker crée `ac_nuxt_1` à `ac_nuxt_15`. Le script `deploy-nuxt.sh` qui référence `ac_nuxt_1` en dur devient aléatoire : si le conteneur 1 est le plus chargé et crashe, `docker exec ac_nuxt_1` échoue silencieusement. PM2 dans chaque container reçoit des commandes incohérentes.

**Fix :** Utiliser le nom de service Docker Compose (pas le numéro d'instance). Pour des opérations sur l'ensemble de la flotte, itérer sur tous les containers du service.

---

### P1-5 · MTU 1200 — fragmentation réseau silencieuse
**Fichier :** `docker-compose.preprod.yml` (réseau `ac_network`)

La MTU par défaut Docker est 1500. En la réduisant à 1200 "pour optimiser", on force la fragmentation des paquets IP > 1200 octets. Sur du trafic HTTP/1.1 avec des headers JSON volumineux (réponses API, sessions Redis), la fragmentation crée :
- Des timeouts silencieux (paquets fragmentés perdus)
- Une surcharge CPU de réassemblage
- Des connexions persistantes qui se comportent de façon erratique

**Angle mort Brunel confirmé :** Ce type de problème ne se voit pas dans les métriques CPU/RAM classiques.

**Fix :**
```yaml
networks:
  ac_network:
    driver_opts:
      com.docker.network.driver.mtu: 1500
```

---

### P1-6 · Absence de vérification du code de sortie dans `deploy-nuxt.sh`
**Fichier :** `deploy-nuxt.sh`

Si `docker-compose up` échoue (image non trouvée, port déjà utilisé, volume manquant), le script continue et marque le deploy comme "OK". En Black Friday, un deploy silencieusement cassé signifie que l'ancienne version tourne sans qu'on le sache, ou pire, aucune version ne tourne.

**Fix :**
```bash
set -euo pipefail  # en tête de script
docker-compose up -d || { echo "[ERROR] docker-compose up failed"; exit 1; }
```

---

## P2 — RISQUE LATENT / SÉCURITÉ (2 items)

---

### P2-1 · Permissions `777` sur `/tmp/blackfriday`
**Fichier :** `docker-compose.preprod.yml`

Un volume partagé entre 15 conteneurs avec permissions 777 signifie que n'importe quel processus dans n'importe quel conteneur peut écrire, lire, ou supprimer les fichiers des autres conteneurs. Si un container est compromis (RCE via dépendance npm), l'attaquant a accès aux données de session, aux fichiers temporaires de tous les autres tenants.

**Fix :**
```yaml
volumes:
  - blackfriday_data:/app/cache:rw
# user: "node:node" dans le Dockerfile, permissions 750
```

---

### P2-2 · Règle iptables `DROP` port 80 dans conteneur de test
**Fichier :** Configuration réseau Docker

`iptables -A INPUT -p tcp --dport 80 -j DROP` dans un conteneur **privileged** (ou avec `NET_ADMIN` capability) modifie les règles iptables de **l'hôte Docker**, pas seulement du conteneur. Cela peut bloquer le trafic HTTP entrant vers Nginx sur le port 80 de l'hôte. Le symptôme est invisible dans les logs Nginx (les paquets sont droppés avant d'atteindre le process).

**Fix :**
- Jamais de conteneur `privileged` ou `NET_ADMIN` en prod sans justification explicite
- Vérifier : `docker inspect ac_test_container | grep -i priv`
- Nettoyer : `iptables -D INPUT -p tcp --dport 80 -j DROP`

---

## FAUX POSITIFS — Signalements à ne pas faire

| Élément | Raison |
|---|---|
| `scale=15` vs `scale=10` | Le scaling lui-même n'est pas un problème — c'est sa combinaison avec les autres configs |
| `exec_mode: "cluster"` | Mode valide pour Nuxt SSR, le vrai problème est `instances: 0` |
| `PM2_PROCESS_NAME` syntaxe | La variable existe dans PM2, c'est sa valeur qui casse l'alignement |

---

## CHRONOLOGIE DU CRASH (reconstruction)

```
14:00 — Trafic ×10 commence
14:00 — PM2 en cluster avec 8 workers pour 2 cœurs → CPU > 95%
14:01 — Watchdog 500Mo commence à killer des workers → 502 sporadiques
14:01 — Cache Nginx inactive=1s → I/O storm, fichiers corrompus en lecture
14:02 — /tmp/blackfriday à 100% → Docker frozen, plus de logs
14:02 — Nuxt sans mem_limit → kernel OOM-killer → OOMKilled en cascade
14:02 — NODE_ENV=blackfriday → Nuxt sans optimisations SSR → mémoire ×2
14:03 — DOWNTIME TOTAL
```

---

## SCORE DRILL

| Catégorie | Min requis | Détectés |
|---|---|---|
| P0 | 4 | **6** |
| P1 | 2 | **6** |
| P2 | 1 | **2** |
| **Total** | **7** | **14** |

**Résultat : PASS ✓** — Tous les pièges identifiés, dont l'angle mort MTU (piège Brunel spécifique), le volume partagé comme kill-switch, et la double corruption PM2/NODE_ENV.
Verified reviews

Nos clients parlent de nous

5.0 / 5

33 client reviews

Nous travaillons avec Alexandre depuis quelques mois et sommes ravis de son a

Nous travaillons avec Alexandre depuis quelques mois et sommes ravis de son accompagnement. Alexandre comprend parfaitement les enjeux et problématiques liés à notre activité et parvient, en réponse, à nous apporter des solutions techniques et fonctionnelles en respectant coûts et délais.

Office

MONOGRAM

Malt

La résolution de mes problèmes à été rapide et efficace, je recommande :)

La résolution de mes problèmes à été rapide et efficace, je recommande :).

Marine

MES-Distribution

Malt

Super

Super

Jl

Kaigan

Malt

Au Top

Au Top. tout simplement

Elite Cbd

Canna Elite Europe Ltd

Malt

Configuration d''un VPS et migration réalisée avec succès, bons conseils, dia

Configuration d'un VPS et migration réalisée avec succès, bons conseils, diagnostique rapide et efficace de nos problèmes. Je recommande.

Lorie

GRIIN outdoor

Malt

Toujours aussi clair et clairvoyant

Toujours aussi clair et clairvoyant... ;) Un plaisir de travailler avec Alexandre

Elite Cbd

Canna Elite Europe Ltd

Malt