Skip to content

Solution design architettura cloud ​

Deliverable D2.1.2: Solution Design Architettura Cloud

Principi guida ​

Il progetto MAPS tratta dati pubblici italiani a granularità comunale, con volumi nell'ordine delle decine di gigabyte e un team operativo ristretto. L'architettura cloud è progettata attorno a tre principi derivati da questo contesto.

Il primo è la prevedibilità dei costi. Le piattaforme cloud di grandi dimensioni (AWS, GCP, Azure) adottano modelli di pricing variabile — per query, per GB processato, per request — che rendono difficile stimare la spesa mensile in anticipo. Per un progetto di ricerca con budget definito, questo rischio è inaccettabile. L'infrastruttura scelta adotta tariffazione a canone fisso mensile per tutte le componenti principali.

Il secondo è la semplicità operativa. La complessità gestionale deve essere proporzionale alla scala del progetto. Servizi managed (cluster Kubernetes, database PostgreSQL) eliminano gli oneri di manutenzione del control plane, degli aggiornamenti di sicurezza e della gestione dei backup, lasciando al team la sola responsabilità dei workload applicativi.

Il terzo è l'adeguatezza alla scala. L'infrastruttura è dimensionata sui carichi di lavoro reali del progetto: circa 200 dataset a granularità comunale, pipeline ETL in modalità batch sporadica, un numero di utenti concorrenti nell'ordine delle unità. Non è necessario progettare per carichi enterprise.

Scelta del provider: DigitalOcean ​

L'infrastruttura è ospitata su DigitalOcean. Rispetto agli hyperscaler (AWS, GCP, Azure), DigitalOcean offre un'esperienza di gestione più lineare, una curva di apprendimento contenuta e un pannello di controllo che non richiede competenze cloud specialistiche. La tariffazione è a canone fisso mensile per tutte le risorse principali (nodi del cluster, database managed, storage a blocchi, load balancer), con assenza di meccanismi di pricing variabile.

DigitalOcean supporta le estensioni PostGIS nel servizio di database managed, requisito essenziale per le operazioni spaziali del progetto. Il catalogo di servizi copre tutti i componenti necessari all'architettura MAPS senza richiedere integrazioni con provider esterni.

Orchestrazione container: Kubernetes (DOKS) ​

I servizi della piattaforma sono distribuiti come container orchestrati da Kubernetes, nella versione managed offerta da DigitalOcean (DOKS — DigitalOcean Kubernetes Service).

La scelta di Kubernetes rispetto a Docker Compose è motivata da tre considerazioni. La prima è la gestione dichiarativa dell'infrastruttura: Kubernetes descrive lo stato desiderato del sistema in manifest versionabili, con convergenza automatica. Se un container si arresta viene ricreato; se un nodo diventa indisponibile i carichi vengono redistribuiti su quelli rimanenti. Docker Compose non offre equivalenti per il self-healing né per la distribuzione su nodi multipli.

La seconda è la separazione dei carichi di lavoro. I servizi della piattaforma hanno profili di consumo risorse molto diversi: le pipeline ETL di Prefect sono CPU-intensive e sporadiche, PostgreSQL richiede I/O disco costante, OpenMetadata e CKAN hanno un consumo moderato ma continuo. Kubernetes permette di allocare risorse (CPU request e limit, memoria) per singolo servizio, evitando che un picco di un componente degradi gli altri.

La terza è la prospettiva di evoluzione. Il progetto prevede fasi successive che introdurranno nuovi servizi e un numero maggiore di utenti. Kubernetes supporta questa crescita senza richiedere una migrazione architetturale: aggiungere nodi al cluster o nuovi deployment è un'operazione ordinaria.

DOKS elimina la complessità di gestione del control plane (API server, etcd, scheduler), che resta a carico del provider, lasciando al team la sola gestione dei workload applicativi.

Database: managed vs self-hosted ​

La scelta tra un'istanza PostgreSQL gestita come servizio managed (DigitalOcean Managed Databases) e un'istanza self-hosted nel cluster Kubernetes ha implicazioni su costi, operatività e flessibilità.

Con il servizio managed, il provider gestisce backup automatici con point-in-time recovery, failover automatico, patching di sicurezza e aggiornamenti di versione. L'overhead operativo è minimo. Il limite principale è la minore flessibilità nella configurazione: parametri di tuning avanzati ed estensioni non standard potrebbero non essere disponibili. Il costo è superiore rispetto al self-hosted a parità di risorse allocate (indicativamente 20-30% in più), ma il risparmio in ore di manutenzione compensa ampiamente per un team ristretto.

Con PostgreSQL self-hosted nel cluster (tramite un operatore Kubernetes come CloudNativePG o Zalando Postgres Operator) si ottiene pieno controllo su configurazione, estensioni e tuning. L'onere operativo è maggiore: backup, monitoring, failover e aggiornamenti sono a carico del team.

CriterioManaged DatabaseSelf-Hosted (K8s Operator)
Backup e recoveryAutomatico (daily, PITR)Da configurare
FailoverAutomaticoGestito dall'operatore
PostGISSupportatoPieno controllo
Tuning avanzatoLimitatoCompleto
Costo (4 vCPU, 8 GB)~$80/mese~$48/mese (risorse cluster)
Overhead operativoBassoMedio-alto
Estensioni customLista predefinitaQualsiasi

Per la fase MVP il database managed è l'opzione raccomandata: riduce il rischio operativo e consente al team di concentrarsi sullo sviluppo delle pipeline. La migrazione a self-hosted resta possibile in qualsiasi momento, se emergessero requisiti di configurazione specifica non supportati dal servizio managed.

Dimensionamento dell'infrastruttura ​

