Runbook: distribuzione del runner ETL
Il servizio è distribuito come immagine container con entrypoint la CLI etl. Questo runbook copre la build, la pubblicazione su ECR e la modalità batch (etl run, non un daemon: un container = una esecuzione di pipeline, poi termina).
Il CMD di default dell'immagine però è serve: server HTTP dei grafi e worker nello stesso processo, un solo container per tutta la piattaforma (ADR-0028, runbook graph-server.md). Il worker da solo (etl worker, poller sulla tabella processes di Noeva, anche multi-workspace) è in etl-worker.md, ADR-0019 e ADR-0021: mai un container worker in parallelo a un serve, o i job vengono presi due volte.
Configurazione solo da variabili d'ambiente (nessun segreto nell'immagine).
La UI non si deploya da qui.
noeva-etl-uiè un'app desktop Tauri, buildata nel suo submodule conpnpm tauri build(ADR-0025, che supera ADR-0023). Il deploy nginx/ECR della UI e i flag--ui/--no-uidegli script sono stati rimossi.
Modello d'uso attuale: l'immagine è pubblicata su ECR e viene scaricata ed eseguita in locale su Docker Desktop. La build è multi-arch, quindi su Apple Silicon gira nativa. L'esecuzione in cloud (ECS) è rinviata a una valutazione futura (ADR-0005).
CLI
etl list # elenca le pipeline disponibili
etl run <pipeline> # esegue una pipeline (es. langfuse-sessions-daily)
etl serve # default dell'immagine: grafi via HTTP + worker
etl worker # solo i workerIn sviluppo: pnpm run etl run <pipeline> (precarica .env).
Build & pubblicazione (ECR)
Usa lo script deploy-ecr.sh: esegue il quality gate, login ECR, crea il repository se assente, build multi-arch (linux/amd64,linux/arm64) e push. Pubblica solo l'immagine del runner: lo script rifiuta qualunque flag --*.
Ogni deploy pubblica sempre:
latest— usato per pull/run in locale;<YYYYmmdd-HHMMSS>— tag temporale immutabile (tracciabilità / rollback).
Un terzo tag versione (es. v0.2.0) è opzionale, come 4° argomento.
# ./deploy-ecr.sh [AWS_PROFILE] [AWS_REGION] [ECR_REPOSITORY_NAME] [VERSION_TAG]
./deploy-ecr.sh # → latest + timestamp
./deploy-ecr.sh default eu-west-1 gruppo4d/noeva-etl v0.2.0 # + tag v0.2.0
# opzioni utili
SKIP_CHECK=1 ./deploy-ecr.sh # salta il gate `pnpm run check` (sconsigliato)
PLATFORMS=linux/amd64 ./deploy-ecr.sh # solo amd64Gli argomenti posizionali si possono dare anche come variabili d'ambiente (AWS_PROFILE, AWS_REGION, ECR_REPOSITORY_NAME, VERSION_TAG).
Requisiti: AWS CLI, Docker con buildx, pnpm. (Per GHCR o un altro registry cambia il login; la build dell'immagine è identica.)
Esecuzione in locale (Docker Desktop)
Modo rapido con lo script run-ecr.sh (login + pull + run, batch in foreground):
./run-ecr.sh # nessun argomento → elenco pipeline (etl list)
./run-ecr.sh langfuse-sessions-daily # pull :latest ed esegue la pipeline
./run-ecr.sh langfuse-sessions-daily 20260603-200239 # tag specificoLo script passa ETL_RELEASE=<tag immagine> al container, così il report registra quale release ha eseguito la run (campo version).
Equivalente manuale:
docker pull <account>.dkr.ecr.<region>.amazonaws.com/gruppo4d/noeva-etl:latest
docker run --rm --env-file .env <...>/gruppo4d/noeva-etl:latest run langfuse-sessions-dailyDB sull'host: dentro il container
localhostè il container stesso. Per raggiungere DB in esecuzione sull'host (es. i container di test), impostare le variabili*HOSTahost.docker.internal(lo script aggiunge già l'alias anche su Linux).
Esecuzione
# una tantum: la tabella di destinazione deve esistere (DDL versionata in sql/)
docker run --rm <image> list
docker run --rm --env-file .env <image> run langfuse-sessions-dailyVariabili richieste: quelle della pipeline, elencate nella sua scheda e in .env.example (per langfuse-sessions-daily: PG* sorgente e MSSQL_* sink), più ETL_ENV e ETL_LOG_LEVEL. In produzione iniettarle da un secret manager (AWS Secrets Manager / SSM), non da .env.
Modelli di deploy per cliente
Il servizio gira tipicamente sull'infra del cliente. L'immagine ECR abilita tutti i casi:
| Modello | Come | Note |
|---|---|---|
| Gestito da noi | ECS Scheduled Task (Fargate) + EventBridge, definiti in Terraform | Retry, log CloudWatch, parità staging/prod |
| ECS del cliente | Stessa immagine, task definition nel loro account | Solo accesso al registry + secrets del cliente |
| Docker locale del cliente | docker run schedulato da cron sul loro host | Più semplice; idempotenza rende sicuri retry/sovrapposizioni |
Scheduling
La pipeline è idempotente (upsert/MERGE su chiave naturale): rieseguire o sovrapporre run non duplica dati. Quindi lo scheduler può essere semplice:
- cron che lancia
docker run ... run <pipeline>; - ECS Scheduled Task (cron via EventBridge);
- per dipendenze/backfill complessi in futuro → orchestratore (es. Temporal TS).
Networking
Il container deve raggiungere sorgente e sink (PG e SQL Server), che possono stare su host/VPC diversi. In locale, dai container verso DB sull'host: usare host.docker.internal come *HOST. In cloud: curare security group / routing verso entrambi i DB.
Osservabilità — il report di run è il risultato
Il servizio è stateless: emette un report e termina (niente DB lato servizio).
stdout= il report in JSON (un oggetto).stderr= log umani.- exit code:
0sesuccess/partial,≠0sefailed(utile per alerting dello scheduler). - Anche in errore viene emesso un report
status: "failed".
# cattura il report e i log separatamente
./run-ecr.sh langfuse-sessions-daily > report.json 2> run.log
# archivialo dove vuoi (è il chiamante a deciderlo): file, S3, CloudWatch, ...Schema completo e semantica: docs/conventions/run-report.md · ADR-0006.

