all.Dockerfile
Rama newjitsu · réplica de lectura del repositorio original.
# 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 ./
COPY patches ./patches
# 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 retl-runner
COPY --from=builder --chown=node:node /app/services/retl-runner/dist/main.cjs /app/main.cjs
USER node
CMD ["node", "/app/main.cjs"]
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"]