Une application SaaS éducative nécessite une séparation stricte des données entre établissements scolaires. L'architecture multi-tenant par sous-domaine (ecole-alpha.classeo.local) permet cette isolation tout en utilisant une base de code unique. Le choix d'une résolution basée sur les sous-domaines plutôt que sur des headers ou tokens facilite le routage au niveau infrastructure (reverse proxy) et offre une UX plus naturelle où chaque école accède à "son" URL dédiée.
108 lines
3.4 KiB
Docker
108 lines
3.4 KiB
Docker
# syntax=docker/dockerfile:1
|
|
|
|
# =============================================================================
|
|
# Node.js 22 - Frontend Classeo (SvelteKit)
|
|
# =============================================================================
|
|
|
|
FROM node:22-alpine AS base
|
|
|
|
# Install pnpm
|
|
RUN corepack enable && corepack prepare pnpm@10.28.2 --activate
|
|
|
|
# Configure pnpm to use a directory inside the project (works with volume mounts)
|
|
ENV PNPM_HOME=/app/.pnpm-store
|
|
ENV PATH="$PNPM_HOME:$PATH"
|
|
|
|
# Set working directory
|
|
WORKDIR /app
|
|
|
|
# =============================================================================
|
|
# Development stage
|
|
# =============================================================================
|
|
FROM base AS dev
|
|
|
|
# Install gosu for proper user switching
|
|
ENV GOSU_VERSION=1.17
|
|
RUN set -eux; \
|
|
apk add --no-cache --virtual .gosu-deps dpkg gnupg; \
|
|
dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
|
|
wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \
|
|
chmod +x /usr/local/bin/gosu; \
|
|
gosu --version; \
|
|
gosu nobody true; \
|
|
apk del --no-network .gosu-deps
|
|
|
|
# Entrypoint: detect host UID/GID and run as matching user
|
|
# Uses gosu with UID:GID directly (no need to create user in Dockerfile)
|
|
COPY --chmod=755 <<'EOF' /usr/local/bin/docker-entrypoint.sh
|
|
#!/bin/sh
|
|
set -e
|
|
|
|
# Detect UID/GID from mounted /app directory
|
|
HOST_UID=$(stat -c %u /app)
|
|
HOST_GID=$(stat -c %g /app)
|
|
|
|
# If root owns /app, run as root (CI environment or volume not mounted)
|
|
if [ "$HOST_UID" = "0" ]; then
|
|
# Install dependencies if not present
|
|
if [ ! -d /app/node_modules ] || [ ! -f /app/node_modules/.pnpm/lock.yaml ]; then
|
|
echo "Installing pnpm dependencies..."
|
|
pnpm install
|
|
fi
|
|
exec "$@"
|
|
fi
|
|
|
|
# Fix node_modules volume ownership (Docker creates volumes as root)
|
|
# This only takes time on first run when the volume is empty
|
|
if [ -d /app/node_modules ] && [ "$(stat -c %u /app/node_modules)" = "0" ]; then
|
|
echo "Fixing node_modules ownership..."
|
|
chown -R "$HOST_UID:$HOST_GID" /app/node_modules
|
|
fi
|
|
|
|
# Ensure pnpm store directory exists and is writable
|
|
mkdir -p /app/.pnpm-store
|
|
chown "$HOST_UID:$HOST_GID" /app/.pnpm-store
|
|
|
|
# Install pnpm dependencies if not present (as host user)
|
|
if [ ! -d /app/node_modules/.pnpm ]; then
|
|
echo "Installing pnpm dependencies..."
|
|
gosu "$HOST_UID:$HOST_GID" pnpm install
|
|
fi
|
|
|
|
# Run command as host user via gosu (using UID:GID directly)
|
|
exec gosu "$HOST_UID:$HOST_GID" "$@"
|
|
EOF
|
|
|
|
EXPOSE 5173
|
|
|
|
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
|
CMD ["pnpm", "run", "dev", "--host", "0.0.0.0"]
|
|
|
|
# =============================================================================
|
|
# Build stage
|
|
# =============================================================================
|
|
FROM base AS builder
|
|
|
|
COPY package.json pnpm-lock.yaml* ./
|
|
RUN if [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile; else pnpm install; fi
|
|
|
|
COPY . .
|
|
RUN pnpm run build
|
|
|
|
# =============================================================================
|
|
# Production stage
|
|
# =============================================================================
|
|
FROM base AS prod
|
|
|
|
ENV NODE_ENV=production
|
|
|
|
COPY package.json pnpm-lock.yaml* ./
|
|
RUN if [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile --prod; else pnpm install --prod; fi
|
|
|
|
COPY --from=builder /app/build build/
|
|
COPY --from=builder /app/package.json .
|
|
|
|
EXPOSE 3000
|
|
|
|
CMD ["node", "build"]
|