# syntax=docker/dockerfile:1.7 FROM node:22-alpine AS builder WORKDIR /app # Alpine needs build tools for better-sqlite3 native module. # vips-dev provides libvips + libheif for sharp (incl. HEIC input from iOS). RUN apk add --no-cache python3 make g++ libc6-compat vips-dev COPY package*.json ./ # --ignore-scripts vermeidet eine Race-Condition: sharp's postinstall checkt, # ob seine Plattform-Prebuilt-Binary (@img/sharp-linuxmusl-arm64) schon im # node_modules liegt. Bei parallelem Install ist sie das mitunter nicht, und # sharp fällt auf "build from source" zurück — das scheitert, weil wir # node-addon-api nicht haben. Mit --ignore-scripts + npm rebuild danach # sind alle Deps garantiert fertig installiert, bevor postinstall läuft. RUN npm ci --ignore-scripts --include=optional RUN npm rebuild COPY . . RUN npm run build # Clean re-install statt npm prune. Grund: package-lock.json wird auf dem Dev- # System (Windows) generiert, dabei markiert npm die linux-musl-arm64-Prebuilts # als "dev": true, obwohl sie für's Runtime gebraucht werden. npm prune --omit=dev # würde sie entfernen. Ein Fresh-Install mit --omit=dev installiert dagegen nur # das, was für's Runtime nötig ist, inkl. matchenden Prebuilts. RUN rm -rf node_modules \ && npm ci --ignore-scripts --omit=dev --include=optional \ && npm rebuild FROM node:22-alpine AS runner WORKDIR /app RUN apk add --no-cache libc6-compat COPY --from=builder /app/build ./build COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/package.json ./package.json ENV NODE_ENV=production ENV HOST=0.0.0.0 ENV PORT=3000 ENV DATABASE_PATH=/data/kochwas.db ENV IMAGE_DIR=/data/images VOLUME ["/data"] EXPOSE 3000 HEALTHCHECK --interval=15s --timeout=5s --retries=3 --start-period=20s --start-interval=2s \ CMD wget -qO- http://127.0.0.1:3000/api/health > /dev/null || exit 1 CMD ["node", "build/index.js"]