# =============================================== # Stage 1: Dependencies Installation # =============================================== FROM node:20-alpine AS dependencies # Install build dependencies RUN apk add --no-cache python3 make g++ libc6-compat # Set working directory WORKDIR /app # Copy package files COPY package*.json ./ COPY tsconfig*.json ./ # Install all dependencies (including dev for build) RUN npm install --legacy-peer-deps # =============================================== # Stage 2: Build Application # =============================================== FROM node:20-alpine AS builder WORKDIR /app # Copy dependencies from previous stage COPY --from=dependencies /app/node_modules ./node_modules # Copy source code COPY . . # Build the application RUN npm run build # Remove dev dependencies to reduce size RUN npm prune --production --legacy-peer-deps # =============================================== # Stage 3: Production Image # =============================================== FROM node:20-alpine AS production # Install dumb-init for proper signal handling RUN apk add --no-cache dumb-init # Create non-root user RUN addgroup -g 1001 -S nodejs && \ adduser -S nestjs -u 1001 # Set working directory WORKDIR /app # Copy built application from builder COPY --from=builder --chown=nestjs:nodejs /app/dist ./dist COPY --from=builder --chown=nestjs:nodejs /app/node_modules ./node_modules COPY --from=builder --chown=nestjs:nodejs /app/package*.json ./ # Copy source code needed at runtime (for CSV storage path resolution) COPY --from=builder --chown=nestjs:nodejs /app/src ./src # Create logs and uploads directories RUN mkdir -p /app/logs && \ mkdir -p /app/src/infrastructure/storage/csv-storage/rates && \ chown -R nestjs:nodejs /app/logs /app/src # Switch to non-root user USER nestjs # Expose port EXPOSE 4000 # Health check HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD node -e "require('http').get('http://localhost:4000/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))" # Set environment variables ENV NODE_ENV=production \ PORT=4000 # Use dumb-init to handle signals properly ENTRYPOINT ["dumb-init", "--"] # Start the application CMD ["node", "dist/main"]