Running the stack on built output stopped the idle CPU load, but the remaining findings from the deployment report were still open. The Dockerfile is now multi-stage. The prod target runs on node:24-slim as the "node" user instead of root and carries only its runtime dependencies; "npm prune --omit=dev" drops tsx, drizzle-kit and typescript. The migration scripts need drizzle-orm and better-sqlite3, both regular dependencies, so they keep working. The dev target keeps devDependencies for compose.dev.yaml. Both compose files get a mem_limit. The server stack also sets memswap_limit to the same value, so a leak lets the OOM killer replace the container instead of pushing the host into swap. The Express API is no longer published on the host: it has no authentication and is reached through the Next.js rewrite. Development ports are bound to the loopback interface. Services drop all capabilities and run with no-new-privileges. SIGTERM and SIGINT now close the HTTP server and the SQLite handle and exit, instead of only logging the signal and waiting for the container's SIGKILL ten seconds later. server.closeIdleConnections() releases the keep-alive sockets the Next.js server holds, which would otherwise keep server.close() pending for the whole grace period. The compose start commands exec into node, because otherwise sh stays the foreground process and the signal never reaches it. Delete scripts/docker-start.sh rather than fixing its unsupervised background API: both compose stacks set their own command, so the single-container entrypoint has no caller left. Also remove drizzle.config.js (a stray tsc artifact drizzle-kit never reads) and the pre-Next index.html and styles.css. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
56 lines
2.4 KiB
Docker
56 lines
2.4 KiB
Docker
# syntax=docker/dockerfile:1
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# deps: vollstaendiger Abhaengigkeitsbaum, gemeinsam genutzt von "dev" und
|
|
# "build". Bleibt auf dem vollen node-Image, weil better-sqlite3 beim
|
|
# Installieren eine Toolchain braucht.
|
|
# ---------------------------------------------------------------------------
|
|
FROM node:24 AS deps
|
|
WORKDIR /app
|
|
COPY package*.json ./
|
|
RUN npm ci
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# dev: Ziel fuer compose.dev.yaml. Behaelt devDependencies, damit tsx,
|
|
# drizzle-kit und "next dev" verfuegbar sind. Die Quellen kommen zur Laufzeit
|
|
# ueber Bind-Mounts, das COPY hier ist nur der Ausgangsstand.
|
|
# ---------------------------------------------------------------------------
|
|
FROM deps AS dev
|
|
ENV NODE_ENV=development
|
|
COPY . .
|
|
RUN mkdir -p data
|
|
EXPOSE 3000 3001
|
|
CMD ["npm", "run", "dev:api"]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# build: API nach dist/ und Frontend nach .next/ uebersetzen, danach die
|
|
# devDependencies entfernen, damit das Laufzeit-Image nur noch traegt, was es
|
|
# auch ausfuehrt. Die Migrationsskripte kommen mit drizzle-orm und
|
|
# better-sqlite3 aus, beides sind regulaere dependencies.
|
|
# ---------------------------------------------------------------------------
|
|
FROM deps AS build
|
|
ENV NEXT_TELEMETRY_DISABLED=1
|
|
# next build schreibt die Rewrite-Ziele aus next.config.mjs fest in
|
|
# .next/routes-manifest.json, "next start" kann eine andere API-Adresse
|
|
# spaeter nicht mehr uebernehmen. Der Wert muss hier bekannt sein, nicht erst
|
|
# zur Laufzeit. Server-Komponenten lesen die Variable zur Laufzeit.
|
|
ARG API_INTERNAL_URL=http://localhost:3000
|
|
ENV API_INTERNAL_URL=$API_INTERNAL_URL
|
|
COPY . .
|
|
RUN npm run build:api && npm run build:web
|
|
RUN npm prune --omit=dev
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# prod: Laufzeit-Image. node:24-slim teilt sich das Debian-Release mit der
|
|
# build-Stufe, damit das kompilierte better-sqlite3-Binding ladbar bleibt.
|
|
# Laeuft als "node" (UID 1000) statt als root.
|
|
# ---------------------------------------------------------------------------
|
|
FROM node:24-slim AS prod
|
|
ENV NODE_ENV=production
|
|
ENV NEXT_TELEMETRY_DISABLED=1
|
|
WORKDIR /app
|
|
COPY --from=build --chown=node:node /app ./
|
|
RUN mkdir -p data && chown node:node data
|
|
USER node
|
|
EXPOSE 3000 3001
|
|
CMD ["node", "dist/server/index.js"]
|