72 lines
2.7 KiB
Docker
72 lines
2.7 KiB
Docker
# PIG — production image.
|
|
#
|
|
# Multi-stage so the runtime image carries no build toolchain and no source
|
|
# maps. The front end is built into the API's static directory and served from
|
|
# the same origin, which matters for more than tidiness: auth sessions are
|
|
# per-origin, so splitting the app across two hostnames turns sign-in into a
|
|
# redirect loop that looks like a broken deployment.
|
|
|
|
FROM node:22-alpine AS build
|
|
WORKDIR /app
|
|
|
|
# Manifests first, so a dependency install is cached across source-only edits.
|
|
COPY package.json package-lock.json* ./
|
|
COPY packages/core/package.json packages/core/
|
|
COPY packages/db/package.json packages/db/
|
|
COPY packages/prime/package.json packages/prime/
|
|
COPY apps/api/package.json apps/api/
|
|
COPY apps/web/package.json apps/web/
|
|
COPY apps/mcp/package.json apps/mcp/
|
|
COPY apps/piggy/package.json apps/piggy/
|
|
RUN npm install --no-audit --no-fund
|
|
|
|
COPY . .
|
|
|
|
# Typecheck as a build gate. A deploy that does not compile should fail here,
|
|
# loudly, rather than at runtime in front of a user.
|
|
RUN npx tsc --noEmit -p packages/core/tsconfig.json \
|
|
&& npx tsc --noEmit -p packages/db/tsconfig.json \
|
|
&& npx tsc --noEmit -p packages/prime/tsconfig.json \
|
|
&& npx tsc --noEmit -p apps/api/tsconfig.json \
|
|
&& npx tsc --noEmit -p apps/web/tsconfig.json \
|
|
&& npx tsc --noEmit -p apps/mcp/tsconfig.json \
|
|
&& npx tsc --noEmit -p apps/piggy/tsconfig.json
|
|
|
|
RUN npm run build -w @pig/web
|
|
|
|
# ---------------------------------------------------------------- runtime
|
|
FROM node:22-alpine AS runtime
|
|
WORKDIR /app
|
|
|
|
ENV NODE_ENV=production
|
|
|
|
# Reinstall without dev dependencies. tsx is needed at runtime because the
|
|
# server runs TypeScript directly; everything else is production-only.
|
|
COPY package.json package-lock.json* ./
|
|
COPY packages/core/package.json packages/core/
|
|
COPY packages/db/package.json packages/db/
|
|
COPY packages/prime/package.json packages/prime/
|
|
COPY apps/api/package.json apps/api/
|
|
COPY apps/mcp/package.json apps/mcp/
|
|
COPY apps/piggy/package.json apps/piggy/
|
|
RUN npm install --omit=dev --no-audit --no-fund && npm install tsx --no-audit --no-fund
|
|
|
|
COPY packages ./packages
|
|
COPY apps/api ./apps/api
|
|
COPY apps/mcp ./apps/mcp
|
|
COPY apps/piggy ./apps/piggy
|
|
COPY --from=build /app/apps/web/dist ./apps/web/dist
|
|
|
|
# Run unprivileged. The node image ships a `node` user for exactly this.
|
|
RUN chown -R node:node /app
|
|
USER node
|
|
|
|
EXPOSE 8920
|
|
|
|
# The health endpoint is unauthenticated by design so this works without
|
|
# credentials baked into the image.
|
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
|
|
CMD node -e "fetch('http://127.0.0.1:8920/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
|
|
|
|
CMD ["npx", "tsx", "apps/api/src/server.ts"]
|