rubis/Dockerfile.api
ordinarthur dd93249362
All checks were successful
Build & Deploy Web / build-and-deploy (push) Successful in 1m16s
Build & Deploy API / build-and-deploy (push) Successful in 1m32s
refactor(deploy): split monolithique en 2 services (rubis-web nginx + rubis-api Node)
Avant : une seule image (Dockerfile.app) qui bundle AdonisJS + SPA static.
Après : deux images, deux deployments, deux workflows CI avec path filters
indépendants.

Architecture
- rubis-web (NodePort 30110, exposé via Traefik)
  · nginx-alpine + SPA Vite dist + nginx.conf
  · sert /assets/* (cache 1y immutable), / (try_files index.html SPA fallback)
  · reverse-proxy /api/* → rubis-api.rubis.svc.cluster.local:3333
- rubis-api (ClusterIP, accessible uniquement depuis le cluster)
  · AdonisJS V7 + workers BullMQ dans le même process
  · init-container migrate (idempotent, depuis build/)
  · /api/v1/health pour les probes K3s + healthcheck Docker
- rubis-redis (ClusterIP, inchangé)

Bénéfices
- Build/deploy indépendants : changement front ne reconstruit pas l'API,
  changement API ne reconstruit pas le SPA
- nginx en frontal donne du gzip + cache long sur les assets fingerprintés
- API n'expose plus de surface publique (defense in depth)
- Routes plus simples : on retire le wildcard SPA fallback dans
  start/routes.ts (nginx s'en charge), on retire @adonisjs/static aurait
  été cohérent mais on le garde pour minimiser les diffs

Files
- Dockerfile.api (replaces Dockerfile.app, Node-only)
- Dockerfile.web (new, nginx)
- apps/web/nginx.conf (new)
- k3s/app/api.yml (replaces deployment.yml + service.yml, ClusterIP)
- k3s/app/web.yml (new, NodePort 30110)
- .gitea/workflows/deploy-{api,web}.yml (replaces deploy-app.yml)
- /api/v1/health route ajoutée

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 02:58:25 +02:00

77 lines
3.0 KiB
Docker

# syntax=docker/dockerfile:1.7
# =============================================================================
# Rubis — image API (AdonisJS V7, Node 22)
# Sert /api/v1/* en interne au cluster (ClusterIP rubis-api:3333).
# Le SPA est servi par rubis-web (nginx) en frontal qui proxy /api/* ici.
# =============================================================================
#
# Workers BullMQ tournent dans le même process Node (cf. start/queue.ts).
# Migrations exécutées par init-container avant le serveur (cf. k3s/app/api.yml).
#
# Particularités :
# - On bypasse @poppinss/ts-exec en appelant ace via tsx (ERR_UNKNOWN_FILE
# _EXTENSION sinon, swc/core race au boot)
# - --ignore-ts-errors car tests/bootstrap.ts réfère un type généré tardif
# =============================================================================
ARG NODE_VERSION=22.13.1
ARG PNPM_VERSION=10.0.0
# -----------------------------------------------------------------------------
# base — node + pnpm + tini
# -----------------------------------------------------------------------------
FROM node:${NODE_VERSION}-alpine AS base
ARG PNPM_VERSION
RUN apk add --no-cache libc6-compat tini && \
corepack enable && \
corepack prepare pnpm@${PNPM_VERSION} --activate
WORKDIR /repo
# -----------------------------------------------------------------------------
# deps — install workspace (avec devDeps pour le build)
# -----------------------------------------------------------------------------
FROM base AS deps
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json tsconfig.base.json ./
COPY apps/api/package.json ./apps/api/
COPY packages/shared/package.json ./packages/shared/
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile
# -----------------------------------------------------------------------------
# build — ace build via tsx
# -----------------------------------------------------------------------------
FROM deps AS build
COPY packages/shared ./packages/shared
COPY apps/api ./apps/api
RUN cd apps/api && pnpm exec tsx ace.js build --ignore-ts-errors
# Prune devDeps (les workspace symlinks restent).
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
pnpm install --prod --frozen-lockfile=false
# -----------------------------------------------------------------------------
# runner — runtime minimal, user non-root
# -----------------------------------------------------------------------------
FROM base AS runner
RUN addgroup -g 1001 -S nodejs && adduser -S adonis -u 1001
ENV NODE_ENV=production \
HOST=0.0.0.0 \
PORT=3333 \
LOG_LEVEL=info
WORKDIR /app
COPY --from=build --chown=adonis:nodejs /repo /app
USER adonis
WORKDIR /app/apps/api
EXPOSE 3333
# /api/v1/health renvoie 200 quand le serveur + DB sont up.
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD wget -qO- http://127.0.0.1:3333/api/v1/health >/dev/null 2>&1 || exit 1
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "build/bin/server.js"]