ajoute la recherche plein texte dans les cours et labs (bloc C)
Elasticsearch interne (jamais exposé, sécurité x-pack désactivée, cohérent avec le reste des services internes de ce serveur), tas JVM fixé à 512 Mo plutôt que le calcul automatique (jusqu'à 50 % de la RAM système, désastreux sur ce serveur à 31 Go réels). Appels HTTP directs depuis Laravel, pas de bibliothèque cliente pour un besoin aussi simple. Index reconstruit après chaque synchronisation du catalogue, page de recherche commune aux profs et aux élèves. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
e549f03e1b
commit
777dd1cbc8
20 changed files with 545 additions and 0 deletions
70
docs/adr/0009-elasticsearch-interne-sans-securite.md
Normal file
70
docs/adr/0009-elasticsearch-interne-sans-securite.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# ADR 0009 — Elasticsearch interne, sécurité x-pack désactivée
|
||||
|
||||
- **Date** : 2026-10-14
|
||||
- **Statut** : accepté
|
||||
|
||||
## Contexte
|
||||
|
||||
Bloc C du CLAUDE.md : « ElasticSearch : recherche plein texte dans les cours
|
||||
et les labs (seulement si le besoin est réel). » Adam a confirmé le besoin
|
||||
explicitement (« fonce »). Catalogue minuscule (quelques labs, un seul
|
||||
`cours.md` aujourd'hui) : aucun besoin d'un cluster, d'un cache de
|
||||
répertoires exotique ou d'une bibliothèque cliente PHP dédiée.
|
||||
|
||||
## Décisions
|
||||
|
||||
**Une instance Elasticsearch 8.19, locale, jamais exposée.** Installée
|
||||
depuis le dépôt APT officiel Elastic (clé GPG vérifiée, même principe que
|
||||
Ceph/ADR 0007). Consommée uniquement par le portail, en PHP, sur
|
||||
`127.0.0.1:9200` — jamais par un navigateur.
|
||||
|
||||
**Sécurité x-pack désactivée (`xpack.security.enabled: false`).**
|
||||
L'installation standard active TLS + authentification par défaut depuis la
|
||||
8.x (mot de passe généré, certificats auto-signés) — pertinent pour un
|
||||
cluster multi-nœuds exposé, disproportionné pour une instance mono-nœud qui
|
||||
ne parle qu'à elle-même sur la boucle locale. Cohérent avec le reste de ce
|
||||
serveur : l'API OpenStack interne (`10.10.0.1`) et le MariaDB/Redis dédiés
|
||||
au portail (`127.0.0.1:3307`/`6380`) n'ont pas non plus de TLS entre
|
||||
services — l'isolation vient du pare-feu (`policy drop` par défaut) et de
|
||||
l'écoute en local, pas d'une authentification par service. Désactiver x-pack
|
||||
évite aussi de devoir stocker et faire tourner un mot de passe Elasticsearch
|
||||
supplémentaire pour rien.
|
||||
|
||||
**Tas JVM réduit à 512 Mo (`-Xms512m -Xmx512m`), pas le calcul automatique
|
||||
d'Elasticsearch.** Par défaut, Elasticsearch vise jusqu'à 50 % de la RAM
|
||||
système — sur ce serveur à 31 Go réels (voir ADR 0007), cela aurait pu
|
||||
réserver ~15 Go à un service qui indexe quelques dizaines de documents.
|
||||
Mesuré après coup : ~900 Mo de RSS au total pour le processus, RAM
|
||||
disponible du serveur restée stable (~6 Go) pendant tout le chantier.
|
||||
|
||||
**Appels HTTP directs (`Illuminate\Support\Facades\Http`), pas le client
|
||||
PHP officiel `elastic/elasticsearch`.** Le besoin se limite à indexer des
|
||||
documents et faire une recherche plein texte avec surlignage — deux appels
|
||||
REST simples. Ajouter une bibliothèque cliente complète (et ses
|
||||
dépendances) pour ça aurait été une techno sans besoin réel (CLAUDE.md,
|
||||
section 8).
|
||||
|
||||
**Analyseur `french` d'Elasticsearch sur les champs `titre`/`contenu`.**
|
||||
Livré avec Elasticsearch, pas un plugin à installer : améliore réellement la
|
||||
pertinence sur du contenu pédagogique en français (élision, racines des
|
||||
mots) sans coût d'exploitation supplémentaire.
|
||||
|
||||
**Reconstruction complète de l'index à chaque synchronisation**
|
||||
(`labs:synchroniser`, `cours:synchroniser`), pas une mise à jour
|
||||
incrémentale. Volume du catalogue trop faible pour que ça coûte quoi que ce
|
||||
soit ; plus simple et plus sûr (jamais de document orphelin si un lab est
|
||||
retiré).
|
||||
|
||||
## Conséquences
|
||||
|
||||
- Recherche vérifiée en réel avec un compte élève jetable : les deux vrais
|
||||
documents existants (labs catalogués + `08-deux-lan-routeur/cours.md`,
|
||||
contenu réel) retrouvés par recherche plein texte, extrait surligné
|
||||
affiché, compte supprimé ensuite.
|
||||
- `App\Services\Recherche\IndexRecherche::disponible()` renvoie `false` si
|
||||
`ELASTICSEARCH_HOTE` n'est pas renseigné : la page de recherche affiche
|
||||
alors un message d'indisponibilité au lieu d'une erreur — même principe
|
||||
que `StockageTravauxEleves::disponible()` pour le S3.
|
||||
- En dette : pas de pagination des résultats (taille de catalogue bien en
|
||||
dessous du besoin), pas de recherche à facettes (niveau, compétence) —
|
||||
à ajouter si le catalogue grossit réellement.
|
||||
|
|
@ -40,3 +40,4 @@ retirer la ligne (et le noter dans le journal) quand c'est fait.
|
|||
| Ceph : démo mono-serveur seulement (1 OSD sur fichier épars, pas de réplication, pas branché à Cinder/Glance) | `ceph_pool_default_size=1` et un seul OSD acceptés uniquement parce que c'est une démo de compréhension, sans donnée réelle. Le vrai cluster (plusieurs OSD, réplication, intégré à Cinder) attend le 2ᵉ serveur du CLAUDE.md. Voir [ADR 0007](adr/0007-ceph-demo-mono-serveur.md). | 2ᵉ serveur (bloc C) | 2026-10-14 |
|
||||
| Ceph : bootstrap fait à la main, pas encore rejouable par Ansible | Comme Kolla à l'étape 2 : acceptable pour une démo, à automatiser si ce cluster doit durer. Le fichier systemd du loop device est suivi dans `infra/ceph/` mais déployé à la main. | Si la démo devient durable | 2026-10-14 |
|
||||
| WebDAV de l'élève : stockage local, pas S3 ; pas de quota par élève | Dossier local (`storage/app/webdav/`), partage le disque serré avec OpenStack et le portail — pas de limite de taille par élève. rclone sait servir un backend S3 sans changement d'architecture (voir [ADR 0008](adr/0008-webdav-eleve-auth-request.md)) : à basculer en même temps que le bucket S3 des devoirs (`docs/runbooks/stockage-s3.md`), et à ajouter un quota si l'usage réel le demande. | Quand le bucket S3 existe / si l'usage le demande | 2026-10-14 |
|
||||
| Recherche (Elasticsearch) : pas de pagination ni de facettes | Catalogue minuscule aujourd'hui (quelques labs, un seul vrai `cours.md`) : inutile tant que ça reste le cas. Voir [ADR 0009](adr/0009-elasticsearch-interne-sans-securite.md). | Si le catalogue grossit réellement | 2026-10-14 |
|
||||
|
|
|
|||
|
|
@ -1251,3 +1251,26 @@ de haut en bas — une bonne question à savoir expliquer en entretien SRE.
|
|||
**Suite**
|
||||
|
||||
Prochain chantier du bloc C : ElasticSearch.
|
||||
|
||||
## 2026-10-14 — Recherche plein texte, Elasticsearch (bloc C)
|
||||
|
||||
Troisième chantier du bloc C : recherche plein texte dans les cours et les
|
||||
labs. Détail des choix : [ADR 0009](adr/0009-elasticsearch-interne-sans-securite.md).
|
||||
|
||||
**Fait**
|
||||
|
||||
- Elasticsearch 8.19 installé depuis le dépôt officiel (clé GPG vérifiée), instance strictement interne : écoute `127.0.0.1` seulement, sécurité x-pack désactivée (cohérent avec le reste du serveur — l'API OpenStack interne et le MariaDB/Redis du portail n'ont pas de TLS entre services non plus, l'isolation vient du pare-feu), tas JVM limité à 512 Mo (le calcul automatique d'Elasticsearch, jusqu'à 50 % de la RAM système, aurait pu réserver ~15 Go sur ce serveur à 31 Go réels).
|
||||
- `App\Services\Recherche\IndexRecherche` : appels HTTP directs (pas de bibliothèque cliente, le besoin se limite à indexer et chercher), analyseur `french` d'Elasticsearch sur les champs texte, `disponible()` même principe que le stockage S3 (la page affiche juste « pas disponible » tant que ce n'est pas configuré, jamais une erreur).
|
||||
- Index reconstruit automatiquement après `labs:synchroniser` et `cours:synchroniser` — pas de mise à jour incrémentale, le catalogue est trop petit pour que ça coûte quoi que ce soit.
|
||||
- Page « Recherche » (menu du compte, profs et élèves), route commune aux deux guards (`auth:eleve,web`, déjà utilisée par « Mes cours »/« Paramètres »).
|
||||
- 5 tests Pest (`Http::fake()`, jamais contre un vrai Elasticsearch) : indisponibilité propre, accès par les deux guards, surlignage affiché avec le bon lien vers la page du cours, reconstruction de l'index envoie bien un document par lab/cours, et n'envoie *aucun* appel réseau quand Elasticsearch n'est pas configuré.
|
||||
|
||||
**Vérifié en réel** : index reconstruit sur le serveur depuis les vraies données (2 documents : le lab 08 et son vrai `cours.md`), recherche du mot « routage » retrouve les deux avec le bon score, page `/recherche` testée avec un compte élève jetable (connexion réelle par cookies de session, pas juste un appel direct au contrôleur) — le mot recherché apparaît bien surligné (`<em>routage</em>`) et le lien vers le cours fonctionne. RAM disponible du serveur restée stable (~6 Go) pendant tout le chantier. Compte de test supprimé ensuite.
|
||||
|
||||
**Comprendre**
|
||||
|
||||
Le réflexe acquis avec Ceph et WebDAV (vérifier l'état réel avant d'agir, mesurer plutôt que deviner) a évité ici une vraie bêtise : Elasticsearch calcule par défaut un tas JVM jusqu'à 50 % de la RAM système, ce qui aurait été catastrophique sur ce serveur sans même un message d'erreur — juste un service qui prend toute la RAM disponible. Fixer explicitement le tas avant le premier démarrage, plutôt qu'après avoir constaté le problème, est le genre de précaution qui ne coûte rien et qui évite un incident.
|
||||
|
||||
**Suite**
|
||||
|
||||
Bloc C restant : WebDAV et Ceph faits, Elasticsearch fait. ElasticSearch avait été écarté du MCP développeurs par Adam (pas pour l'instant). Prochains chantiers confirmés par Adam : LTI Moodle 1.3, puis SSO ENT (Keycloak) — normalement des étapes V2/V3 du produit, avancées à la demande explicite d'Adam.
|
||||
|
|
|
|||
64
docs/runbooks/elasticsearch.md
Normal file
64
docs/runbooks/elasticsearch.md
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# Runbook — Elasticsearch (recherche dans les cours et labs)
|
||||
|
||||
Instance interne, jamais exposée, consommée seulement par le portail en PHP
|
||||
(`App\Services\Recherche\IndexRecherche`). Détail des choix :
|
||||
[ADR 0009](../adr/0009-elasticsearch-interne-sans-securite.md).
|
||||
|
||||
## Où sont les choses
|
||||
|
||||
| Élément | Emplacement |
|
||||
|---|---|
|
||||
| Config | `/etc/elasticsearch/elasticsearch.yml` (sécurité x-pack désactivée, écoute `127.0.0.1` seulement) |
|
||||
| Tas JVM | `/etc/elasticsearch/jvm.options.d/heap.options` (512 Mo, voir ADR 0009) |
|
||||
| Index | `paillasse_catalogue` |
|
||||
| Déployé par | `ansible/elasticsearch.yml` (rôle `elasticsearch`, rejoue aussi `portail` pour écrire `.env`) |
|
||||
|
||||
```
|
||||
cd ansible && script -q /dev/null ansible-playbook elasticsearch.yml -i inventory.ini
|
||||
```
|
||||
|
||||
## Vérifier que ça fonctionne
|
||||
|
||||
```
|
||||
systemctl is-active elasticsearch
|
||||
curl -s http://127.0.0.1:9200/paillasse_catalogue/_count
|
||||
```
|
||||
|
||||
Reconstruire l'index manuellement (après un changement de mapping, ou si le
|
||||
catalogue semble désynchronisé) :
|
||||
|
||||
```
|
||||
cd /var/www/portail
|
||||
sudo -u www-data HOME=/tmp php8.3 artisan recherche:indexer
|
||||
```
|
||||
|
||||
Autrement, l'index se reconstruit automatiquement après `labs:synchroniser`
|
||||
et `cours:synchroniser` (voir ces deux commandes).
|
||||
|
||||
## Pourquoi la RAM est surveillée
|
||||
|
||||
Comme pour Ceph et WebDAV (voir les runbooks correspondants) : ce serveur a
|
||||
réellement 31 Go de RAM, partagés avec OpenStack et le portail. Le tas JVM
|
||||
est volontairement limité à 512 Mo (~900 Mo de RSS au total mesuré) — ne
|
||||
jamais retirer `heap.options` ni laisser Elasticsearch calculer sa taille de
|
||||
tas automatiquement sur ce serveur.
|
||||
|
||||
## Si le besoin grossit réellement
|
||||
|
||||
Pas de pagination ni de recherche à facettes pour l'instant (catalogue
|
||||
minuscule). À ajouter dans `App\Services\Recherche\IndexRecherche` et
|
||||
`RechercheController` si le catalogue de cours/labs grossit vraiment —
|
||||
jamais avant, pour ne pas construire une fonction sans usage réel.
|
||||
|
||||
## Nettoyer entièrement (si besoin)
|
||||
|
||||
```
|
||||
ssh paillasse
|
||||
sudo systemctl disable --now elasticsearch
|
||||
sudo rm -rf /var/lib/elasticsearch /etc/elasticsearch
|
||||
sudo apt-get purge -y elasticsearch
|
||||
sudo rm /etc/apt/sources.list.d/elastic-8.x.list /usr/share/keyrings/elastic.gpg
|
||||
sudo apt-get update
|
||||
```
|
||||
Puis retirer `ELASTICSEARCH_HOTE`/`ELASTICSEARCH_PORT` du `.env` du portail
|
||||
et redémarrer Horizon.
|
||||
Loading…
Add table
Add a link
Reference in a new issue