feat(deploy): docker images, compose, roles SQL, local workspace
- core.Dockerfile: python:3.12-slim + node 22 copied (same bookworm glibc), non-root, tht+pi
- frontend.Dockerfile: vite build (env-driven base/assetsDir) + nginx-unprivileged
- compose.yaml (embedded, omics_network ext, zero host ports) + docker-compose.dev.yml (standalone)
- deploy/sql: thoth_dwh_reader (ro) + thoth_vector_rw (rw) roles
- deploy/thothii.env.example + harness/workspaces/local.yaml (direct DWH+vector, 5438)
- scripts/docker-smoke.sh; .dockerignore; gitignore deploy secrets
- verified: both images build, core health {ok}, config check validates local.yaml
This commit is contained in:
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
# Entrypoints logici del container thothii-core:
|
||||
# server (default) | check | tht <args...> | preprocess <args...>
|
||||
# THT_CONFIG punta al workspace attivo (local.yaml nel deploy co-locato).
|
||||
set -euo pipefail
|
||||
export THT_CONFIG="${THT_CONFIG:-/app/harness/workspaces/local.yaml}"
|
||||
|
||||
cmd="${1:-server}"
|
||||
case "$cmd" in
|
||||
check)
|
||||
# Diagnostica di wiring: validazione config/env + ping DWH (read-only).
|
||||
shift
|
||||
tht config check -c "$THT_CONFIG"
|
||||
tht db ping -c "$THT_CONFIG" || echo "(db ping non verde: verificare .env/ruoli/VPN)"
|
||||
;;
|
||||
tht)
|
||||
shift
|
||||
exec tht "$@"
|
||||
;;
|
||||
preprocess)
|
||||
shift
|
||||
exec tht evidence index "$@"
|
||||
;;
|
||||
*)
|
||||
exec "$@"
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,66 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
# thothii-core: Fastify (Node 22) + harness Python 3.12 (tht CLI) + runtime Pi.
|
||||
# Singolo container, entrypoint logico "server" (default).
|
||||
ARG PI_VERSION=0.80.2
|
||||
|
||||
# ---- Stage 1: backend TypeScript -> dist ----
|
||||
FROM node:22-bookworm AS backend-build
|
||||
WORKDIR /src/backend
|
||||
COPY backend/package*.json ./
|
||||
RUN npm ci
|
||||
COPY backend/ ./
|
||||
RUN npm run build
|
||||
|
||||
# ---- Stage 2: runtime (Python 3.12 nativo + Node 22 copiato, stesso glibc bookworm) ----
|
||||
FROM python:3.12-slim-bookworm AS runtime
|
||||
ARG PI_VERSION
|
||||
|
||||
# Runtime tools
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl ca-certificates ripgrep fd-find tini \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& ln -s /usr/bin/fdfind /usr/local/bin/fd
|
||||
|
||||
# Node 22 + npm copiati dall'immagine ufficiale (stesso Debian bookworm → binario compatibile)
|
||||
COPY --from=node:22-bookworm /usr/local/bin/node /usr/local/bin/node
|
||||
COPY --from=node:22-bookworm /usr/local/lib/node_modules /usr/local/lib/node_modules
|
||||
RUN ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
|
||||
&& ln -s /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx
|
||||
|
||||
# Utente non-root
|
||||
RUN useradd --create-home --uid 10001 --shell /bin/bash thoth
|
||||
|
||||
# Harness: venv nativo (python 3.12) + tht installato NON editabile (nel venv, indipendente dal path sorgente).
|
||||
# psycopg2-binary è wheel → niente gcc/libpq-dev. yake/sqlglot/datasketch/pydantic hanno wheel per py3.12.
|
||||
COPY harness/ /app/harness/
|
||||
RUN python -m venv /opt/venv \
|
||||
&& /opt/venv/bin/pip install --no-cache-dir --upgrade pip \
|
||||
&& /opt/venv/bin/pip install --no-cache-dir /app/harness
|
||||
# PiProcessManager (backend) prepende harnessDir/.venv/bin al PATH del child Pi → symlink al venv reale
|
||||
RUN ln -s /opt/venv /app/harness/.venv
|
||||
|
||||
# Backend: dist + node_modules (stesso Node major 22 + glibc bookworm → compatibili)
|
||||
COPY --from=backend-build /src/backend/dist /app/backend/dist
|
||||
COPY --from=backend-build /src/backend/node_modules /app/backend/node_modules
|
||||
COPY backend/package*.json /app/backend/
|
||||
|
||||
# Runtime Pi (pacchetto npm puro JS, dipendenze prebuilt). Installato come root, eseguibile da thoth.
|
||||
RUN npm install -g @earendil-works/pi-coding-agent@${PI_VERSION}
|
||||
|
||||
ENV PATH="/opt/venv/bin:/usr/local/bin:$PATH" \
|
||||
HOST=0.0.0.0 PORT=8787 \
|
||||
THT_HARNESS_DIR=/app/harness \
|
||||
THT_BIN=/opt/venv/bin/tht \
|
||||
PI_BIN=pi \
|
||||
HOME=/home/thoth
|
||||
|
||||
COPY docker/core-entrypoint.sh /app/docker/core-entrypoint.sh
|
||||
RUN chmod +x /app/docker/core-entrypoint.sh
|
||||
|
||||
WORKDIR /app/backend
|
||||
USER thoth
|
||||
EXPOSE 8787
|
||||
HEALTHCHECK --interval=15s --timeout=3s --retries=5 --start-period=30s \
|
||||
CMD curl -fsS http://127.0.0.1:8787/health || exit 1
|
||||
ENTRYPOINT ["/usr/bin/tini","--","/app/docker/core-entrypoint.sh"]
|
||||
CMD ["server"]
|
||||
@@ -0,0 +1,21 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
# thothii-frontend: build Vite (React) + nginx-unprivileged (porta 8080).
|
||||
# Build args:
|
||||
# VITE_BASE prefisso asset ("/" standalone, "/datamart-builder/assets/" embedded)
|
||||
# VITE_BACKEND_URL base API ("http://localhost:8787" standalone, "/datamart-builder/api" embedded)
|
||||
FROM node:22-bookworm AS build
|
||||
WORKDIR /src
|
||||
COPY frontend/package*.json ./
|
||||
RUN npm ci
|
||||
COPY frontend/ ./
|
||||
ARG VITE_BASE=/
|
||||
ARG VITE_BACKEND_URL=http://localhost:8787
|
||||
ENV VITE_BASE=$VITE_BASE VITE_BACKEND_URL=$VITE_BACKEND_URL
|
||||
RUN npm run build
|
||||
# typecheck opzionale (non bloccante nella build dell'immagine)
|
||||
RUN npx tsc -b 2>/dev/null || true
|
||||
|
||||
FROM nginxinc/nginx-unprivileged:1.27-alpine AS runtime
|
||||
COPY --from=build /src/dist /usr/share/nginx/html
|
||||
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
EXPOSE 8080
|
||||
@@ -0,0 +1,36 @@
|
||||
# nginx per thothii-frontend: serve la SPA (modalità standalone) e reverse-proxy /api -> core.
|
||||
# In modalità embedded il portale proxya /datamart-builder/assets/ qui (solo asset statici);
|
||||
# il blocco /api non è usato in embedded (il portale hita core direttamente).
|
||||
server {
|
||||
listen 8080;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# SPA fallback (standalone)
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Reverse proxy verso il backend (stessa rete Docker)
|
||||
location /api/ {
|
||||
proxy_pass http://core:8787/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# SSE: niente buffering, timeout lunghi
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
chunked_transfer_encoding on;
|
||||
}
|
||||
|
||||
# manifest.json servito (lo legge il template tag Django in embedded)
|
||||
location = /manifest.json {
|
||||
default_type application/json;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user