-
Notifications
You must be signed in to change notification settings - Fork 46
Expand file tree
/
Copy pathDockerfile.prod
More file actions
210 lines (177 loc) · 7.99 KB
/
Dockerfile.prod
File metadata and controls
210 lines (177 loc) · 7.99 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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# ============================================
# Build Stage
# ============================================
FROM node:25-alpine AS builder
# Install build dependencies for native modules (hnswlib-node) and npm (for corepack)
RUN apk add --no-cache python3 make g++ npm
# Install pnpm via corepack (use --force to handle yarn symlink conflict)
RUN npm install -g --force corepack && corepack enable && corepack prepare pnpm@9.15.0 --activate
WORKDIR /app
# Copy package files first (better layer caching)
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json ./
COPY apps/api/package.json ./apps/api/
COPY apps/web/package.json ./apps/web/
COPY packages/shared/package.json ./packages/shared/
# Install dependencies (including devDeps needed for build - we'll remove them later)
RUN pnpm install --frozen-lockfile --filter '!@app/entitlement'
# Copy source code (excluding entitlement app)
COPY apps/api ./apps/api
COPY apps/web ./apps/web
COPY packages/shared ./packages/shared
COPY proprietary ./proprietary
# Create symlink for proprietary node_modules (symlinks don't copy properly)
RUN ln -sf ../apps/api/node_modules proprietary/node_modules
# PostHog telemetry token (baked into frontend at build time)
ARG VITE_PUBLIC_POSTHOG_PROJECT_TOKEN
ARG VITE_PUBLIC_POSTHOG_HOST=https://eu.i.posthog.com
ENV VITE_PUBLIC_POSTHOG_PROJECT_TOKEN=$VITE_PUBLIC_POSTHOG_PROJECT_TOKEN
ENV VITE_PUBLIC_POSTHOG_HOST=$VITE_PUBLIC_POSTHOG_HOST
# Registration proxy URL (baked into frontend at build time).
# Defaults to the canonical www host so the in-app registration form on
# self-hosted instances reaches the public website proxy out of the box.
ARG VITE_REGISTRATION_URL=https://www.betterdb.com/api/register
ENV VITE_REGISTRATION_URL=$VITE_REGISTRATION_URL
# Build only api, web, and shared (exclude entitlement)
RUN pnpm --filter api --filter web --filter @betterdb/shared build
# ============================================
# Cleanup Stage - Remove AI dependencies
# ============================================
FROM node:25-alpine AS cleanup
WORKDIR /app
# Copy node_modules from builder
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/apps/api/node_modules ./apps/api/node_modules
COPY --from=builder /app/packages/shared/node_modules ./packages/shared/node_modules
# Remove AI dependencies, devDependencies, and build tools (~150MB+ savings)
# AI packages are only needed when AI_ENABLED=true
# DevDependencies are only needed during build, not runtime
# Must remove from BOTH top-level symlinks AND .pnpm store (where pnpm keeps actual files)
RUN rm -rf \
# AI-related top-level symlinks
node_modules/@lancedb \
node_modules/@langchain \
node_modules/langchain \
node_modules/hnswlib-node \
node_modules/better-sqlite3 \
node_modules/apache-arrow \
node_modules/@apache-arrow \
node_modules/ollama \
node_modules/@huggingface \
node_modules/openai \
node_modules/js-tiktoken \
apps/api/node_modules/@lancedb \
apps/api/node_modules/@langchain \
apps/api/node_modules/langchain \
apps/api/node_modules/hnswlib-node \
apps/api/node_modules/better-sqlite3 \
apps/api/node_modules/apache-arrow \
apps/api/node_modules/@apache-arrow \
apps/api/node_modules/ollama \
apps/api/node_modules/@huggingface \
apps/api/node_modules/openai \
apps/api/node_modules/js-tiktoken \
# pnpm store - AI packages + devDependencies (actual files)
&& find node_modules/.pnpm -maxdepth 1 -type d \( \
-name '@lancedb*' -o \
-name '@langchain*' -o \
-name 'langchain@*' -o \
-name 'hnswlib-node@*' -o \
-name 'better-sqlite3@*' -o \
-name 'apache-arrow@*' -o \
-name '@apache-arrow*' -o \
-name 'ollama@*' -o \
-name '@huggingface*' -o \
-name 'vectordb@*' -o \
-name '@napi-rs*' -o \
-name 'openai@*' -o \
-name 'js-tiktoken@*' -o \
-name 'typescript@*' -o \
-name 'turbo-*' -o \
-name '@types+*' -o \
-name 'prettier@*' -o \
-name 'eslint@*' -o \
-name '@typescript-eslint*' -o \
-name 'jest@*' -o \
-name 'ts-jest@*' -o \
-name '@nestjs+cli@*' -o \
-name '@nestjs+schematics@*' -o \
-name '@nestjs+testing@*' -o \
-name 'webpack@*' -o \
-name '@esbuild*' -o \
-name 'playwright*' \
\) -exec rm -rf {} + 2>/dev/null || true
# Copy dist files and remove AI module
COPY --from=builder /app/apps/api/dist ./apps/api/dist
RUN rm -rf /app/apps/api/dist/proprietary/ai
# ============================================
# Production Stage (Without AI Features)
# ============================================
FROM node:25-alpine AS production
# Install wget for healthcheck and tar (>=7.5.4) for security fix
# Upgrade all packages to get latest security patches (including Go stdlib in binaries)
RUN apk add --no-cache wget tar>=7.5.4 && \
apk upgrade --no-cache
WORKDIR /app
# Set APP_VERSION from build argument
ARG APP_VERSION=0.1.1
ENV APP_VERSION=$APP_VERSION
# Copy CLEANED node_modules from cleanup stage (no AI packages in this layer)
COPY --from=cleanup /app/node_modules ./node_modules
COPY --from=cleanup /app/apps/api/node_modules ./apps/api/node_modules
COPY --from=cleanup /app/packages/shared/node_modules ./packages/shared/node_modules
# Copy package files for module resolution
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY apps/api/package.json ./apps/api/
COPY packages/shared/package.json ./packages/shared/
# Copy built files from cleanup stage (AI module already removed)
COPY --from=cleanup /app/apps/api/dist ./apps/api/dist
COPY --from=builder /app/apps/web/dist ./apps/api/public
COPY --from=builder /app/packages/shared/dist ./packages/shared/dist
# Create symlink for @proprietary path alias (ai module already excluded)
RUN mkdir -p /app/node_modules/@proprietary && \
for dir in /app/apps/api/dist/proprietary/*/; do \
ln -s "$dir" /app/node_modules/@proprietary/; \
done
# PostHog telemetry (backend, runtime)
ARG POSTHOG_API_KEY
ARG POSTHOG_HOST=https://eu.i.posthog.com
ENV POSTHOG_API_KEY=$POSTHOG_API_KEY
ENV POSTHOG_HOST=$POSTHOG_HOST
# Set environment defaults
ENV NODE_ENV=production
ENV PORT=3001
ENV DB_HOST=localhost
ENV DB_PORT=6379
ENV DB_TYPE=auto
ENV DB_USERNAME=default
ENV STORAGE_TYPE=memory
ENV AI_ENABLED=false
# Install RedisShake binary for migration execution (with checksum verification)
ARG TARGETARCH
ARG REDISSHAKE_VERSION=4.6.0
RUN apk add --no-cache wget && \
REDISSHAKE_SHA256_AMD64="6ccab1ff2ba3c200950f8ada811f0c6fe6e2f5e6bd3b8e92b4d9444dc0aff4df" && \
REDISSHAKE_SHA256_ARM64="653298efa83ef3d495ae2ec21b40c773f36eb15e507f8b3f2931660509d09690" && \
if [ "${TARGETARCH}" = "amd64" ]; then EXPECTED_SHA256="${REDISSHAKE_SHA256_AMD64}"; else EXPECTED_SHA256="${REDISSHAKE_SHA256_ARM64}"; fi && \
wget -qO /tmp/redis-shake.tar.gz "https://github.com/tair-opensource/RedisShake/releases/download/v${REDISSHAKE_VERSION}/redis-shake-v${REDISSHAKE_VERSION}-linux-${TARGETARCH}.tar.gz" && \
echo "${EXPECTED_SHA256} /tmp/redis-shake.tar.gz" | sha256sum -c - && \
tar -xzf /tmp/redis-shake.tar.gz --strip-components=0 -C /usr/local/bin ./redis-shake && \
chmod +x /usr/local/bin/redis-shake && \
rm /tmp/redis-shake.tar.gz && \
apk del wget
# Create non-root user for security (Docker Scout compliance)
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 --ingroup nodejs betterdb
# Change ownership of app directory
RUN chown -R betterdb:nodejs /app
USER betterdb
# Expose port (can be overridden with -e PORT=<port> at runtime)
# Note: EXPOSE is documentation only - actual port binding happens via -p flag
EXPOSE 3001
# Health check - uses PORT environment variable
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:${PORT}/health || exit 1
# Set NODE_PATH to resolve workspace dependencies
ENV NODE_PATH=/app/node_modules
# Start the server
CMD ["node", "apps/api/dist/apps/api/src/main.js"]