Repository navigation
Expand file tree
/
Copy pathDockerfile
More file actions
140 lines (123 loc) · 6.68 KB
/
Copy pathDockerfile
File metadata and controls
140 lines (123 loc) · 6.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# syntax=docker/dockerfile:1.7
# Piloti — image multi-stage Next.js 16 + Prisma 7 + better-sqlite3.
#
# Cibles :
# - deps : `pnpm install` (mise en cache)
# - builder : `prisma generate` + `next build` (output: 'standalone')
# - migrate : conteneur one-shot qui applique les migrations DB
# - runner : image finale minimale, USER non-root
#
# Build : `docker compose build`
# Run : `docker compose up -d`
# Version de l'image Node, épinglée. La valeur réelle vient de NODE_IMAGE_TAG
# dans le fichier .env passé à docker compose (voir .env.example) ; ce défaut
# ne sert que pour un `docker build` lancé à la main.
ARG NODE_IMAGE_TAG=22.23.3-alpine3.24
# -----------------------------------------------------------------------------
# Base : Node Alpine + pnpm + outils de compilation native (better-sqlite3)
# -----------------------------------------------------------------------------
FROM node:${NODE_IMAGE_TAG} AS base
RUN apk add --no-cache libc6-compat python3 make g++ \
&& corepack enable \
&& corepack prepare pnpm@latest-11 --activate
WORKDIR /app
ENV PNPM_HOME=/pnpm
ENV PATH=$PNPM_HOME:$PATH
# -----------------------------------------------------------------------------
# Deps : installe toutes les dépendances (dev incluses, on en aura besoin pour
# Prisma CLI et tsx dans la cible migrate)
# -----------------------------------------------------------------------------
FROM base AS deps
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm install --frozen-lockfile
# -----------------------------------------------------------------------------
# Builder : génère le client Prisma, compile Next.js en mode standalone
# -----------------------------------------------------------------------------
FROM base AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
# `prisma generate` ne se connecte pas à la DB mais `prisma.config.ts` exige
# DATABASE_URL via env() — on injecte un placeholder pour faire passer le build.
# La vraie URL est passée au runtime par docker-compose (file:/data/piloti.db).
ENV DATABASE_URL=file:/tmp/build-placeholder.db
# `auth.ts` plante au load (S-4) si BETTER_AUTH_SECRET absent, et Next build
# évalue les modules en page-data collection → on met un placeholder build.
# La vraie valeur vient de docker-compose --env-file au runtime.
ENV BETTER_AUTH_SECRET=build-placeholder-not-used-at-runtime
RUN pnpm prisma generate
RUN pnpm build
# sharp : le file-tracing de Next ne suit que les `require()` JavaScript. Il
# embarque donc le binding `sharp-linuxmusl-x64.node` mais PAS la bibliothèque
# native `libvips-cpp.so` que celui-ci charge par `dlopen` — le module échoue au
# chargement dans l'image finale ("ERR_DLOPEN_FAILED: libvips-cpp.so.8.18.3"),
# et TOUS les uploads d'images échouent (lieux, annonces, incidents, frais).
# On met les paquets natifs de côté ici pour les recopier dans le runner ; le
# glob reste versionless afin de survivre à une montée de version de sharp.
RUN mkdir -p /sharp-native \
&& cp -r /app/node_modules/.pnpm/@img+sharp-libvips-linuxmusl-x64@* /sharp-native/ \
&& cp -r /app/node_modules/.pnpm/@img+sharp-linuxmusl-x64@* /sharp-native/ \
&& test -n "$(find /sharp-native -name 'libvips-cpp.so*' -print -quit)"
# -----------------------------------------------------------------------------
# Migrate : conteneur léger qui applique `prisma migrate deploy` au démarrage,
# puis exit 0. compose le lance avant l'app (depends_on + service_completed_*).
# -----------------------------------------------------------------------------
FROM base AS migrate
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/prisma ./prisma
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml prisma.config.ts ./
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Le runner tourne en UID 1001 (nextjs). On crée la DB avec ce uid pour qu'elle
# soit writable après migration. `prisma migrate deploy` lit DATABASE_URL et
# crée le fichier — on chown ensuite tout le dossier monté.
CMD ["sh", "-c", "pnpm prisma migrate deploy && chown -R 1001:1001 /data"]
# -----------------------------------------------------------------------------
# Runner : image finale, minimale, USER non-root
# -----------------------------------------------------------------------------
FROM node:${NODE_IMAGE_TAG} AS runner
RUN apk add --no-cache libc6-compat wget
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
# User non-root (1001:1001)
RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 --ingroup nodejs nextjs
# Standalone : minimal node_modules + server.js
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
# Remet la lib native de sharp que le tracing a laissée de côté (cf. builder).
COPY --from=builder --chown=nextjs:nodejs /sharp-native/ ./node_modules/.pnpm/
# Dossier prêt à recevoir les uploads (monté en volume). HORS de `public/` :
# un fichier sous `public/` est servi par le serveur statique de Next sans
# passer par `/uploads/[...path]`, donc sans contrôle de session (cf. lib/upload.ts).
RUN mkdir -p /app/var/uploads && chown -R nextjs:nodejs /app/var/uploads
USER nextjs
EXPOSE 3000
# Healthcheck via la route /api/health (Phase 2)
HEALTHCHECK --interval=30s --timeout=3s --start-period=15s --retries=3 \
CMD wget -qO- http://localhost:3000/api/health || exit 1
CMD ["node", "server.js"]
# -----------------------------------------------------------------------------
# Dev : image qui monte le code en volume et lance `pnpm dev`. Utilisée par
# docker-compose.dev.yml. Pour les vrais dev workflows on lance `pnpm dev`
# en local — ce target sert si on veut reproduire l'env conteneurisé.
# -----------------------------------------------------------------------------
FROM base AS dev
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Le client Prisma doit être généré dans node_modules avant le démarrage,
# sinon `pnpm dev` plante avec "Cannot find module '.prisma/client/default'".
# DATABASE_URL placeholder — `prisma generate` ne se connecte pas à la DB.
ENV DATABASE_URL=file:/tmp/build-placeholder.db
RUN pnpm prisma generate
ENV NODE_ENV=development
EXPOSE 3000
# Au démarrage : régénère le client Prisma (garantit qu'il colle au schéma même
# après un down/up qui recrée le volume node_modules), applique les migrations,
# puis lance Next. `generate` (~150ms) et `migrate deploy` sont idempotents.
CMD ["sh", "-c", "pnpm prisma generate && pnpm prisma migrate deploy && pnpm dev"]