2025-12-02 18:56:38 +09:00
|
|
|
# syntax=docker/dockerfile:1
|
2025-12-02 11:06:54 +09:00
|
|
|
# =============================================================================
|
2025-12-02 18:56:38 +09:00
|
|
|
# BFF (NestJS) Dockerfile
|
2025-12-02 11:06:54 +09:00
|
|
|
# =============================================================================
|
2025-12-02 18:56:38 +09:00
|
|
|
# Multi-stage build with BuildKit cache mounts for fast rebuilds
|
2025-12-10 16:31:18 +09:00
|
|
|
# Optimized for minimal image size, security, and fast startup
|
2025-12-02 11:06:54 +09:00
|
|
|
# =============================================================================
|
2025-08-21 15:24:40 +09:00
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
ARG NODE_VERSION=22
|
2025-12-10 13:59:41 +09:00
|
|
|
ARG PNPM_VERSION=10.25.0
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
# =============================================================================
|
2025-12-10 16:31:18 +09:00
|
|
|
# Stage 1: Dependencies (cached layer)
|
2025-12-02 11:06:54 +09:00
|
|
|
# =============================================================================
|
2025-12-10 16:31:18 +09:00
|
|
|
FROM node:${NODE_VERSION}-alpine AS deps
|
2025-12-02 11:06:54 +09:00
|
|
|
|
|
|
|
|
ARG PNPM_VERSION
|
|
|
|
|
|
2025-12-10 16:08:34 +09:00
|
|
|
# Install build dependencies in single layer
|
2025-12-02 18:56:38 +09:00
|
|
|
RUN apk add --no-cache python3 make g++ openssl libc6-compat \
|
2025-12-02 11:06:54 +09:00
|
|
|
&& corepack enable \
|
|
|
|
|
&& corepack prepare pnpm@${PNPM_VERSION} --activate
|
2025-08-20 18:02:50 +09:00
|
|
|
|
|
|
|
|
WORKDIR /app
|
|
|
|
|
|
2025-12-10 18:42:33 +09:00
|
|
|
# Copy manifests first for dependency caching (all workspace packages)
|
2025-12-02 10:05:11 +09:00
|
|
|
COPY .npmrc pnpm-workspace.yaml package.json pnpm-lock.yaml ./
|
2025-12-10 18:42:33 +09:00
|
|
|
COPY packages/domain/package.json ./packages/domain/package.json
|
|
|
|
|
COPY apps/bff/package.json ./apps/bff/package.json
|
|
|
|
|
COPY apps/portal/package.json ./apps/portal/package.json
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-10 18:42:33 +09:00
|
|
|
# Install only the packages needed for the BFF (domain + bff)
|
2025-12-02 11:06:54 +09:00
|
|
|
ENV HUSKY=0
|
2025-12-10 16:08:34 +09:00
|
|
|
RUN --mount=type=cache,id=pnpm-bff,target=/root/.local/share/pnpm/store \
|
2025-12-10 18:42:33 +09:00
|
|
|
pnpm install --frozen-lockfile --filter @customer-portal/domain... --filter @customer-portal/bff...
|
2025-08-21 15:24:40 +09:00
|
|
|
|
2025-12-10 16:31:18 +09:00
|
|
|
# =============================================================================
|
|
|
|
|
# Stage 2: Builder
|
|
|
|
|
# =============================================================================
|
|
|
|
|
FROM deps AS builder
|
|
|
|
|
|
2025-12-02 18:56:38 +09:00
|
|
|
# Copy source files
|
2025-12-02 11:06:54 +09:00
|
|
|
COPY tsconfig.json tsconfig.base.json ./
|
2025-12-02 18:56:38 +09:00
|
|
|
COPY packages/domain/ ./packages/domain/
|
2025-08-21 15:24:40 +09:00
|
|
|
COPY apps/bff/ ./apps/bff/
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-10 16:31:18 +09:00
|
|
|
# Build: domain → Prisma generate → BFF (single RUN for better layer efficiency)
|
2025-12-10 18:42:33 +09:00
|
|
|
# Clean tsbuildinfo to force fresh emit; checked-in files can skip output otherwise
|
|
|
|
|
RUN rm -f apps/bff/tsconfig*.tsbuildinfo \
|
|
|
|
|
&& pnpm --filter @customer-portal/domain build \
|
2025-12-10 16:08:34 +09:00
|
|
|
&& pnpm --filter @customer-portal/bff exec prisma generate \
|
2025-12-02 18:56:38 +09:00
|
|
|
&& pnpm --filter @customer-portal/bff build
|
2025-12-02 10:05:11 +09:00
|
|
|
|
2025-12-10 16:08:34 +09:00
|
|
|
# Create production deployment bundle with pnpm deploy
|
2025-12-02 18:56:38 +09:00
|
|
|
RUN pnpm deploy --filter @customer-portal/bff --prod /app/deploy \
|
|
|
|
|
&& cp -r apps/bff/dist deploy/dist \
|
|
|
|
|
&& cp -r apps/bff/prisma deploy/prisma \
|
|
|
|
|
&& cp -r packages/domain/dist deploy/node_modules/@customer-portal/domain/dist
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-11 10:44:21 +09:00
|
|
|
# Regenerate Prisma client in the flattened deploy layout so embedded schema path matches production
|
|
|
|
|
WORKDIR /app/deploy
|
2025-12-12 11:47:17 +09:00
|
|
|
RUN pnpm exec prisma generate --schema=prisma/schema.prisma
|
2025-12-11 10:44:21 +09:00
|
|
|
WORKDIR /app
|
|
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
# =============================================================================
|
2025-12-10 16:31:18 +09:00
|
|
|
# Stage 3: Production
|
2025-12-02 11:06:54 +09:00
|
|
|
# =============================================================================
|
|
|
|
|
FROM node:${NODE_VERSION}-alpine AS production
|
2025-08-21 15:24:40 +09:00
|
|
|
|
2025-12-11 11:25:23 +09:00
|
|
|
ARG PNPM_VERSION
|
2025-08-29 18:52:31 +09:00
|
|
|
|
2025-12-02 18:56:38 +09:00
|
|
|
LABEL org.opencontainers.image.title="Customer Portal BFF" \
|
2025-12-10 16:31:18 +09:00
|
|
|
org.opencontainers.image.description="NestJS Backend-for-Frontend API" \
|
|
|
|
|
org.opencontainers.image.vendor="Customer Portal"
|
2025-12-02 10:05:11 +09:00
|
|
|
|
2025-12-10 16:31:18 +09:00
|
|
|
# Install runtime dependencies only + security hardening
|
2025-12-10 16:08:34 +09:00
|
|
|
RUN apk add --no-cache dumb-init libc6-compat netcat-openbsd \
|
2025-12-11 11:25:23 +09:00
|
|
|
&& corepack enable \
|
|
|
|
|
&& corepack prepare pnpm@${PNPM_VERSION} --activate \
|
2025-12-02 18:56:38 +09:00
|
|
|
&& addgroup --system --gid 1001 nodejs \
|
2025-12-10 16:31:18 +09:00
|
|
|
&& adduser --system --uid 1001 nestjs \
|
|
|
|
|
# Remove apk cache and unnecessary files
|
|
|
|
|
&& rm -rf /var/cache/apk/* /tmp/* /root/.npm
|
2025-12-02 11:06:54 +09:00
|
|
|
|
2025-12-02 10:05:11 +09:00
|
|
|
WORKDIR /app
|
2025-09-01 15:11:42 +09:00
|
|
|
|
2025-12-10 16:08:34 +09:00
|
|
|
# Set Prisma schema path before copying files
|
|
|
|
|
ENV PRISMA_SCHEMA_PATH=/app/prisma/schema.prisma
|
|
|
|
|
|
2025-12-10 16:31:18 +09:00
|
|
|
# Copy deploy bundle with correct ownership in single layer
|
2025-12-02 18:56:38 +09:00
|
|
|
COPY --from=builder --chown=nestjs:nodejs /app/deploy ./
|
|
|
|
|
|
2025-12-10 16:08:34 +09:00
|
|
|
# Copy entrypoint and setup directories
|
2025-12-02 18:56:38 +09:00
|
|
|
COPY --chown=nestjs:nodejs apps/bff/scripts/docker-entrypoint.sh ./docker-entrypoint.sh
|
|
|
|
|
RUN chmod +x docker-entrypoint.sh \
|
|
|
|
|
&& mkdir -p secrets logs \
|
|
|
|
|
&& chown nestjs:nodejs secrets logs
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-10 16:31:18 +09:00
|
|
|
# Security: Run as non-root user
|
2025-08-20 18:02:50 +09:00
|
|
|
USER nestjs
|
|
|
|
|
|
2025-12-10 16:31:18 +09:00
|
|
|
# Expose BFF port
|
2025-08-20 18:02:50 +09:00
|
|
|
EXPOSE 4000
|
2025-12-02 11:06:54 +09:00
|
|
|
|
2025-12-10 16:31:18 +09:00
|
|
|
# Environment configuration
|
2025-12-02 18:56:38 +09:00
|
|
|
ENV NODE_ENV=production \
|
|
|
|
|
PORT=4000 \
|
2025-12-10 16:31:18 +09:00
|
|
|
# Node.js production optimizations
|
|
|
|
|
NODE_OPTIONS="--max-old-space-size=512"
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-10 16:31:18 +09:00
|
|
|
# Health check for container orchestration
|
2025-08-21 15:24:40 +09:00
|
|
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
2025-12-02 18:56:38 +09:00
|
|
|
CMD node -e "fetch('http://localhost:4000/health').then(r=>r.ok||process.exit(1)).catch(()=>process.exit(1))"
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-02 18:56:38 +09:00
|
|
|
ENTRYPOINT ["dumb-init", "--", "./docker-entrypoint.sh"]
|
2025-09-01 16:45:12 +09:00
|
|
|
CMD ["node", "dist/main.js"]
|