-
Notifications
You must be signed in to change notification settings - Fork 350
Expand file tree
/
Copy pathall.Dockerfile
More file actions
249 lines (207 loc) · 10.5 KB
/
all.Dockerfile
File metadata and controls
249 lines (207 loc) · 10.5 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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# Multi-stage Dockerfile for building Jitsu services (console, rotor, profiles)
#
# Usage:
# docker buildx build --target console -t jitsucom/console:latest .
# docker buildx build --target rotor -t jitsucom/rotor:latest .
# docker buildx build --target profiles -t jitsucom/profiles:latest .
#
# Build with version info:
# docker buildx build --target console \
# --build-arg JITSU_BUILD_VERSION=1.0.0 \
# --build-arg JITSU_BUILD_COMMIT_SHA=abc123 \
# -t jitsucom/console:1.0.0 .
# ============================================================================
# BASE STAGE - Shared runtime image for all services
# ============================================================================
# This stage provides the minimal Node.js runtime environment
# Shared by all final service images (console, rotor, profiles)
FROM node:24-bookworm-slim AS base
WORKDIR /app
# Install runtime dependencies required by all services
# - nano, curl: debugging and healthchecks
# - cron: scheduled tasks for console
# - bash: shell scripting
# - netcat-traditional: network utilities
# - procps: process management (ps, top, etc.)
# - jq: JSON parsing for extracting package versions
RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates nano curl cron bash netcat-traditional procps jq && \
rm -rf /var/lib/apt/lists/*
# ============================================================================
# BUILDER STAGE - Build all TypeScript/JavaScript code
# ============================================================================
# Uses jitsu-builder image which has:
# - Node.js 24, pnpm 10, build tools (g++, make, python)
# - Pre-populated pnpm store with all dependencies at /pnpm-store
# - Playwright browsers pre-installed
FROM jitsucom/jitsu-builder:latest AS builder
ARG CI=false
WORKDIR /app
# STEP 1: Copy lockfiles and workspace config (smallest possible layer)
# This layer only invalidates when dependency versions change
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
# STEP 2: Fetch dependencies into pnpm store
# The builder image already has most packages cached at /pnpm-store
# This step verifies the store and fetches any new/updated packages
# --ignore-scripts: Skip postinstall scripts (they run during install step)
RUN echo "pnpm store path: $(pnpm store path)" && pnpm fetch --ignore-scripts
# STEP 3: Copy only package.json files (not source code yet!)
# This optimization allows the install layer to be cached independently from source changes
# How it works:
# 1. Copy entire workspace to /tmp/src temporarily
# 2. Find all package.json files (excluding build artifacts)
# 3. Copy just the package.json files to /app, preserving directory structure
# 4. Delete /tmp/src to free up space
# Why: pnpm needs all package.json files to understand the workspace structure,
# but doesn't need source code yet. This means editing .ts/.tsx files won't
# invalidate the expensive install layer.
COPY . /tmp/src
RUN cd /tmp/src && \
find . -name 'package.json' \
-not -path '*/node_modules/*' \
-not -path '*/.pnpm-store/*' \
-not -path '*/dist/*' \
-not -path '*/build/*' \
-exec sh -c 'mkdir -p /app/$(dirname {}) && cp {} /app/{}' \; && \
rm -rf /tmp/src
# STEP 4: Install dependencies (THIS LAYER IS CACHED!)
# This layer only invalidates when lockfile or any package.json changes
# Flags:
# -r: install all workspace packages recursively
# --frozen-lockfile: fail if lockfile needs updates (ensures reproducibility)
# --prefer-offline: use cache when possible, but allow downloads for native modules
# --unsafe-perm: allow postinstall scripts to run as root (needed for native module compilation)
RUN pnpm install -r --frozen-lockfile --prefer-offline --unsafe-perm
# STEP 5: Copy source code
# This layer invalidates on ANY source file change, but the install layer above remains cached
COPY . .
# STEP 6: Build all TypeScript/JavaScript code
# Environment variables:
# NEXTJS_STANDALONE_BUILD=1: tells Next.js to create minimal standalone output
# CI: some packages behave differently in CI (e.g., disable interactive prompts)
ENV NEXTJS_STANDALONE_BUILD=1
ENV CI=${CI}
# Note: pnpm build now includes building the management CLI (build:manage)
RUN pnpm build
# ============================================================================
# CONSOLE STAGE - Next.js web application with Prisma ORM
# ============================================================================
# The admin console for managing Jitsu (Next.js + Prisma)
FROM base AS console
# Build arguments passed from CI/CD or docker build command
# These become environment variables in the final image
ARG JITSU_BUILD_VERSION=dev,
ARG JITSU_BUILD_DOCKER_TAG=dev,
ARG JITSU_BUILD_COMMIT_SHA=unknown,
WORKDIR /app
# Install Prisma CLI globally (needed for database migrations at runtime)
# Why globally: Prisma needs to be available for migrations in docker-start-console.sh
# Why this approach: Extract exact version from package.json to ensure compatibility
# Steps:
# 1. Copy package.json to temporary location
# 2. Use jq to extract the exact prisma version from dependencies
# 3. Install that specific version globally
# 4. The temp file is discarded (no cleanup needed - happens in same layer)
COPY --from=builder /app/webapps/console/package.json /tmp/console-package.json
RUN npm -g install prisma@$(jq -r '.dependencies.prisma' /tmp/console-package.json)
# Copy startup script and Prisma schema
# docker-start-console.sh: Runs migrations and starts the server
# schema.prisma: Needed for Prisma CLI commands at runtime
COPY --from=builder /app/docker-start-console.sh ./
COPY --from=builder /app/webapps/console/prisma/schema.prisma ./
# Copy Next.js standalone build output
# Next.js standalone mode creates a minimal, self-contained server with only necessary files
# Why .next/standalone: Contains the server and minimal dependencies
# Why .next/static separate: Next.js requires static assets in specific location
# Why public separate: User-uploaded or public assets served by Next.js
COPY --from=builder /app/webapps/console/.next/standalone ./
COPY --from=builder /app/webapps/console/.next/static ./webapps/console/.next/static
COPY --from=builder /app/webapps/console/public ./webapps/console/public
# Copy management CLI script (bundled with esbuild)
# This allows running management commands like: node /app/webapps/console/build/manage.js seed
COPY --from=builder /app/webapps/console/build/manage.js ./webapps/console/build/
# Setup cron for scheduled tasks (e.g., cleanup, analytics aggregation)
# chmod 0644: cron requires specific permissions (owner read/write, others read)
# crontab: Install the cron schedule
COPY --from=builder /app/console.cron /etc/cron.d/console.cron
RUN chmod 0644 /etc/cron.d/console.cron
RUN crontab /etc/cron.d/console.cron
EXPOSE 3000
# Health check for container orchestration (Kubernetes, Docker Compose, etc.)
# Calls Next.js healthcheck endpoint every 30s (default)
HEALTHCHECK CMD curl --fail http://localhost:3000/api/healthcheck || exit 1
# Set environment variables for runtime
# NODE_ENV=production: Enables production optimizations in Node.js and Next.js
# JITSU_VERSION_*: Version info displayed in the UI and logs
ENV NODE_ENV=production
ENV JITSU_VERSION_COMMIT_SHA=${JITSU_BUILD_COMMIT_SHA}
ENV JITSU_VERSION_DOCKER_TAG=${JITSU_BUILD_DOCKER_TAG}
ENV JITSU_VERSION_STRING=${JITSU_BUILD_VERSION}
# Use shell to execute startup script (needed for environment variable substitution)
ENTRYPOINT ["sh", "-c", "/app/docker-start-console.sh"]
# ============================================================================
# ROTOR STAGE - Data ingestion and routing service
# ============================================================================
# High-throughput Node.js service for processing incoming events
FROM base AS rotor
# Build arguments for version information
ARG JITSU_BUILD_VERSION=dev,
ARG JITSU_BUILD_DOCKER_TAG=dev,
ARG JITSU_BUILD_COMMIT_SHA=unknown,
WORKDIR /app
# Create non-root user for security best practices
# Why: Running as root in containers is a security risk
# GID/UID 1001: Arbitrary non-privileged IDs (common convention)
# --system: Creates a system user (no password, no login shell)
RUN addgroup --system --gid 1001 runner
RUN adduser --system --uid 1001 runner
USER runner
EXPOSE 3401
# Copy compiled JavaScript from builder stage
# The /dist folder contains the bundled Node.js application
COPY --from=builder /app/services/rotor/dist .
COPY --from=builder /app/services/rotor/entrypoint.sh .
# Runtime environment configuration
ENV NODE_ENV=production
ENV JITSU_VERSION_COMMIT_SHA=${JITSU_BUILD_COMMIT_SHA}
ENV JITSU_VERSION_DOCKER_TAG=${JITSU_BUILD_DOCKER_TAG}
ENV JITSU_VERSION_STRING=${JITSU_BUILD_VERSION}
ENTRYPOINT ["/app/entrypoint.sh"]
# ============================================================================
# FUNCTIONS-SERVER STAGE - Deno-based UDF execution with Web Worker isolation
# ============================================================================
# Sandboxed functions execution for free-tier workspaces
FROM denoland/deno:debian AS functions-server
ARG JITSU_BUILD_VERSION=dev,
ARG JITSU_BUILD_DOCKER_TAG=dev,
ARG JITSU_BUILD_COMMIT_SHA=unknown,
WORKDIR /app
# Install curl for healthchecks
RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates curl && \
rm -rf /var/lib/apt/lists/*
EXPOSE 3401
# Copy Deno-specific build artifacts from builder
COPY --from=builder /app/services/rotor/dist/functions-server.mjs ./functions-server.mjs
COPY --from=builder /app/services/rotor/dist/workspace-worker.mjs ./workspace-worker.mjs
COPY --from=builder /app/services/rotor/dist/profile-worker.mjs ./profile-worker.mjs
# Copy node_modules with native deps (installed by build.mts)
# Workspace packages and pure JS deps are bundled into functions-server.mjs by esbuild
COPY --from=builder /app/services/rotor/dist/node_modules ./node_modules
COPY --from=builder /app/services/rotor/dist/package.json ./package.json
ENV JITSU_VERSION_COMMIT_SHA=${JITSU_BUILD_COMMIT_SHA}
ENV JITSU_VERSION_DOCKER_TAG=${JITSU_BUILD_DOCKER_TAG}
ENV JITSU_VERSION_STRING=${JITSU_BUILD_VERSION}
ENV NODE_ENV=production
HEALTHCHECK CMD curl --fail http://localhost:3401/health || exit 1
ENTRYPOINT ["deno", "run", \
"--allow-net", \
"--allow-read", \
"--allow-write=/tmp/jitsu-udf,/data", \
"--allow-env", \
"--allow-sys", \
"--allow-ffi", \
"--allow-run=/app/node_modules/@esbuild/linux-arm64/bin/esbuild,/app/node_modules/@esbuild/linux-x64/bin/esbuild,/app/node_modules/esbuild/bin/esbuild", \
"--unstable-worker-options", \
"--no-check", \
"functions-server.mjs"]