|
1 | | -# ---- Base Node ---- |
2 | | -# Use a specific Node.js version known to work, Alpine for smaller size |
| 1 | +# syntax=docker/dockerfile:1.7 |
| 2 | +# |
| 3 | +# Build context: REPO ROOT (npm workspaces monorepo uses a single root |
| 4 | +# package-lock.json shared by every workspace). The workflow must set |
| 5 | +# `context: .` so this Dockerfile can see the root lockfile. |
| 6 | +# |
| 7 | +# Produces a runtime image for @ibm/ibmi-mcp-server only — the CLI |
| 8 | +# workspace is not shipped. |
| 9 | + |
| 10 | +# ---- Base ---- |
3 | 11 | FROM node:bookworm-slim AS base |
4 | | -WORKDIR /usr/src/app |
5 | | -# NODE_ENV will be set by docker-compose from .env file |
6 | | - |
7 | | -# Update system packages and install security updates |
8 | | -# This resolves all system-level CVEs |
9 | | -RUN apt-get update && \ |
10 | | - apt-get upgrade -y && \ |
11 | | - apt-get install -y --no-install-recommends \ |
12 | | - ca-certificates \ |
13 | | - && \ |
14 | | - npm install -g npm@latest && \ |
15 | | - apt-get clean && \ |
16 | | - rm -rf /var/lib/apt/lists/* |
17 | | - |
18 | | -# ---- Dependencies ---- |
19 | | -# Install dependencies first to leverage Docker cache |
20 | | -FROM base AS deps |
21 | | -WORKDIR /usr/src/app |
22 | | -ENV NODE_ENV=production |
23 | | -COPY package.json package-lock.json* ./ |
24 | | -# Use npm ci for deterministic installs based on lock file |
25 | | -# Install only production dependencies in this stage for the final image |
26 | | -RUN npm ci --only=production |
| 12 | +WORKDIR /app |
27 | 13 |
|
28 | | -# ---- Builder ---- |
29 | | -# Build the application |
| 14 | +# System updates + recent npm (lockfileVersion 3 needs npm >= 7) |
| 15 | +RUN apt-get update \ |
| 16 | + && apt-get upgrade -y \ |
| 17 | + && apt-get install -y --no-install-recommends ca-certificates \ |
| 18 | + && npm install -g npm@latest \ |
| 19 | + && apt-get clean \ |
| 20 | + && rm -rf /var/lib/apt/lists/* |
| 21 | + |
| 22 | +# ---- Builder: install all deps, build the server workspace ---- |
30 | 23 | FROM base AS builder |
31 | | -WORKDIR /usr/src/app |
32 | | -# Override NODE_ENV to ensure devDependencies (including TypeScript) are installed |
| 24 | +WORKDIR /app |
33 | 25 | ENV NODE_ENV=development |
34 | | -# Copy dependency manifests and install *all* dependencies (including dev) |
35 | | -COPY package.json package-lock.json* ./ |
| 26 | + |
| 27 | +# Copy manifests first so the Docker layer cache is invalidated only when |
| 28 | +# dependency declarations change, not on every source edit. Every workspace |
| 29 | +# package.json must be present for `npm ci` to resolve the workspace graph |
| 30 | +# that the root lockfile describes. |
| 31 | +COPY package.json package-lock.json ./ |
| 32 | +COPY packages/server/package.json ./packages/server/ |
| 33 | +COPY packages/cli/package.json ./packages/cli/ |
| 34 | + |
36 | 35 | RUN npm ci |
37 | | -# Copy the rest of the source code |
| 36 | + |
| 37 | +# Copy the full source tree and build only the server workspace. |
| 38 | +# (.dockerignore keeps node_modules/, dist/, .git/, .github/, .claude/, |
| 39 | +# agents/, and .env files out of the build context.) |
38 | 40 | COPY . . |
39 | | -# Build the TypeScript project |
40 | | -RUN npm run build |
| 41 | + |
| 42 | +RUN npm run build -w @ibm/ibmi-mcp-server |
| 43 | + |
| 44 | +# ---- Production dependencies only ---- |
| 45 | +# Separate stage so the runtime image carries only what the server needs |
| 46 | +# to execute — no TypeScript, no test frameworks, no CLI workspace deps. |
| 47 | +FROM base AS prod-deps |
| 48 | +WORKDIR /app |
| 49 | +ENV NODE_ENV=production |
| 50 | + |
| 51 | +COPY package.json package-lock.json ./ |
| 52 | +COPY packages/server/package.json ./packages/server/ |
| 53 | +COPY packages/cli/package.json ./packages/cli/ |
| 54 | + |
| 55 | +# --workspace=@ibm/ibmi-mcp-server + --include-workspace-root installs |
| 56 | +# exactly the production deps the server needs plus anything hoisted to |
| 57 | +# the root. The CLI workspace's deps are skipped. |
| 58 | +RUN npm ci --omit=dev \ |
| 59 | + --workspace=@ibm/ibmi-mcp-server \ |
| 60 | + --include-workspace-root |
41 | 61 |
|
42 | 62 | # ---- Runner ---- |
43 | | -# Final stage with all dependencies and built code |
44 | 63 | FROM base AS runner |
45 | | -WORKDIR /usr/src/app |
46 | | -# Copy ALL node_modules from the 'builder' stage (includes dev dependencies) |
47 | | -COPY --from=builder /usr/src/app/node_modules ./node_modules |
48 | | -# Copy built application from the 'builder' stage |
49 | | -COPY --from=builder /usr/src/app/dist ./dist |
50 | | -# Copy package.json (needed for potential runtime info, like version) |
51 | | -COPY package.json . |
52 | | - |
53 | | -# Create a non-root user and switch to it |
54 | | -RUN groupadd -r appgroup && useradd -r -g appgroup appuser |
55 | | - |
56 | | -# Change ownership of app directory to appuser and create npm cache directory |
57 | | -RUN chown -R appuser:appgroup /usr/src/app && \ |
58 | | - mkdir -p /home/appuser/.npm && \ |
59 | | - chown -R appuser:appgroup /home/appuser/.npm |
| 64 | +WORKDIR /app |
| 65 | + |
| 66 | +# node_modules carries a symlink `@ibm/ibmi-mcp-server -> ../packages/server`. |
| 67 | +# Copying node_modules from prod-deps preserves the symlink; populating |
| 68 | +# packages/server/ from the builder makes the symlink resolve to the |
| 69 | +# actual built dist output. |
| 70 | +COPY --from=prod-deps /app/node_modules ./node_modules |
| 71 | +COPY --from=builder /app/package.json ./package.json |
| 72 | +COPY --from=builder /app/packages/server/package.json ./packages/server/package.json |
| 73 | +COPY --from=builder /app/packages/server/dist ./packages/server/dist |
| 74 | + |
| 75 | +# Non-root user + npm cache dir |
| 76 | +RUN groupadd -r appgroup \ |
| 77 | + && useradd -r -g appgroup appuser \ |
| 78 | + && chown -R appuser:appgroup /app \ |
| 79 | + && mkdir -p /home/appuser/.npm \ |
| 80 | + && chown -R appuser:appgroup /home/appuser/.npm |
60 | 81 |
|
61 | 82 | USER appuser |
62 | 83 |
|
63 | | -# Expose port if the application runs a server (adjust if needed) |
64 | 84 | ENV MCP_TRANSPORT_TYPE=http |
65 | 85 | EXPOSE 3010 |
66 | 86 |
|
67 | | -# Command to run the application |
68 | | -# This will execute the binary defined in package.json |
69 | | -CMD ["npx", "ibmi-mcp-server"] |
| 87 | +# Run node directly on the built entry rather than via `npx` — avoids |
| 88 | +# any bin-resolution surprises and gives a cleaner PID 1. |
| 89 | +CMD ["node", "packages/server/dist/index.js"] |
0 commit comments