All checks were successful
ci/woodpecker/push/ci Pipeline was successful
The .npmrc file contains supportedArchitectures settings to force pnpm to install glibc x64 binaries for native modules like matrix-sdk-crypto-nodejs. Without copying this file into the Docker image, pnpm defaults to the platform's native behavior which may skip or install incorrect binaries.
145 lines
5.3 KiB
Docker
145 lines
5.3 KiB
Docker
# Base image for all stages
|
|
# Uses Debian slim (glibc) for consistency with API/orchestrator and to prevent
|
|
# future native addon compatibility issues with Alpine's musl libc.
|
|
FROM git.mosaicstack.dev/mosaic/node-base:24-slim AS base
|
|
|
|
# Install pnpm globally
|
|
RUN corepack enable && corepack prepare pnpm@10.27.0 --activate
|
|
|
|
# Set working directory
|
|
WORKDIR /app
|
|
|
|
# Copy monorepo configuration files
|
|
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./
|
|
COPY turbo.json ./
|
|
|
|
# ======================
|
|
# Dependencies stage
|
|
# ======================
|
|
FROM base AS deps
|
|
|
|
# Copy all package.json files for workspace resolution
|
|
COPY packages/shared/package.json ./packages/shared/
|
|
COPY packages/ui/package.json ./packages/ui/
|
|
COPY packages/config/package.json ./packages/config/
|
|
COPY apps/web/package.json ./apps/web/
|
|
|
|
# Copy npm configuration for native binary architecture hints
|
|
COPY .npmrc ./
|
|
|
|
# Install dependencies (no cache mount — Kaniko builds are ephemeral in CI)
|
|
RUN pnpm install --frozen-lockfile
|
|
|
|
# ======================
|
|
# Production dependencies stage
|
|
# ======================
|
|
FROM base AS prod-deps
|
|
|
|
# Copy all package.json files for workspace resolution
|
|
COPY packages/shared/package.json ./packages/shared/
|
|
COPY packages/ui/package.json ./packages/ui/
|
|
COPY packages/config/package.json ./packages/config/
|
|
COPY apps/web/package.json ./apps/web/
|
|
|
|
# Copy npm configuration for native binary architecture hints
|
|
COPY .npmrc ./
|
|
|
|
# Install production dependencies only
|
|
RUN pnpm install --frozen-lockfile --prod
|
|
|
|
# ======================
|
|
# Builder stage
|
|
# ======================
|
|
FROM base AS builder
|
|
|
|
# Copy root node_modules from deps
|
|
COPY --from=deps /app/node_modules ./node_modules
|
|
|
|
# Copy all source code FIRST
|
|
COPY packages ./packages
|
|
COPY apps/web ./apps/web
|
|
|
|
# Then copy workspace node_modules from deps (these go AFTER source to avoid being overwritten)
|
|
COPY --from=deps /app/packages/shared/node_modules ./packages/shared/node_modules
|
|
COPY --from=deps /app/packages/ui/node_modules ./packages/ui/node_modules
|
|
COPY --from=deps /app/packages/config/node_modules ./packages/config/node_modules
|
|
COPY --from=deps /app/apps/web/node_modules ./apps/web/node_modules
|
|
|
|
# Build arguments for Next.js
|
|
ARG NEXT_PUBLIC_API_URL
|
|
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
|
|
|
|
# Debug: Show what we have before building
|
|
RUN echo "=== Pre-build directory structure ===" && \
|
|
echo "--- packages/config/typescript ---" && ls -la packages/config/typescript/ && \
|
|
echo "--- packages/shared (top level) ---" && ls -la packages/shared/ && \
|
|
echo "--- packages/ui (top level) ---" && ls -la packages/ui/ && \
|
|
echo "--- apps/web (top level) ---" && ls -la apps/web/
|
|
|
|
# Build the web app and its dependencies using TurboRepo
|
|
# This ensures @mosaic/shared and @mosaic/ui are built first
|
|
# Disable turbo cache temporarily to ensure fresh build
|
|
RUN pnpm turbo build --filter=@mosaic/web --force
|
|
|
|
# Debug: Show what was built
|
|
RUN echo "=== Post-build directory structure ===" && \
|
|
echo "--- packages/shared/dist ---" && ls -la packages/shared/dist/ 2>/dev/null || echo "NO dist in shared" && \
|
|
echo "--- packages/ui/dist ---" && ls -la packages/ui/dist/ 2>/dev/null || echo "NO dist in ui" && \
|
|
echo "--- apps/web/.next ---" && ls -la apps/web/.next/ 2>/dev/null || echo "NO .next in web"
|
|
|
|
# Ensure public directory exists (may be empty)
|
|
RUN mkdir -p ./apps/web/public
|
|
|
|
# ======================
|
|
# Production stage
|
|
# ======================
|
|
FROM git.mosaicstack.dev/mosaic/node-base:24-slim AS production
|
|
|
|
# dumb-init, ca-certificates pre-installed in base image
|
|
|
|
# Single RUN to minimize Kaniko filesystem snapshots (each RUN = full snapshot)
|
|
# - Remove npm/npx to reduce image size (not used in production)
|
|
# - Create non-root user
|
|
RUN rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx \
|
|
&& groupadd -g 1001 nodejs && useradd -m -u 1001 -g nodejs nextjs
|
|
|
|
WORKDIR /app
|
|
|
|
# Copy node_modules from builder (includes all dependencies in pnpm store)
|
|
COPY --from=prod-deps --chown=nextjs:nodejs /app/node_modules ./node_modules
|
|
|
|
# Copy built packages (includes dist/ directories)
|
|
COPY --from=builder --chown=nextjs:nodejs /app/packages ./packages
|
|
|
|
# Copy built web application
|
|
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next ./apps/web/.next
|
|
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public
|
|
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/next.config.ts ./apps/web/
|
|
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/package.json ./apps/web/
|
|
# Copy app's node_modules which contains symlinks to root node_modules
|
|
COPY --from=prod-deps --chown=nextjs:nodejs /app/apps/web/node_modules ./apps/web/node_modules
|
|
|
|
# Set working directory to web app
|
|
WORKDIR /app/apps/web
|
|
|
|
# Switch to non-root user
|
|
USER nextjs
|
|
|
|
# Expose web port (default 3000, can be overridden via PORT env var)
|
|
EXPOSE ${PORT:-3000}
|
|
|
|
# Environment variables
|
|
ENV NODE_ENV=production
|
|
ENV HOSTNAME="0.0.0.0"
|
|
ENV PATH="/app/apps/web/node_modules/.bin:${PATH}"
|
|
|
|
# Health check uses PORT env var (set by docker-compose or defaults to 3000)
|
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
|
CMD node -e "const port = process.env.PORT || 3000; require('http').get('http://localhost:' + port, (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
|
|
|
|
# Use dumb-init to handle signals properly
|
|
ENTRYPOINT ["dumb-init", "--"]
|
|
|
|
# Start the application
|
|
CMD ["next", "start"]
|