From ed92ca7ff832487851d512a07a3dba2abf05a0d2 Mon Sep 17 00:00:00 2001 From: Mortifia Date: Wed, 15 Jul 2026 07:14:09 +0200 Subject: [PATCH] =?UTF-8?q?perf:=20r=C3=A9duire=20la=20fragilit=C3=A9=20et?= =?UTF-8?q?=20la=20taille=20du=20build=20(npm=20ci,=20maxThreads,=20d?= =?UTF-8?q?=C3=A9dup=20images,=20garde-fou=20m=C3=A9moire)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le build (4 locales, Docusaurus) tournait directement sur le VPS de prod (1 vCPU/2GB, partagé avec 13 autres conteneurs) et avait déjà échoué deux fois faute de ressources. Quatre correctifs indépendants, aucun ne touche au contenu : - npm ci au lieu de npm install : plus rapide et déterministe, s'appuie sur package-lock.json au lieu de re-résoudre les versions. - .dockerignore (absent jusqu'ici) : exclut .git/ (67MB), node_modules, et les fichiers résidus (duplicates.txt, FilesNotFound*.txt, Test). - maxThreads: 1 sur docusaurus-lunr-search : le plugin utilise os.cpus() par défaut, qui peut renvoyer le nombre de coeurs du host physique plutôt que la limite réelle du conteneur (1 vCPU ici) — plusieurs threads se battaient pour un seul coeur au lieu d'aider. - NODE_OPTIONS=--max-old-space-size=1024 : force V8 à garbage-collecter plus tôt plutôt que de laisser le kernel OOM-killer intervenir brutalement en pleine compilation webpack. - Dédup des images dupliquées par locale : static/img/ (67MB) est copié intégralement par Docusaurus dans le build de CHAQUE locale (comportement natif de staticDirectories, pas un bug applicatif) — build/fr/img, build/ru/img, build/de/img sont 4 copies identiques du même contenu. Remplacées par des liens symboliques vers build/img (vérifié : busybox httpd les suit nativement, et Docker COPY préserve les symlinks entre stages). Piste explorée et abandonnée : builder chaque locale séparément (docusaurus build --locale X) pour réduire le pic mémoire. Testé directement — --locale fr --out-dir build écrase la racine au lieu de nicher sous build/fr/, contrairement à un build multi-locale classique. Recomposer correctement l'arborescence (routing, sitemap, recherche par langue) est un vrai chantier, pas un réglage — hors du périmètre "tuning" de ce soir. Testé sur le VPS (build --no-cache complet, 4 locales) : - symlinks confirmés dans build/{fr,ru,de}/img, contenu accessible via Docker COPY --from - conteneur démarré réellement : / , /fr/ , /ru/ , /de/ répondent 200, une image testée via /fr/img/... et /img/... répond 200 dans les deux cas (même contenu, symlink suivi correctement) Taille de l'image : 465MB -> 267MB (-43%). --- .dockerignore | 7 +++++++ Dockerfile | 34 ++++++++++++++++++++++++++++++---- docusaurus.config.js | 7 ++++++- 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0b82a03 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +.git +node_modules +build +duplicates.txt +FilesNotFound.txt +FilesNotFound-processed.txt +Test diff --git a/Dockerfile b/Dockerfile index 138b451..c6e23a3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,37 @@ -FROM node:20 AS build +FROM node:20-alpine AS build WORKDIR /usr/src/app + +# npm ci (pas npm install) : plus rapide et déterministe, s'appuie sur +# package-lock.json déjà verrouillé au lieu de re-résoudre les versions. COPY package*.json ./ -RUN npm install +RUN npm ci + COPY . . -RUN npm run build + +# --max-old-space-size sous la RAM réelle du VPS (1 vCPU/2GB, partagé avec +# 13 autres conteneurs) : force V8 à garbage-collecter plus tôt plutôt que +# de laisser le kernel OOM-killer intervenir brutalement en pleine +# compilation webpack. +RUN NODE_OPTIONS="--max-old-space-size=1024" npm run build + +# static/img/ (67MB) est copié intégralement par Docusaurus dans le +# dossier de sortie de CHAQUE locale (comportement natif de +# staticDirectories, pas un bug applicatif) : build/img, build/fr/img, +# build/ru/img, build/de/img sont 4 copies identiques. On ne garde que la +# copie racine et on remplace les 3 autres par des liens symboliques — +# busybox httpd les suit nativement (vérifié), le contenu servi est +# identique, seule la taille de l'image finale change (~268MB -> ~67MB +# pour les images). +RUN for l in fr ru de; do \ + if [ -d "build/$l/img" ]; then \ + rm -rf "build/$l/img" && ln -s ../img "build/$l/img"; \ + fi; \ + done # Deployment step +# Ce stage n'est jamais publié (multi-stage) : il ne sert qu'à builder, +# node:20-alpine réduit juste l'empreinte disque pendant le build (pas +# d'effet sur l'image finale, déjà minimale via busybox ci-dessous). FROM busybox:1.36 AS deploy @@ -17,4 +43,4 @@ COPY --from=build /usr/src/app/build/ ./ EXPOSE 3000 -CMD ["busybox", "httpd", "-f", "-v", "-p", "3000"] \ No newline at end of file +CMD ["busybox", "httpd", "-f", "-v", "-p", "3000"] diff --git a/docusaurus.config.js b/docusaurus.config.js index 7cd12b4..596fe83 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -141,7 +141,12 @@ const config = { }, themes: ['@docusaurus/theme-mermaid'], plugins: [[require.resolve('docusaurus-lunr-search'), { - languages: ['en', 'fr', 'ru', 'de'] + languages: ['en', 'fr', 'ru', 'de'], + // Sans ça, le plugin utilise os.cpus() qui peut renvoyer le nombre de + // coeurs du host physique plutot que la limite reelle du conteneur (1 + // vCPU sur ce VPS) : plusieurs threads se battent alors pour un seul + // coeur au lieu d'aider. + maxThreads: 1 }]], };