Repository navigation
Expand file tree
/
Copy pathDockerfile.optimized
More file actions
103 lines (82 loc) · 3.73 KB
/
Copy pathDockerfile.optimized
File metadata and controls
103 lines (82 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#############################
# Optimized Multi-stage Docker build for SCIMServer
# Prisma 7 + Node 24 + better-sqlite3 driver adapter
# Target: Reduce image size from 1GB+ to <300MB
#############################
#############################
# Stage 1: Build web frontend (React + Vite)
#############################
FROM node:24-alpine AS web-build
WORKDIR /web
# Copy package files first for better layer caching
COPY web/package*.json ./
# Install dependencies (need all deps for build)
RUN npm ci --no-audit --no-fund && \
npm cache clean --force
# Copy source and build, clean in same layer
COPY web/ ./
RUN npm run build && \
rm -rf node_modules src public *.json *.config.* *.md .eslint* vite.config.ts
#############################
# Stage 2: Build API (NestJS) with aggressive optimization
#############################
FROM node:24-alpine AS api-build
WORKDIR /app
# openssl needed for Prisma migration engine (Rust binary used by prisma migrate deploy)
RUN apk add --no-cache openssl
# Copy package files for better caching
COPY api/package*.json ./
# Install all dependencies (prisma devDep needed at runtime for migrate deploy)
RUN npm ci --no-audit --no-fund
COPY api/ ./
COPY --from=web-build /web/dist ./public
# Prisma 7: generate client (→ src/generated/prisma/), push schema, then build
ENV DATABASE_URL="file:./data.db"
RUN npx prisma generate && \
npx prisma db push && \
npx tsc -p tsconfig.build.json
# Clean dev files; preserve prisma.config.ts (needed at runtime for prisma migrate deploy)
RUN cp prisma.config.ts /tmp/prisma.config.ts && \
rm -rf src test *.ts tsconfig*.json *.md .eslint* jest.config.js && \
mv /tmp/prisma.config.ts ./prisma.config.ts && \
npm cache clean --force && \
rm -rf /root/.npm /tmp/*
#############################
# Stage 3: Minimal runtime using distroless-like approach
#############################
FROM node:24-alpine AS runtime
WORKDIR /app
# openssl needed for Prisma migration engine at container startup
RUN apk add --no-cache openssl && \
rm -rf /var/cache/apk/* /tmp/* && \
addgroup -g 1001 -S nodejs && \
adduser -S scim -u 1001
# Production environment variables
ENV NODE_ENV=production \
PORT=8080 \
DATABASE_URL="file:./data.db" \
NODE_OPTIONS="--max_old_space_size=512"
# Create data directory for volume mount
RUN mkdir -p /app/data && chown scim:nodejs /app/data
# Copy only production artifacts (minimal footprint)
COPY --from=api-build --chown=scim:nodejs /app/node_modules ./node_modules
COPY --from=api-build --chown=scim:nodejs /app/dist ./dist
COPY --from=api-build --chown=scim:nodejs /app/public ./public
COPY --from=api-build --chown=scim:nodejs /app/prisma ./prisma
COPY --from=api-build --chown=scim:nodejs /app/prisma.config.ts ./prisma.config.ts
COPY --from=api-build --chown=scim:nodejs /app/package.json ./package.json
# Copy entrypoint script (handles migrations + hybrid storage)
COPY --chown=scim:nodejs api/docker-entrypoint.sh /app/
RUN chmod +x /app/docker-entrypoint.sh
# Remove unnecessary files (preserve effect/ which Prisma 7 depends on internally)
RUN find ./node_modules -name "*.md" -delete && \
find ./node_modules -name "*.txt" -delete && \
find ./node_modules -path "*/effect" -prune -o -name "test" -type d -exec rm -rf {} + 2>/dev/null || true && \
find ./node_modules -path "*/effect" -prune -o -name "tests" -type d -exec rm -rf {} + 2>/dev/null || true && \
find ./node_modules -name "*.map" -delete 2>/dev/null || true
USER scim
EXPOSE 8080
# Minimal health check
HEALTHCHECK --interval=60s --timeout=3s --start-period=10s --retries=2 \
CMD node -e "require('http').get('http://127.0.0.1:8080/health',r=>{process.exit(r.statusCode===200?0:1)}).on('error',()=>process.exit(1))"
CMD ["/app/docker-entrypoint.sh"]