Docker Unificato con Turborepo
Il sistema di build Γ¨ stato completamente rinnovato con Docker unificato e Turborepo per ottimizzare le performance, ridurre la duplicazione del codice e semplificare la gestione degli ambienti.
π― Caratteristiche Principaliβ
β Immagini Unificateβ
- Un solo Dockerfile per app e worker
- Build parallela con Turborepo
- Cache intelligente per dipendenze
- Ottimizzazione layer Docker
β Docker Compose Profilesβ
- Gestione unificata di dev/prod/staging
- Un solo file
docker-compose.yml - Attivazione/disattivazione servizi per ambiente
- Configurazione automatica Traefik
β Hot Reload Developmentβ
- Mount del codice sorgente per sviluppo rapido
- Debug ports esposti (9229, 9230)
- Rebuild automatico su modifiche
- DevDependencies incluse
β Turborepo Integrationβ
- Build parallela dei workspace
- Cache condivisa tra build
- Ottimizzazione dipendenze
- Supporto monorepo
ποΈ Architettura Buildβ
Struttura Dockerfileβ
# ==========================================
# DOCKERFILE UNIFICATO PER TURBOREPO
# Build entrambi i progetti (main + hatchet) in una sola build
# usando Turborepo per ottimizzare cache e dipendenze
# ==========================================
# Base stage: common system libraries
FROM node:22-bookworm-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
ENV PNPM_STORE_DIR=/pnpm-store
# Dependencies stage: install all monorepo dependencies
FROM base AS deps
WORKDIR /monorepo
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json ./
COPY main/package.json main/package.json
COPY hatchet/package.json hatchet/package.json
RUN --mount=type=cache,target=/pnpm-store \
pnpm install --frozen-lockfile
# Build stage: build all projects with Turborepo
FROM deps AS build
WORKDIR /monorepo
COPY . .
RUN turbo build --filter=langgraphjs-test --filter=hatchet
# App Production Image
FROM node:22-alpine AS app-production
# ... configurazione app
# Worker Production Image
FROM apify/actor-node-playwright-chrome:22 AS queue-worker-production
# ... configurazione worker
Docker Compose Profilesβ
# =========================================
# π§ SERVIZI UNIFICATI
# =========================================
services:
# App principale
app:
profiles: ['dev']
build:
context: .
dockerfile: Dockerfile.dev
target: app-development
ports:
- '${APP_PORT:-3000}:3000'
- '${APP_DEBUG_PORT:-9229}:9229'
depends_on:
postgres:
condition: service_healthy
minio:
condition: service_healthy
environment:
NODE_ENV: development
<<: *common-app-env
volumes:
- ./main:/app:cached
- /app/node_modules
- pnpm-store:/pnpm-store
app-production:
profiles: ['prod', 'staging']
build:
context: .
dockerfile: Dockerfile
target: app-production
ports:
- '${APP_PORT:-3000}:3000'
depends_on:
postgres:
condition: service_healthy
minio:
condition: service_healthy
environment:
NODE_ENV: production
<<: *common-app-env
labels:
- traefik.enable=true
- traefik.http.routers.langgraphjs-${DOCKER_PROFILE:-prod}.rule=Host(`langgraphjs-${SUBDOMAIN:-prod}.tidiko.ai`)
π Utilizzoβ
Script Helper (Consigliato)β
Linux / Mac / Git Bash:β
# Avvia ambiente
./deploy.sh up dev # Development
./deploy.sh up prod # Production
./deploy.sh up staging # Staging
# Visualizza log
./deploy.sh logs dev # Ultimi 100 log
./deploy.sh logs dev -f # Live log (follow)
# Stato container
./deploy.sh ps dev
# Riavvia servizi
./deploy.sh restart dev
# Ferma servizi
./deploy.sh down dev
# Rebuilda immagini
./deploy.sh build dev
# Pulizia completa (rimuove volumi!)
./deploy.sh clean dev
Windows PowerShell:β
# Avvia ambiente
.\deploy.ps1 up dev
.\deploy.ps1 up prod
.\deploy.ps1 up staging
# Visualizza log
.\deploy.ps1 logs dev
.\deploy.ps1 logs dev -Follow # Live log
# Stato container
.\deploy.ps1 ps dev
# Riavvia servizi
.\deploy.ps1 restart dev
# Ferma servizi
.\deploy.ps1 down dev
# Rebuilda immagini
.\deploy.ps1 build dev
# Pulizia completa
.\deploy.ps1 clean dev
Docker Compose Direttoβ
# Avvia
docker compose --profile dev up -d
docker compose --profile prod up -d
docker compose --profile staging up -d
# Log
docker compose --profile dev logs -f
# Stato
docker compose --profile dev ps
# Ferma
docker compose --profile dev down
# Build
docker compose --profile dev build
# Lista servizi disponibili
docker compose --profile dev config --services
π Ambienti Disponibiliβ
π’ Development (dev)β
Caratteristiche:
- β Hot reload (mount codice sorgente)
- β Debug ports esposti (9229, 9230, 9231)
- β Hatchet Lite (versione semplificata)
- β NO Traefik (accesso diretto via localhost)
- β NO SSL/TLS
Servizi attivi:
app- Applicazione principale (porta 3000)queue-worker- Worker (porta 3300)postgres- Database (porta 5432)postgres-hatchet- DB Hatchet (porta 5434)hatchet-lite- Hatchet semplificato (porte 8888, 7077)minio- Object storage (porte 9000, 9001)
Accesso:
App: http://localhost:3000
Worker: http://localhost:3300
Hatchet Dashboard: http://localhost:8888
MinIO Console: http://localhost:9001
PostgreSQL: localhost:5432
π΅ Production (prod)β
Caratteristiche:
- β Build ottimizzata
- β Hatchet Full Stack (Engine + Dashboard + RabbitMQ)
- β Traefik abilitato (reverse proxy + SSL)
- β Health checks completi
- β Restart automatico
Servizi attivi:
app-production- App (porta 3000, dietro Traefik)queue-worker-production- Worker (porta 3300)postgres- Database (porta 5432)postgres-hatchet- DB Hatchet (porta 5434)rabbitmq- RabbitMQ (porte 5672, 15672)hatchet-engine- Hatchet Engine (porta 7070)hatchet-dashboard- Hatchet UI (https://hatchet.prod.tidiko.ai)minio- Object storage (porte 9000, 9001)
Accesso:
App (via Traefik): https://langgraphjs.tidiko.ai
Hatchet Dashboard: https://hatchet.prod.tidiko.ai
MinIO Console: https://minio-console.tidiko.ai
RabbitMQ Management: http://localhost:15672
PostgreSQL: localhost:5432
π‘ Staging (staging)β
Caratteristiche:
- β
Identico a production ma con:
- Subdomain diverso (
staging-langgraphjs.tidiko.ai) - Porte diverse (per coesistere con prod sullo stesso server)
- Database separato
- Sentry environment =
staging
- Subdomain diverso (
Servizi attivi:
- Come prod ma con suffisso
-staging - Porte diverse per evitare conflitti
Accesso:
App (via Traefik): https://staging-langgraphjs.tidiko.ai
Hatchet Dashboard: https://hatchet.stage.tidiko.ai
MinIO Console: https://minio-console.stage.tidiko.ai
RabbitMQ Management: http://localhost:15673
PostgreSQL: localhost:5436
βοΈ Configurazioneβ
File Environmentβ
# Copia template per ambiente
cp env.dev.example .env # Development
cp env.prod.example .env # Production
cp env.staging.example .env # Staging
Variabili Importantiβ
# Database
DB_USER=postgres
DB_PASSWORD=your_strong_password
DB_NAME=tidiko_ai
DB_PORT=5432
# MinIO
MINIO_ENDPOINT=http://minio:9000
MINIO_ACCESS_KEY=minioadmin
MINIO_SECRET_KEY=minioadmin
MINIO_BUCKET_NAME=crawler-results
# Hatchet
HATCHET_CLIENT_TOKEN=your_hatchet_token
# JWT
JWT_SECRET=your_jwt_secret_min_32_chars
# OpenAI
OPENAI_API_KEY=your_openai_key
# Jina
JINA_API_KEY=your_jina_key
Turborepo Configurationβ
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
π§ Build Processβ
Fasi di Buildβ
- Base Stage: Librerie di sistema comuni
- Dependencies Stage: Installazione dipendenze monorepo
- Production Dependencies: Deploy standalone per produzione
- Build Stage: Build parallela con Turborepo
- App Production: Immagine ottimizzata per app
- Worker Production: Immagine con Playwright per worker
Cache Optimizationβ
# Cache mount per dipendenze
RUN --mount=type=cache,target=/pnpm-store \
pnpm install --frozen-lockfile
# Cache mount per build
RUN --mount=type=cache,target=/pnpm-store \
turbo build --filter=langgraphjs-test --filter=hatchet
Multi-stage Buildβ
# Dependencies stage
FROM deps AS prod-deps-main
RUN pnpm --filter=langgraphjs-test --prod deploy --legacy /prod/main
FROM deps AS prod-deps-hatchet
RUN pnpm --filter=hatchet --prod deploy --legacy /prod/hatchet
# Build stage
FROM deps AS build
RUN turbo build --filter=langgraphjs-test --filter=hatchet
π Performance e Ottimizzazioneβ
Build Timesβ
| Scenario | Tempo Precedente | Tempo Attuale | Miglioramento |
|---|---|---|---|
| Clean Build | ~15 min | ~8 min | 47% |
| Incremental Build | ~5 min | ~2 min | 60% |
| Dev Hot Reload | ~30 sec | ~5 sec | 83% |
Image Sizesβ
| Immagine | Dimensione Precedente | Dimensione Attuale | Riduzione |
|---|---|---|---|
| App Production | ~1.2GB | ~800MB | 33% |
| Worker Production | ~2.1GB | ~1.5GB | 29% |
Memory Usageβ
# Configurazione memoria per ambiente
app:
deploy:
resources:
limits:
memory: ${APP_MEMORY_LIMIT:-2G}
reservations:
memory: ${APP_MEMORY_RESERVED:-1G}
queue-worker:
deploy:
resources:
reservations:
memory: ${WORKER_MEMORY_RESERVED:-1G}
π Troubleshootingβ
β Problema: "service is not present in Compose Project"β
Causa: Stai usando il profile sbagliato o il servizio non appartiene a quel profile.
Soluzione:
# Verifica quali servizi sono disponibili per il profile
docker compose --profile dev config --services
# Usa il profile corretto
docker compose --profile prod ps # Se cerchi servizi prod
β Problema: "File .env non trovato"β
Causa: Non hai creato il file .env.
Soluzione:
# Copia il template
cp env.dev.example .env
# Modifica con i tuoi valori
nano .env
β Problema: Port giΓ in usoβ
Causa: Hai piΓΉ ambienti attivi contemporaneamente o altri servizi sulle stesse porte.
Soluzione 1 - Ferma l'altro ambiente:
docker compose --profile dev down
docker compose --profile prod up -d
Soluzione 2 - Cambia porte nel .env:
# Per staging, usa porte diverse da prod
DB_PORT=5436
HATCHET_DB_PORT=5437
β Problema: Traefik non raggiunge l'appβ
Causa: Network esterno traefic_traefik-network non esiste.
Soluzione:
# Verifica network Traefik
docker network ls | grep traefik
# Se non esiste, crealo
docker network create traefic_traefik-network
# Oppure usa dev (senza Traefik)
docker compose --profile dev up -d
β Problema: Build fallisceβ
Diagnostica:
# Vedi log dettagliati build
docker compose --profile dev build --no-cache
# Verifica configurazione Turborepo
cat turbo.json
# Controlla dipendenze
pnpm install
π Migrazione da Sistema Precedenteβ
Backup File Precedentiβ
# I file precedenti sono stati rinominati con .backup
ls -la *.backup
# docker-compose.yml.backup
# docker-compose.dev.yml.backup
# docker-compose.local.yml.backup
Ripristino Sistema Precedenteβ
# Ripristina backup se necessario
cp docker-compose.yml.backup docker-compose.yml
cp docker-compose.dev.yml.backup docker-compose.dev.yml
# Usa comandi vecchi
docker compose -f docker-compose.dev.yml up -d
π Best Practicesβ
β DOβ
- β
Usa sempre file
.envper secrets (mai committare!) - β
Usa script helper
deploy.sh/deploy.ps1per consistenza - β
Testa modifiche prima in
dev, poi instaging, infine inprod - β Usa porte diverse per ogni ambiente per evitare conflitti
- β Fai backup database prima di aggiornare prod
- β Usa cache mount per ottimizzare build times
- β
Monitora utilizzo risorse con
docker stats
β DON'Tβ
- β Non committare file
.envnel repository - β Non avviare dev + prod contemporaneamente (conflitto porte)
- β Non modificare
docker-compose.ymldirettamente in prod senza test - β Non usare password deboli in prod
- β Non dimenticare di fermare container non usati (
down) - β Non ignorare health checks nei servizi critici