feat: add Docker deployment with Containerfile, entrypoints, and nginx

Multi-stage Containerfile for all Node.js services (single image,
different CMD per docker-compose service). ESM entrypoints for gateway,
config, text-completion, prompt, embeddings, agent, and librarian.

Workbench gets a separate Containerfile (nginx:alpine) with SPA routing
and API/WebSocket proxy to gateway.

Docker Compose updated with 6 app services (gateway, config-service,
text-completion, prompt, embeddings, workbench) using shared
trustgraph-ts:local image.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
elpresidank 2026-04-06 00:21:00 -05:00
parent f09ef4de45
commit d1f24cf759
13 changed files with 241 additions and 78 deletions

7
ts/.dockerignore Normal file
View file

@ -0,0 +1,7 @@
node_modules
.git
deploy
**/dist
**/.turbo
*.log
.env*

44
ts/Containerfile Normal file
View file

@ -0,0 +1,44 @@
# TrustGraph TypeScript — multi-stage build for all Node.js services.
# A single image is built once; each service overrides CMD to pick its entrypoint.
# ---------------------------------------------------------------------------
# Stage 1: Build
# ---------------------------------------------------------------------------
FROM node:22-slim AS builder
RUN corepack enable && corepack prepare pnpm@9.15.0 --activate
WORKDIR /app
# Copy workspace config first for layer caching
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json tsconfig.base.json ./
COPY packages/base/package.json packages/base/tsconfig.json packages/base/
COPY packages/client/package.json packages/client/tsconfig.json packages/client/
COPY packages/flow/package.json packages/flow/tsconfig.json packages/flow/
COPY packages/cli/package.json packages/cli/tsconfig.json packages/cli/
COPY packages/mcp/package.json packages/mcp/tsconfig.json packages/mcp/
RUN pnpm install --frozen-lockfile
# Copy source and build
COPY packages/ packages/
COPY tsconfig.json ./
RUN pnpm build
# ---------------------------------------------------------------------------
# Stage 2: Runtime
# ---------------------------------------------------------------------------
FROM node:22-slim AS runtime
WORKDIR /app
# Copy built output and production deps
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/packages ./packages
COPY --from=builder /app/package.json ./
COPY --from=builder /app/pnpm-workspace.yaml ./
COPY entrypoints/ ./entrypoints/
# Default env
ENV NODE_ENV=production
ENV NATS_URL=nats://nats:4222
EXPOSE 8088
CMD ["node", "entrypoints/gateway.mjs"]

View file

@ -197,82 +197,89 @@ services:
restart: unless-stopped restart: unless-stopped
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# TrustGraph Services (placeholders — will be filled in later) # TrustGraph Application Services
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
#
# gateway: gateway:
# build: image: trustgraph-ts:local
# context: ../ build:
# dockerfile: packages/base/Dockerfile context: ../
# target: gateway dockerfile: Containerfile
# ports: command: ["node", "entrypoints/gateway.mjs"]
# - "${GATEWAY_PORT:-8088}:8000" ports:
# environment: - "${GATEWAY_PORT:-8088}:8088"
# - NATS_URL=nats://nats:4222 environment:
# - FALKORDB_URL=redis://falkordb:6379 - NATS_URL=nats://nats:4222
# - QDRANT_URL=http://qdrant:6333 - GATEWAY_PORT=8088
# - OPENAI_TOKEN=${OPENAI_TOKEN} - GATEWAY_SECRET=${GATEWAY_SECRET:-}
# - CLAUDE_KEY=${CLAUDE_KEY} depends_on:
# - GATEWAY_SECRET=${GATEWAY_SECRET} nats:
# - OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 condition: service_healthy
# - OTEL_SERVICE_NAME=gateway networks:
# depends_on: - trustgraph
# nats: restart: unless-stopped
# condition: service_healthy
# falkordb: config-service:
# condition: service_healthy image: trustgraph-ts:local
# qdrant: command: ["node", "entrypoints/config.mjs"]
# condition: service_healthy environment:
# networks: - NATS_URL=nats://nats:4222
# - trustgraph depends_on:
# nats:
# text-completion: condition: service_healthy
# build: networks:
# context: ../ - trustgraph
# dockerfile: packages/base/Dockerfile restart: unless-stopped
# target: text-completion
# environment: text-completion:
# - NATS_URL=nats://nats:4222 image: trustgraph-ts:local
# - OPENAI_TOKEN=${OPENAI_TOKEN} command: ["node", "entrypoints/text-completion-openai.mjs"]
# - CLAUDE_KEY=${CLAUDE_KEY} environment:
# - OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 - NATS_URL=nats://nats:4222
# - OTEL_SERVICE_NAME=text-completion - OPENAI_TOKEN=${OPENAI_TOKEN:-}
# depends_on: - OPENAI_BASE_URL=${OPENAI_BASE_URL:-}
# nats: depends_on:
# condition: service_healthy nats:
# networks: condition: service_healthy
# - trustgraph networks:
# - trustgraph
# graph-rag: restart: unless-stopped
# build:
# context: ../ prompt:
# dockerfile: packages/base/Dockerfile image: trustgraph-ts:local
# target: graph-rag command: ["node", "entrypoints/prompt.mjs"]
# environment: environment:
# - NATS_URL=nats://nats:4222 - NATS_URL=nats://nats:4222
# - FALKORDB_URL=redis://falkordb:6379 depends_on:
# - QDRANT_URL=http://qdrant:6333 nats:
# - OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 condition: service_healthy
# - OTEL_SERVICE_NAME=graph-rag networks:
# depends_on: - trustgraph
# nats: restart: unless-stopped
# condition: service_healthy
# falkordb: embeddings:
# condition: service_healthy image: trustgraph-ts:local
# qdrant: command: ["node", "entrypoints/embeddings.mjs"]
# condition: service_healthy environment:
# networks: - NATS_URL=nats://nats:4222
# - trustgraph - OLLAMA_URL=http://ollama:11434
# depends_on:
# workbench: nats:
# build: condition: service_healthy
# context: ../ ollama:
# dockerfile: packages/workbench/Dockerfile condition: service_started
# ports: networks:
# - "3001:3000" - trustgraph
# environment: restart: unless-stopped
# - GATEWAY_URL=http://gateway:8000
# depends_on: workbench:
# - gateway build:
# networks: context: ../
# - trustgraph dockerfile: packages/workbench/Containerfile
ports:
- "${WORKBENCH_PORT:-3001}:80"
depends_on:
- gateway
networks:
- trustgraph
restart: unless-stopped