Profilo dei carichi di lavoro ​

Le fonti dati del progetto hanno frequenza di aggiornamento tipicamente semestrale o annuale. Le pipeline ETL di Prefect operano quindi in modalità batch sporadica: l'esecuzione avviene quando una fonte pubblica un aggiornamento, o durante le fasi di primo caricamento massivo dei dataset. I picchi di CPU sono concentrati nelle fasi di parsing PDF con Docling e nelle trasformazioni spaziali PostGIS, ma si verificano in modo occasionale. I servizi web (CKAN, OpenMetadata, Prefect UI) hanno un consumo costante ma contenuto, con utenti concorrenti nell'ordine delle unità.

Configurazione del cluster ​

Un cluster con tre nodi di tipo General Purpose da 4 vCPU e 8 GB di RAM ciascuno è sufficiente per garantire disponibilità e distribuzione dei carichi. La distribuzione indicativa dei workload è la seguente:

ComponenteCPU requestMemoria requestStorageNote
PostgreSQL + PostGIS2 vCPU4 GB100 GB (block storage)Solo se self-hosted
Prefect Server0.5 vCPU1 GB10 GBUI e orchestrazione
Prefect Worker2 vCPU4 GB50 GB (Bronze files)Burst durante ETL
OpenMetadata1 vCPU2 GB20 GBCatalogo e lineage
CKAN + Redis1 vCPU2 GB20 GBCatalogo pubblico
Ingress Controller0.25 vCPU256 MB-Traffico HTTPS

In condizioni ordinarie il cluster richiede circa 7 vCPU e 13 GB di RAM, con picchi fino a 10 vCPU durante le esecuzioni ETL. Tre nodi da 4 vCPU / 8 GB (totale 12 vCPU / 24 GB) offrono il margine necessario per i picchi e per tollerare la perdita di un nodo senza interruzione del servizio.

Storage ​

DigitalOcean Volumes (block storage) forniscono lo storage persistente per il database e per il Bronze layer. Il volume database è dimensionato a 100 GB con possibilità di espansione a caldo. Il Bronze layer richiede circa 50 GB per i file originali, anch'esso espandibile. I volumi sono replicati dal provider con protezione contro il guasto del singolo disco.

Stima dei Costi Mensili ​

VoceConfigurazioneCosto mensile
DOKS cluster (control plane)Managed$12
3 nodi General Purpose4 vCPU / 8 GB ciascuno$192 ($64/nodo)
Managed PostgreSQL4 vCPU / 8 GB, 100 GB storage$80
Block storage (150 GB)Bronze + dati applicativi$15
Load BalancerIngress HTTPS$12
Totale~$311/mese (~$3.700/anno)

Se il database è self-hosted nel cluster, il costo del Managed PostgreSQL ($80/mese) viene eliminato, riducendo il totale a circa $231/mese (~$2.770/anno), a fronte di un maggiore impegno operativo.

Topologia dei servizi ​

graph TB
    subgraph "Internet"
        U[Utenti / API Client]
    end

    subgraph "DigitalOcean"
        LB[Load Balancer
HTTPS Termination] subgraph "DOKS Cluster (3 nodi)" subgraph "Namespace: maps-app" PS[Prefect Server] PW[Prefect Worker] OM[OpenMetadata] CK[CKAN] RD[Redis] end subgraph "Namespace: maps-data" PG["PostgreSQL + PostGIS
(se self-hosted)"] BZ[Bronze Storage
Persistent Volume] end subgraph "Namespace: ingress" IC[Ingress Controller] end end MDB["Managed PostgreSQL
(se managed)"] end U --> LB LB --> IC IC --> PS IC --> OM IC --> CK PS --> PW PW --> PG PW --> MDB PW --> BZ OM --> PG OM --> MDB CK --> RD CK --> PG CK --> MDB

I servizi sono organizzati in namespace Kubernetes distinti per separare i carichi applicativi dai dati persistenti. L'Ingress Controller gestisce il traffico HTTPS in ingresso e il routing verso i servizi esposti (Prefect UI, OpenMetadata, CKAN). I servizi interni (Prefect Worker, Redis) non sono esposti all'esterno e comunicano esclusivamente sulla rete interna del cluster.

Sicurezza ​

Isolamento di rete ​

Kubernetes Network Policies restringono la comunicazione tra pod: i servizi applicativi possono raggiungere il database, ma non comunicano tra loro se non necessario. L'Ingress Controller è l'unico punto di ingresso dall'esterno, con terminazione TLS e certificati gestiti automaticamente tramite cert-manager e Let's Encrypt.

Controllo degli accessi al database ​

PostgreSQL implementa un modello di autorizzazione a tre livelli: un ruolo maps_writer con permessi di scrittura sugli schemi Bronze e Silver, un ruolo maps_reader con accesso in sola lettura al Gold layer, e un ruolo maps_api con accesso limitato alle sole tabelle esposte dalle applicazioni web. Questa separazione garantisce che le pipeline ETL non possano alterare i dati pubblicati, e che i servizi pubblici non possano accedere ai dati grezzi o intermedi.

Gestione dei segreti ​

Le credenziali sono gestite tramite un sistema di secret management esterno al cluster (AWS Secrets Manager o equivalente), che funge da source of truth per tutti i segreti dell'infrastruttura. I segreti vengono iniettati nei pod Kubernetes tramite External Secrets Operator, che sincronizza automaticamente i valori verso Kubernetes Secrets. Le API key per i servizi esterni sono configurate come Prefect Secret Blocks, anch'essi alimentati dallo stesso meccanismo. Nessuna credenziale è archiviata nei manifest Kubernetes o nel repository del codice.