CI / check (push) Successful in 29s
CI / tests-integration (push) Successful in 2m13s
CI / tests-unit (push) Successful in 2m28s
CI / tests-imaging-browsers (push) Successful in 2m29s
CI / tests-quality (push) Successful in 55s
CI / tests-ui (push) Successful in 5m10s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m47s
The Docker build was slower than it needed to be and could drift away from the lockfile. Three separate causes, fixed together. The image installed a pinned [email protected].1 while package.json pins 12.11.2 through `packageManager`. pnpm silently self-managed the difference at build time: it downloaded the right version into an uncached location and never verified the sha512 hash. Install corepack instead and let it resolve version and hash from the pin, so the image can no longer diverge and a tampered tarball is rejected. The resolved pnpm lives in COREPACK_HOME inside the image, so the migrations image still runs pnpm offline (`docker run --entrypoint pnpm ... db:migrate`). The pnpm store cache-mount pointed at /root/.local/share/pnpm/store, but pnpm keeps its store in $PNPM_HOME/store/v11. The mount was a no-op: every build re-downloaded all 493 packages ("reused 0, downloaded 493"). Mounting the store where pnpm actually keeps it turns that into "reused 493, downloaded 0". The build context carried backups/ (232MB of rotating database dumps) and public/vendor/ (regenerated by `pnpm assets:editor` from node_modules). Both grew the context and invalidated the `COPY . .` layer on every daily backup rotation, forcing a full Next.js rebuild. Excluding them takes the context from 276MB to 23MB. Compose now also exports the build cache to .docker-cache/cms and imports it again, so the cache survives `scripts/docker-prune.sh`, which trims the daemon cache to 4GB after every deploy. Verified by pruning the entire daemon cache: the next build restored every layer from the local export and downloaded nothing. Also: byparr's floating `:latest` tag is now pulled on every start, the migrations build in scripts/docker-update.sh imports the same local cache, the README no longer claims the build needs host networking or an iptables-disabled daemon, the pnpm rationale in renovate.json reflects that Docker follows the pin automatically, and contract tests pin the new invariants so the store path cannot drift back.
97 lines
4.3 KiB
YAML
97 lines
4.3 KiB
YAML
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Next.js CMS — single slot on port 3002
|
|
#
|
|
# ── Eigenaar van poort 3002 ─────────────────────────────────────────────────
|
|
# Deze repo kent twee deploy-paden die allebei op poort 3002 willen:
|
|
# * `scripts/ci-deploy.sh` (blue/green, docker run) — de eigenaar op een
|
|
# CI-host. Elke push naar main bouwt daar een nieuwe image, draait de
|
|
# migrations en zet nginx pas om na health + e2e + imaging.
|
|
# * deze compose-`cms`-service — bedoeld voor een LOSSE host zonder CI.
|
|
#
|
|
# Ze kunnen niet naast elkaar draaien: wie op 3002 zit, blokkeert de ander met
|
|
# `EADDRINUSE`. Daarom staat `cms` achter een profile. Een bloot
|
|
# `docker compose up -d` start dus alleen byparr en kan nooit de live CI-release
|
|
# van de site drukken. De service start alleen als je hem expliciet noemt
|
|
# (`docker compose up -d cms`, `docker compose build cms`, ...): Compose schakelt
|
|
# het profile van een expliciet genoemde service vanzelf in. Op een CI-host wil
|
|
# je dat dus juist NOOIT doen.
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
x-cms: &cms
|
|
image: epicnext-cms:${CMS_RELEASE:-local}
|
|
# No `network: host` on the build. BuildKit (v0.26, Docker 29) refuses to grant
|
|
# host networking unless every caller passes --allow=network.host, and
|
|
# `docker compose build` has no such flag — so asking for it here turned every
|
|
# rebuild into an immediate "additional privileges requested" failure, which
|
|
# left the previous release serving traffic. The build only needs outbound
|
|
# internet (apk, pnpm, next/font/google), which the default bridge provides.
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
args:
|
|
NEXT_DEPLOYMENT_ID: ${CMS_RELEASE:-unknown}
|
|
# Lokale buildcache op schijf. `scripts/docker-prune.sh` brengt de
|
|
# daemon-cache na elke deploy terug tot 4GB, waardoor de lagen van de
|
|
# vorige release verdwijnen. Deze export overleeft die prune: een rebuild
|
|
# na een lockfile-wijziging hergebruikt dan de al gedownloade packages
|
|
# (pnpm store) in plaats van ze opnieuw te downloaden.
|
|
# De map ligt binnen de buildcontext, zodat buildx een ontbrekende
|
|
# cachemap stilzwijgend negeert i.p.v. de build te laten falen; zowel
|
|
# .dockerignore als .gitignore sluiten de map uit.
|
|
cache_from:
|
|
- type=local,src=.docker-cache/cms
|
|
cache_to:
|
|
- type=local,dest=.docker-cache/cms,mode=max
|
|
# Runtime host networking IS required: nginx reaches the CMS over 127.0.0.1
|
|
# on the single port that is actually served (3002).
|
|
network_mode: host
|
|
stop_grace_period: 15s
|
|
restart: unless-stopped
|
|
env_file:
|
|
- .env
|
|
volumes:
|
|
- ./public/nitro-assets:/app/public/nitro-assets
|
|
- ./public/swf:/app/public/swf
|
|
- ./storage:/app/storage
|
|
- /var/www/Gamedata:/var/www/Gamedata
|
|
|
|
# ── Resource limits ──
|
|
mem_limit: 2g
|
|
memswap_limit: 2g
|
|
cpus: 2.0
|
|
pids_limit: 512
|
|
|
|
healthcheck:
|
|
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:'+(process.env.PORT||'3002')+'/api/health').then(r=>{process.exit(r.ok?0:1)}).catch(()=>process.exit(1))"]
|
|
interval: 15s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 40s
|
|
|
|
services:
|
|
cms:
|
|
<<: *cms
|
|
# Alleen starten als je deze host bewust compose-only beheert.
|
|
profiles: ["cms"]
|
|
container_name: epicnext-cms
|
|
environment:
|
|
- HOSTNAME=0.0.0.0
|
|
- PORT=3002
|
|
|
|
byparr:
|
|
image: ghcr.io/thephaseless/byparr:latest
|
|
# `latest` is een drijvende tag. Zonder pull_policy haalt compose de
|
|
# bestaande image nooit opnieuw op en blijft byparr hangen op de eerste
|
|
# versie die ooit werd binnengehaald.
|
|
pull_policy: always
|
|
container_name: byparr
|
|
network_mode: host
|
|
restart: unless-stopped
|
|
environment:
|
|
- LOG_LEVEL=INFO
|
|
pids_limit: 256
|
|
healthcheck:
|
|
test: ["CMD", "curl", "http://localhost:8191/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 30s |