7
ts/entrypoints/agent.mjs Normal file
View file

@ -0,0 +1,7 @@
// Will work once the agent service is merged.
import("../packages/flow/dist/agent/react/service.js")
.then((m) => m.run())
.catch((err) => {
console.error(err);
process.exit(1);
});

View file

@ -0,0 +1,6 @@
import("../packages/flow/dist/config/service.js")
.then((m) => m.run())
.catch((err) => {
console.error(err);
process.exit(1);
});

View file

@ -0,0 +1,6 @@
import("../packages/flow/dist/embeddings/ollama.js")
.then((m) => m.run())
.catch((err) => {
console.error(err);
process.exit(1);
});

View file

@ -0,0 +1,6 @@
import("../packages/flow/dist/gateway/server.js")
.then((m) => m.run())
.catch((err) => {
console.error(err);
process.exit(1);
});

View file

@ -0,0 +1,7 @@
// Will work once the librarian service is merged.
import("../packages/flow/dist/librarian/service.js")
.then((m) => m.run())
.catch((err) => {
console.error(err);
process.exit(1);
});

View file

@ -0,0 +1,6 @@
import("../packages/flow/dist/prompt/template.js")
.then((m) => m.run())
.catch((err) => {
console.error(err);
process.exit(1);
});

View file

@ -0,0 +1,6 @@
import("../packages/flow/dist/model/text-completion/claude.js")
.then((m) => m.run())
.catch((err) => {
console.error(err);
process.exit(1);
});

View file

@ -0,0 +1,6 @@
import("../packages/flow/dist/model/text-completion/openai.js")
.then((m) => m.run())
.catch((err) => {
console.error(err);
process.exit(1);
});

View file

@ -0,0 +1,27 @@
# TrustGraph Workbench — Vite SPA served by nginx.
# ---------------------------------------------------------------------------
# Stage 1: Build
# ---------------------------------------------------------------------------
FROM node:22-slim AS builder
RUN corepack enable && corepack prepare pnpm@9.15.0 --activate
WORKDIR /app
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json tsconfig.base.json ./
COPY packages/base/package.json packages/base/tsconfig.json packages/base/
COPY packages/client/package.json packages/client/tsconfig.json packages/client/
COPY packages/workbench/package.json packages/workbench/tsconfig.json packages/workbench/vite.config.ts packages/workbench/
RUN pnpm install --frozen-lockfile
COPY packages/ packages/
COPY tsconfig.json ./
RUN pnpm build --filter=@trustgraph/workbench
# ---------------------------------------------------------------------------
# Stage 2: Serve
# ---------------------------------------------------------------------------
FROM nginx:alpine
COPY --from=builder /app/packages/workbench/dist /usr/share/nginx/html
COPY packages/workbench/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

View file

@ -0,0 +1,28 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# SPA routing
location / {
try_files $uri $uri/ /index.html;
}
# API proxy to gateway
location /api/v1/ {
proxy_pass http://gateway:8088;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# WebSocket proxy
location /api/v1/socket {
proxy_pass http://gateway:8088;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400;
}
}