`db-init` suppose un orchestrateur qui honore `depends_on: service_completed_successfully`. Swarm l'ignore, et une pile déployée avant l'ajout du service ne le contient même pas. L'application redémarrait alors en boucle sur un refus d'authentification que le diagnostic ajouté précédemment décrivait sans que personne puisse le corriger. Elle le corrige donc elle-même au démarrage, si on lui confie les identifiants d'amorçage — et se tait sinon, pour ne pas contrarier un déploiement qui préfère les garder hors du conteneur applicatif. Le point d'entrée retire ces variables avant de lancer le serveur : le processus qui sert les requêtes ne les voit jamais. Le branchement create/alter se fait côté client et non dans un bloc `DO` : le corps d'un `DO` est une chaîne littérale, où `$1` n'est pas un paramètre de requête. L'échappement du mot de passe est confié à `quote_literal`, et le nom de rôle est refusé s'il n'a pas la forme d'un identifiant. Éprouvé sous authentification scram réelle : après réalignement, l'ancien mot de passe est refusé et le nouveau accepté, le rôle reste NOSUPERUSER NOBYPASSRLS et devient propriétaire de la base. Au passage, `withTenant` pose un budget de transaction explicite. Tout accès aux données passe par lui, si bien que le défaut Prisma de 5 s plafonnait en réalité chaque requête de l'application, et l'échec se présentait en `P2028` qui ne désigne ni la requête ni la cause. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
67 lines
2.8 KiB
Docker
67 lines
2.8 KiB
Docker
# syntax=docker/dockerfile:1
|
|
|
|
FROM node:22-alpine AS base
|
|
RUN corepack enable
|
|
WORKDIR /app
|
|
|
|
# ---- dependencies -----------------------------------------------------------
|
|
FROM base AS deps
|
|
COPY package.json pnpm-lock.yaml ./
|
|
COPY prisma ./prisma
|
|
RUN pnpm install --frozen-lockfile
|
|
|
|
# ---- build ------------------------------------------------------------------
|
|
FROM base AS build
|
|
COPY --from=deps /app/node_modules ./node_modules
|
|
COPY . .
|
|
RUN pnpm db:generate && pnpm build
|
|
|
|
# CLI Prisma pour les migrations au démarrage, installée à plat.
|
|
#
|
|
# `node_modules/prisma` de pnpm ne se recopie pas : ses dépendances vivent dans
|
|
# le magasin virtuel `.pnpm`, sous un répertoire au nom haché. En prélever
|
|
# quelques répertoires à la main donne une CLI qui se lance et s'arrête sur
|
|
# « Cannot find module '@prisma/config' ». npm produit une disposition plate,
|
|
# copiable telle quelle.
|
|
#
|
|
# La version est lue dans package.json : la figer ici la ferait diverger au
|
|
# premier changement.
|
|
RUN PRISMA_VERSION="$(node -p "require('/app/package.json').devDependencies.prisma")" \
|
|
&& npm install --prefix /migrator --no-save --no-audit --no-fund "prisma@${PRISMA_VERSION}"
|
|
|
|
# ---- runtime ----------------------------------------------------------------
|
|
FROM base AS runner
|
|
ENV NODE_ENV=production
|
|
|
|
RUN addgroup --system --gid 1001 nodejs \
|
|
&& adduser --system --uid 1001 --ingroup nodejs nextjs
|
|
|
|
# Tout ce qui sert aux migrations vit à part, dans /migrator : modules, schéma
|
|
# et fichier de configuration.
|
|
#
|
|
# Les superposer aux modules de l'application les ferait entrer en collision —
|
|
# la sortie `standalone` de pnpm porte `react` en lien symbolique vers son
|
|
# magasin interne, là où l'installation npm de la CLI l'apporte en répertoire
|
|
# réel. Deux arbres séparés n'ont rien à s'écraser.
|
|
COPY --from=build --chown=nextjs:nodejs /migrator/node_modules /migrator/node_modules
|
|
COPY --from=build --chown=nextjs:nodejs /app/prisma /migrator/prisma
|
|
COPY --from=build --chown=nextjs:nodejs /app/prisma.config.ts /migrator/prisma.config.ts
|
|
|
|
# `output: standalone` emits a server bundle carrying only the modules it uses.
|
|
COPY --from=build --chown=nextjs:nodejs /app/.next/standalone ./
|
|
COPY --from=build --chown=nextjs:nodejs /app/.next/static ./.next/static
|
|
COPY --from=build --chown=nextjs:nodejs /app/public ./public
|
|
COPY --chown=nextjs:nodejs docker/entrypoint.sh ./docker/entrypoint.sh
|
|
COPY --chown=nextjs:nodejs docker/bootstrap-role.mjs ./docker/bootstrap-role.mjs
|
|
|
|
# Créé dans l'image, et non laissé au montage : un volume nommé hérite du
|
|
# propriétaire du répertoire qu'il recouvre, et sans cela l'application —
|
|
# qui ne tourne pas en root — ne pourrait pas y écrire.
|
|
RUN mkdir -p /data/documents /secrets && chown -R nextjs:nodejs /data /secrets
|
|
|
|
USER nextjs
|
|
EXPOSE 3000
|
|
ENV PORT=3000 HOSTNAME=0.0.0.0
|
|
|
|
CMD ["./docker/entrypoint.sh"]
|