-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathDockerfile
More file actions
146 lines (115 loc) · 4.9 KB
/
Dockerfile
File metadata and controls
146 lines (115 loc) · 4.9 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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# syntax=docker/dockerfile:1
# ============================================
# Base image with security updates
# ============================================
FROM node:20-alpine AS base
# Install OpenSSL (required for Prisma) and CA certificates
# libc6-compat is sometimes needed for compatibility with certain libraries
RUN apk add --no-cache openssl ca-certificates libc6-compat
# ============================================
# Stage 1: Install dependencies + Prisma client
# ============================================
FROM base AS deps
WORKDIR /app
ARG PRISMA_PROVIDER=sqlite
ARG DATABASE_URL=file:./data/atlantis.db
ENV PRISMA_PROVIDER=${PRISMA_PROVIDER}
ENV DATABASE_URL=${DATABASE_URL}
# Copy package and prisma metadata for cached install/generate
COPY package.json package-lock.json ./
COPY prisma ./prisma
COPY scripts/prepare-prisma-schema.js ./scripts/prepare-prisma-schema.js
# Install all dependencies (including devDependencies for build) and generate Prisma client
RUN --mount=type=cache,target=/root/.npm \
npm ci && \
npm run prisma:prepare && \
npx prisma generate
# ============================================
# Stage 1.5: Install production dependencies only
# ============================================
FROM base AS production-deps
WORKDIR /app
ARG PRISMA_PROVIDER=sqlite
ARG DATABASE_URL=file:./data/atlantis.db
ENV PRISMA_PROVIDER=${PRISMA_PROVIDER}
ENV DATABASE_URL=${DATABASE_URL}
COPY package.json package-lock.json ./
COPY prisma ./prisma
COPY scripts/prepare-prisma-schema.js ./scripts/prepare-prisma-schema.js
# Install only production dependencies (now includes prisma)
RUN --mount=type=cache,target=/root/.npm \
npm ci --omit=dev && \
npm run prisma:prepare && \
npx prisma generate
# ============================================
# Stage 2: Build the application
# ============================================
FROM base AS builder
WORKDIR /app
ARG PRISMA_PROVIDER=sqlite
ARG DATABASE_URL=file:./data/atlantis.db
ENV PRISMA_PROVIDER=${PRISMA_PROVIDER}
ENV DATABASE_URL=${DATABASE_URL}
ENV PRISMA_SKIP_BACKFILL=true
# Copy dependencies and Prisma artifacts from deps stage
COPY --from=deps /app/node_modules ./node_modules
COPY --from=deps /app/prisma ./prisma
COPY --from=deps /app/scripts ./scripts
# Copy source files
COPY . .
# Disable Next.js telemetry during build
ENV NEXT_TELEMETRY_DISABLED=1
ENV NEXT_OUTPUT=standalone
# Prepare schema/client, seed empty DB, and build app
RUN npm run prisma:prepare && \
npx prisma generate && \
mkdir -p /app/data && \
npx prisma db push && \
npm run build
# ============================================
# Stage 3: Production runner (minimal image)
# ============================================
FROM base AS runner
WORKDIR /app
# Set production environment
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Create non-root user for security
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# Copy only the necessary files from builder
# 1. Public assets
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
# 2. Standalone server (includes minimal node_modules from Next.js)
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
# 3. Static files
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# 4. Production node_modules from production-deps stage
# (Contains only what's needed for runtime, including prisma)
COPY --from=production-deps --chown=nextjs:nodejs /app/node_modules ./node_modules
# 5. Prisma schema template, config, and scripts for runtime generation
COPY --from=builder --chown=nextjs:nodejs /app/prisma/schema.template.prisma ./prisma/schema.template.prisma
COPY --from=builder --chown=nextjs:nodejs /app/prisma/prisma.config.ts ./prisma/prisma.config.ts
COPY --from=builder --chown=nextjs:nodejs /app/scripts/prepare-prisma-schema.js ./scripts/prepare-prisma-schema.js
COPY --from=builder --chown=nextjs:nodejs /app/scripts/docker-entrypoint.sh ./scripts/docker-entrypoint.sh
RUN chmod +x ./scripts/docker-entrypoint.sh
# 6. Baseline SQLite database (empty schema)
COPY --from=builder --chown=nextjs:nodejs /app/data ./data
# Create data directory for diagram persistence
RUN mkdir -p /app/data && chown -R nextjs:nodejs /app/data
# Install TeX Live for LaTeX support
RUN apk add --no-cache texlive-full fontconfig
# Install su-exec for privilege dropping in entrypoint
RUN apk add --no-cache su-exec
# NOTE: We do NOT switch to nextjs user here because the entrypoint
# needs to run as root initially to fix mounted volume permissions.
# The entrypoint will drop privileges to nextjs after setup.
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD node -e "fetch('http://127.0.0.1:3000/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
# Start via entrypoint (generates Prisma client + syncs schema at runtime)
ENTRYPOINT ["./scripts/docker-entrypoint.sh"]