forked from jappel/leistungsbilanz-ts
The development stack was running permanently on a server: polling file watchers, a healthcheck that rendered a full page every five seconds and no memory limit grew next dev to 10 GB and pushed the host into swap. - add compose.prod.yaml running compiled output in separate api/web services - make the Dockerfile multi-stage with dev and prod targets, prune devDependencies and run the runtime image as node instead of root - bake API_INTERNAL_URL at build time; next start ignores it at runtime because rewrite destinations are resolved into routes-manifest.json - drop CHOKIDAR_USEPOLLING and WATCHPACK_POLLING - probe /health instead of /, which redirects to /projects and made every healthcheck render the project list - give every service a memory limit and forbid swap in production - rename the development compose project to leistungsbilanz-dev so its down command cannot target the production stack - bind development ports to localhost - close the http server and the SQLite handle on SIGTERM/SIGINT - match probe user agents in the navigation log filter; Node's fetch sends one, so the previous check never matched - exit docker-start.sh when either supervised process dies - remove drizzle.config.js, a compiled copy drizzle-kit never reads, and the pre-Next index.html/styles.css leftovers Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
51 lines
2.1 KiB
Docker
Executable file
51 lines
2.1 KiB
Docker
Executable file
# syntax=docker/dockerfile:1
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# deps: complete dependency tree, shared by the build and the dev target.
|
|
# Stays on the full node image because better-sqlite3 needs a toolchain.
|
|
# ---------------------------------------------------------------------------
|
|
FROM node:22 AS deps
|
|
WORKDIR /app
|
|
COPY package*.json ./
|
|
RUN npm ci
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# dev: watch-mode target used by compose.yaml. Keeps devDependencies so
|
|
# tsx, drizzle-kit and next dev are available. Sources come from bind mounts.
|
|
# ---------------------------------------------------------------------------
|
|
FROM deps AS dev
|
|
ENV NODE_ENV=development
|
|
COPY . .
|
|
RUN mkdir -p data
|
|
EXPOSE 3000 3001
|
|
CMD ["npm", "run", "dev:api"]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# build: compile the API to dist/ and the frontend to .next/, then drop
|
|
# devDependencies so the runtime stage carries only what it executes.
|
|
# ---------------------------------------------------------------------------
|
|
FROM deps AS build
|
|
ENV NEXT_TELEMETRY_DISABLED=1
|
|
# Next.js resolves next.config.mjs rewrites at build time and writes the literal
|
|
# destination into .next/routes-manifest.json. Setting API_INTERNAL_URL only at
|
|
# runtime has no effect on `next start`, so the API address of the target
|
|
# topology has to be known here. Server components read the variable at runtime.
|
|
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: runtime image. node:22-slim shares the Debian release of the build
|
|
# stage, so the compiled better-sqlite3 binding stays loadable.
|
|
# ---------------------------------------------------------------------------
|
|
FROM node:22-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"]
|