From 0a32094e936a9354a5a28e0ae4513f1b5ff742a5 Mon Sep 17 00:00:00 2001 From: Dmytro Stanchiev Date: Sat, 13 Dec 2025 20:54:32 -0500 Subject: [PATCH] feat: adapt Dockerfile for monorepo structure --- Dockerfile | 131 ++++++++++++++++++++++++++++++++++++++------- docker-compose.yml | 23 -------- 2 files changed, 113 insertions(+), 41 deletions(-) delete mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile index b469bb3..40af632 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,31 +1,126 @@ -# Use the official Bun base image -FROM oven/bun:latest AS base +# ============================================================================= +# Stage 1: Dependencies +# Install only production dependencies for optimal layer caching +# ============================================================================= +FROM oven/bun:1-slim AS dependencies -# Set the working directory WORKDIR /app -# Copy package files for monorepo -COPY package.json bun.lock* ./ +# Copy workspace configuration +COPY package.json bun.lock ./ -# Install dependencies +# Copy all package.json files to establish workspace structure +COPY packages/core/package.json ./packages/core/ +COPY packages/api-server/package.json ./packages/api-server/ +COPY packages/mcp-server/package.json ./packages/mcp-server/ + +# Install dependencies with frozen lockfile (production only) +RUN bun install --frozen-lockfile --production + +# ============================================================================= +# Stage 2: Build +# Build both services with minification for production +# ============================================================================= +FROM oven/bun:1-slim AS build + +WORKDIR /app + +# Copy workspace configuration +COPY package.json bun.lock ./ + +# Copy all package.json files +COPY packages/core/package.json ./packages/core/ +COPY packages/api-server/package.json ./packages/api-server/ +COPY packages/mcp-server/package.json ./packages/mcp-server/ + +# Install ALL dependencies (including devDependencies for TypeScript) RUN bun install --frozen-lockfile -# Copy monorepo packages -COPY packages ./packages +# Copy source code for all packages +COPY packages/core ./packages/core +COPY packages/api-server ./packages/api-server +COPY packages/mcp-server ./packages/mcp-server -# Build the application for production -RUN cd packages/scraper && bun build ./src/index.ts --target=bun --outdir=../../dist --minify +# Build both services with minification +# Output: dist/api/index.js and dist/mcp/index.js +RUN bun build ./packages/api-server/src/index.ts \ + --target=bun \ + --outdir=./dist/api \ + --minify && \ + bun build ./packages/mcp-server/src/index.ts \ + --target=bun \ + --outdir=./dist/mcp \ + --minify -# Multi-stage build - runtime stage -FROM oven/bun:latest AS runtime +# Verify builds succeeded +RUN ls -lh ./dist/api/index.js ./dist/mcp/index.js + +# ============================================================================= +# Stage 3: Runtime +# Minimal production image with both services +# ============================================================================= +FROM oven/bun:1-slim AS runtime WORKDIR /app -# Copy the built application from the base stage -COPY --from=base /app/dist/ ./ +# Copy production dependencies from dependencies stage +COPY --from=dependencies /app/node_modules ./node_modules -# Expose the port the app runs on -EXPOSE 3000 +# Copy built artifacts from build stage +COPY --from=build /app/dist ./dist -# Start the application -CMD ["bun", "index.js"] +# Create cookies directory (will be mounted as volume at runtime) +# This ensures the directory exists even if volume is not mounted +RUN mkdir -p /app/cookies && \ + chown -R bun:bun /app/cookies + +# Create startup script that runs both services +# Uses Bun's built-in capabilities for process management +RUN cat > /app/start.sh << 'EOF' +#!/bin/bash +set -e + +# Trap SIGTERM and SIGINT for graceful shutdown +trap 'echo "Received shutdown signal, stopping services..."; kill -TERM $API_PID $MCP_PID 2>/dev/null; wait' TERM INT + +# Start API Server in background +echo "Starting API Server on port ${API_PORT:-4005}..." +bun /app/dist/api/index.js & +API_PID=$! + +# Give API server a moment to initialize +sleep 1 + +# Start MCP Server in background +echo "Starting MCP Server on port ${API_PORT:-4006}..." +bun /app/dist/mcp/index.js & +MCP_PID=$! + +echo "Both services started successfully" +echo "API Server PID: $API_PID" +echo "MCP Server PID: $MCP_PID" + +# Wait for both processes +wait $API_PID $MCP_PID +EOF + +RUN chmod +x /app/start.sh + +# Expose both service ports +# API Server: 4005 (default), MCP Server: 4006 (default) +EXPOSE 4005 4006 + +# Environment variables for port configuration +ENV PORT=4005 +ENV MCP_PORT=4006 + +# Volume mount point for cookies +# Mount your cookies directory here: -v /path/to/cookies:/app/cookies +VOLUME ["/app/cookies"] + +# Health check that verifies both services are responding +HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ + CMD bun -e "Promise.all([fetch('http://localhost:4005/api/status'),fetch('http://localhost:4006/.well-known/mcp/server-card.json')]).then(r=>process.exit(0)).catch(()=>process.exit(1))" + +# Run the startup script +CMD ["/app/start.sh"] diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index db297ad..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,23 +0,0 @@ -# NOT USED, CHECK LOBECHAT CONFIG -services: - ca-marketplace-scraper: - container_name: ca-marketplace-scraper - build: . - ports: - - "4005:4005" - environment: - - NODE_ENV=production - - PORT=4005 - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:4005/api/status"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 5s - restart: unless-stopped - networks: - - internal -networks: - internal: - driver: bridge - name: ca-marketplace-scraper-network