Cross-arch : container-test accepte une platform cible (incident « exec format error »)
Le premier déploiement NAS a échoué avec « exec /docker-entrypoint.sh: exec format error » : image arm64 (buildée sur Mac Apple Silicon) exécutée sur un hôte amd64. Le test réel l'a épiné : container-test.sh accepte désormais un paramètre PLATFORM (build cross-arch SANS émulation — le Dockerfile n'a aucun RUN — puis run émulé + E2E complet) : bash scripts/container-test.sh <port> linux/amd64 → validé vert sur linux/amd64 (healthcheck durci, E2E complet). Docs §10 : leçon cross-arch (les 2 procédures de build — sur le serveur cible ou multi-arch push via buildx), statut : les DEUX archs testées ; note : l'« io_setup() failed » sous émulation Rosetta est inoffensif.
This commit is contained in:
parent
96e0627741
commit
e078650045
23
README.md
23
README.md
@ -62,23 +62,32 @@ server {
|
||||
### Avec Docker (self-host NAS/VPS)
|
||||
|
||||
L'image ne fait **que servir les fichiers** : aucune donnée dedans, la vie
|
||||
privée est identique (les données vivent dans les navigateurs). Build et
|
||||
exécution :
|
||||
privée est identique (les données vivent dans les navigateurs). Deux
|
||||
procédures équivalentes — **l'image doit être pour l'arch CPU de l'hôte**
|
||||
(« exec format error » = arch incompatible, cf
|
||||
[docs/DEVELOPPEMENT.md §10](docs/DEVELOPPEMENT.md)) :
|
||||
|
||||
```bash
|
||||
docker compose up -d # build + run → http://<hôte>:8080/
|
||||
docker compose up -d --build # rebuild après mise à jour du dépôt
|
||||
# ── Option 1 (recommandée) : build SUR le serveur cible
|
||||
git clone https://gitea.cloudyfy.fr/Siphonight/HormoneTrack-web && cd HormoneTrack-web
|
||||
docker compose up -d --build # arch native, toujours correcte
|
||||
|
||||
# ── Option 2 : multi-arch depuis un Mac (push vers ton registry)
|
||||
docker buildx build --platform linux/amd64,linux/arm64 \
|
||||
-t tonuser/hormonetrack-web:latest --push .
|
||||
```
|
||||
|
||||
- Image **non privilégiée** (`nginx-unprivileged`, utilisateur 101, port
|
||||
8080), filesystem en **lecture seule** (composé prêt pour le NAS),
|
||||
healthcheck intégré, gzip sur l'asset PK (550 Ko → ~150 Ko).
|
||||
8080), filesystem en **lecture seule** + tmpfs (composé durci), vérif
|
||||
healthcheck intégrée, gzip sur l'asset PK (550 Ko → ~150 Ko).
|
||||
- Headers `no-cache` : une mise à jour d'image est prise en compte au
|
||||
rechargement suivant, sans code périmé chez les clients.
|
||||
- Validation en 3 commandes sur l'hôte qui a Docker (cf
|
||||
[docs/DEVELOPPEMENT.md §10](docs/DEVELOPPEMENT.md)) : build, run, puis
|
||||
`HRT_E2E_BASE=http://127.0.0.1:8080 node scripts/e2e.mjs` — le même test
|
||||
E2E que le CI pilote le site SERVI PAR LE CONTENEUR.
|
||||
E2E que le CI pilote le site SERVI PAR LE CONTENEUR. Pour tester l'arch
|
||||
cible AVANT déploiement :
|
||||
`bash scripts/container-test.sh 8979 linux/amd64`.
|
||||
|
||||
Aucun build, aucune variable d'environnement, aucun composant serveur : les
|
||||
données de chaque personne vivent **dans SON navigateur**, jamais sur la
|
||||
|
||||
@ -571,14 +571,54 @@ HRT_E2E_BASE=http://127.0.0.1:8080 node scripts/e2e.mjs
|
||||
|
||||
**Statut (8 sept. 2026)** : build et run RÉELS validés localement via
|
||||
colima (daemon Docker léger, 2 CPU / 2 Go) — `scripts/container-test.sh`
|
||||
vert en configuration DURCIE (healthcheck healthy, endpoints, headers,
|
||||
gzip, MIME, E2E complet contre le conteneur). Deux problèmes réels trouvés
|
||||
et corrigés au premier test : (a) tmpfs `/tmp` REQUIS en read-only (les
|
||||
temporaires de nginx-unprivileged — « mkdir /tmp/proxy_temp failed »
|
||||
sinon), (b) curl `%header_json` minuscule les clés (bug du TEST, pas du
|
||||
conteneur). Si le durcissement pose problème sur ton NAS : retirer
|
||||
`read_only`/`tmpfs`/`security_opt` du compose (aucune perte de sécurité
|
||||
cruciale — le conteneur ne détient rien).
|
||||
vert en configuration DURCIE pour **les DEUX architectures** (arm64 native
|
||||
et linux/amd64 cross-compilée : healthcheck healthy, endpoints, headers,
|
||||
gzip, MIME, E2E complet contre le conteneur). Problèmes réels trouvés aux
|
||||
premiers tests, corrigés et documentés : (a) tmpfs `/tmp` REQUIS en
|
||||
read-only (« mkdir /tmp/proxy_temp failed » sinon), (b) curl `%header_json`
|
||||
minuscule les clés (bug du TEST), (c) **exec format error sur l'hôte
|
||||
amd64** (cf §10 bis). Si le durcissement pose problème sur ton NAS :
|
||||
retirer `read_only`/`tmpfs`/`security_opt` du compose (aucune perte de
|
||||
sécurité cruciale — le conteneur ne détient rien).
|
||||
|
||||
### Cross-arch (ⓘ leçon du 8 sept. 2026 — « exec /docker-entrypoint.sh:
|
||||
exec format error »)
|
||||
|
||||
`exec format error` au `docker run` = l'image est pour une AUTRE
|
||||
architecture CPU que l'hôte (image arm64 buildée sur Mac → serveur amd64).
|
||||
Le Dockerfile ne contient **AUCUN `RUN`** (labels + COPY + HEALTHCHECK) :
|
||||
la cross-compilation est FAIBLE — buildx produit l'image pour n'importe
|
||||
quelle platform SANS émulation de build (constaté : build amd64 instantané
|
||||
sur l'arm64). Seul le RUN du conteneur émule (Rosetta via colima VZ / qemu
|
||||
sur l'hôte de build — sous émulation nginx journalise un
|
||||
`io_setup() failed (ENOSYS)` inoffensif : il retombe et répond 200 ; ce
|
||||
syscall existe sur un vrai Linux amd64).
|
||||
|
||||
**Règle** : le conteneur de PROD doit être buildé pour L'ARCH de l'hôte —
|
||||
deux procédures équivalentes :
|
||||
|
||||
1. **Sur le serveur cible** (recommandé — zéro registre, zéro émulation) :
|
||||
```bash
|
||||
git clone https://gitea.cloudyfy.fr/Siphonight/HormoneTrack-web && cd HormoneTrack-web
|
||||
docker compose up -d --build # arch native du serveur, toujours bon
|
||||
```
|
||||
2. **Multi-arch depuis le Mac** (push vers un registry — Docker Hub, GHCR,
|
||||
ou le registry interne du NAS) :
|
||||
```bash
|
||||
docker buildx build --platform linux/amd64,linux/arm64 -t <user>/hormonetrack-web:latest --push .
|
||||
```
|
||||
(build natif des deux archs — cf container-test.sh [platform] pour
|
||||
tester CHAQUE arch localement avant push : l'E2E complet tourne contre
|
||||
l'image cross-archémulée.)
|
||||
|
||||
**Test de l'arch cible AVANT push/déploiement** :
|
||||
`bash scripts/container-test.sh <port> linux/amd64` — c'est le test qui
|
||||
aurait attrapé l'incident « exec format error » du premier déploiement
|
||||
NAS (image arm64 seule déployée sur hôte amd64).
|
||||
|
||||
Composition de l'utilisatrice (8 sept.) : service `image:` depuis un
|
||||
registry, `env_file`/limites de ressources/réseaux externes — tout est
|
||||
inoffensif pour ce conteneur statique (aucune variable lue, no volumes).
|
||||
|
||||
## 11. Bugs potentiels évités pendant le portage
|
||||
|
||||
|
||||
@ -12,7 +12,18 @@
|
||||
# Prérequis : docker (daemon) ; node + playwright pour l'E2E final (skippé
|
||||
# sinon — cf check.sh pour l'installation).
|
||||
#
|
||||
# Usage : bash scripts/container-test.sh [port] (défaut 8975)
|
||||
# Usage : bash scripts/container-test.sh [port] [platform]
|
||||
# [port] défaut 8975
|
||||
# [platform] platform Docker optionnelle (ex. linux/amd64) — permet de
|
||||
# tester l'image pour L'HÔTE CIBLE depuis un Mac arm64 : sans
|
||||
# elle, on build+run l'arch native (arm64) ; avec platform,
|
||||
# buildx produit l'image pour CETTE platform (build natif —
|
||||
# le Dockerfile ne contient AUCUN RUN, cross-compile sans
|
||||
# émulation de build) et le run passe par l'émulation de
|
||||
# l'hôte (Rosetta/qemu). ⚠️ Le bug réel du 8 sept. —
|
||||
# « exec /docker-entrypoint.sh: exec format error » sur le
|
||||
# NAS amd64 — venait d'une image arm64 uniquement : C'EST CE
|
||||
# TEST cross-arch qui l'eût attrapé.
|
||||
#
|
||||
# ⚠️ Un SEUL invocation fait tout (leçon Android #43 : les invocations
|
||||
# rapprochées se remplacent mutuellement) et l'échec est BRUYANT (exit 1
|
||||
@ -22,9 +33,17 @@ set -euo pipefail
|
||||
cd "$(dirname "$0")/.." # racine du dépôt
|
||||
|
||||
PORT="${1:-8975}"
|
||||
PLATFORM="${2:-}"
|
||||
HOST_PORT="127.0.0.1:${PORT}"
|
||||
IMAGE="hormonetrack-web:smoke"
|
||||
CONTAINER="hrt-web-smoke"
|
||||
# Suffixe de tag par platevorme pour ne jamais mélanger les images
|
||||
TAG_SUFFIX="smoke"
|
||||
PLATFORM_ARG=()
|
||||
if [[ -n "${PLATFORM:-}" ]]; then
|
||||
TAG_SUFFIX="smoke-${PLATFORM##*/}" # linux/amd64 → smoke-amd64
|
||||
PLATFORM_ARG=(--platform "$PLATFORM")
|
||||
fi
|
||||
IMAGE="hormonetrack-web:${TAG_SUFFIX}"
|
||||
CONTAINER="hrt-web-${TAG_SUFFIX}"
|
||||
ROOM=0 # compteur d'échecs
|
||||
|
||||
fail() { echo " ✗ $1"; ROOM=$((ROOM + 1)); }
|
||||
@ -35,8 +54,8 @@ cleanup() {
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "── 1. Build de l'image ──"
|
||||
docker build -t "$IMAGE" . 2>&1 | tail -2
|
||||
echo "── 1. Build de l'image${PLATFORM:+ [${PLATFORM}]} ──"
|
||||
docker build "${PLATFORM_ARG[@]}" -t "$IMAGE" . 2>&1 | tail -2
|
||||
|
||||
echo "── 2. Run (durcissement compose : read_only + no-new-privileges) ──"
|
||||
# On teste l'image dans la configuration DURCIE de docker-compose.yml —
|
||||
@ -46,6 +65,7 @@ echo "── 2. Run (durcissement compose : read_only + no-new-privileges) ─
|
||||
# « mkdir /tmp/proxy_temp failed » (constaté au premier container-test).
|
||||
docker run -d --rm --name "$CONTAINER" \
|
||||
-p "${HOST_PORT}:8080" \
|
||||
"${PLATFORM_ARG[@]}" \
|
||||
--read-only \
|
||||
--tmpfs /var/cache/nginx --tmpfs /run --tmpfs /tmp \
|
||||
--security-opt no-new-privileges \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user