Il punto di partenza.

La piattaforma on-premise riuniva un’interfaccia Vue, due servizi Spring Boot, un worker Python Temporal, Temporal, Keycloak, PostgreSQL e MinIO. Gestiva estrazione documentale e workflow assistiti dall’IA, ma gli ambienti non condividevano un percorso di setup affidabile.

Definirla soltanto una migrazione cloud avrebbe descritto la destinazione, non il lavoro. Bisognava spostare con criterio componenti stateful e stateless, separare la delivery dimostrativa da quella di produzione e offrire agli operatori uno switch controllato tra due slot.

Ho scomposto il cambiamento in quattro confini collegati: packaging dei workload, dati gestiti, configurazione degli ambienti e controllo del rilascio. Così “metterla su Kubernetes” non poteva diventare l’intero design.

Cosa doveva risolvere il nuovo modello.

Il disegno della piattaforma doveva rendere espliciti cinque aspetti:

  1. I workload Vue, Spring Boot, Python, Temporal e Keycloak dovevano condividere un solo modello di deploy Kubernetes.
  2. Le responsabilità di PostgreSQL e MinIO dovevano passare a Cloud SQL e Cloud Storage senza nascondere il cambiamento dietro altri container.
  3. L’infrastruttura riutilizzabile doveva restare comune, mentre i valori specifici di ogni ambiente dovevano rimanere input revisionabili.
  4. La pipeline dimostrativa e quella di produzione richiedevano controlli diversi perché esponevano a rischi operativi diversi.
  5. Il rollout di produzione richiedeva uno slot inattivo, smoke test e uno switch manuale esplicito.

La diagnosi.

La parte fragile non era un singolo servizio. Era il percorso dal codice sorgente a un ambiente funzionante. Quando quel percorso cambia da un ambiente all’altro, ogni modifica porta con sé ipotesi nascoste.

Un semplice lift-and-shift avrebbe riprodotto quelle ipotesi in un’altra posizione. Eseguire PostgreSQL e MinIO nel nuovo cluster avrebbe inoltre conservato responsabilità operative che Google Cloud poteva assumere attraverso confini gestiti più chiari.

Ho quindi trattato riproducibilità e reversibilità come requisiti centrali. I moduli Terraform definiscono la base Google Cloud, Helm impacchetta i workload Kubernetes e i valori d’ambiente restano separati dalle definizioni riutilizzabili.

Il modello di piattaforma risultante.

GitLab CI avvia il percorso di produzione, Cloud Build crea le immagini distribuibili e Artifact Registry conserva la versione destinata a GKE. Il deploy raggiunge lo slot blue/red inattivo. Readiness Kubernetes e smoke test devono riuscire prima che un operatore sposti il traffico; Cloud SQL e Cloud Storage sostituiscono le responsabilità autogestite di PostgreSQL e MinIO.

Il modello di piattaforma risultante. Build unica, verifica sullo slot inattivo e switch di produzione esplicito.VISTA DEL SISTEMA / CLOUDGITLAB CICLOUD BUILDARTIFACTREGISTRYGKE BLUE / REDCLOUD SQL + GCSPERCORSO DI DELIVERY VERSIONATO
Build unica, verifica sullo slot inattivo e switch di produzione esplicito.

Perché queste tecnologie erano adatte alla migrazione.

Erano scelte compiute dentro un prodotto esistente e una destinazione Google Cloud già definita, non una classifica greenfield di ogni piattaforma possibile. La domanda utile era quali confini rendessero ripetibile e gestibile questo insieme concreto di workload.

T01 La scelta

GKE come confine comune per i workload

Perché
La piattaforma riuniva già un’interfaccia Vue, servizi Spring Boot, un worker Python, Temporal e Keycloak. GKE offriva a workload diversi un unico modello di distribuzione, readiness e slot blue/red, mentre i dati gestiti uscivano dal cluster.
Cosa ho escluso
Distribuire i componenti tra prodotti serverless avrebbe imposto più modelli di esecuzione allo stesso rilascio; VM persistenti avrebbero conservato una parte maggiore del setup e della manutenzione specifici per host.
Quanto è costata
Il team accetta la superficie operativa di Kubernetes, il ciclo di vita del cluster e la necessità di rendere espliciti risorse, readiness e aggiornamenti dei workload.
T02 La scelta

Moduli Terraform per la base Google Cloud

Perché
I moduli riutilizzabili mantenevano unite le definizioni comuni e rendevano le differenze tra ambienti input visibili e revisionabili. Era una risposta diretta al setup specifico per ambiente che la migrazione doveva eliminare.
Cosa ho escluso
Configurazione da console o template copiati avrebbero creato più rapidamente il primo ambiente, ma le modifiche successive sarebbero state meno verificabili e ogni copia avrebbe potuto divergere da sola.
Quanto è costata
Contratti dei moduli, stato dei provider e cambi di versione richiedono disciplina; anche una piccola eccezione infrastrutturale va modellata invece di essere corretta a mano in silenzio.
T03 La scelta

Helm per impacchettare i workload Kubernetes

Perché
Helm forniva un’unità di rilascio per le risorse collegate e un punto controllato per i valori d’ambiente, senza copiare l’intera definizione per ogni ambiente e slot.
Cosa ho escluso
Manifest Kubernetes non templati sarebbero stati più diretti per un singolo deploy, ma duplicarli tra ambienti e slot blue/red avrebbe reso meno distinguibili modifiche condivise e differenze intenzionali.
Quanto è costata
Template e valori introducono un livello di indirezione: l’output renderizzato va ispezionato e le modifiche al chart vanno versionate con la stessa cura del codice applicativo.
T04 La scelta

Responsabilità separate tra Cloud Build e GitLab CI

Perché
Cloud Build produceva le immagini nel percorso Google Cloud, mentre GitLab CI manteneva orchestrazione produttiva, verifiche e decisione esplicita sul traffico. La separazione rifletteva le conseguenze diverse di creare un artefatto e rilasciarlo.
Cosa ho escluso
Un’unica pipeline di deploy indistinta sarebbe stata più semplice da descrivere, ma avrebbe confuso controlli dimostrativi e produttivi e legato in una sola azione build, rollout e spostamento del traffico.
Quanto è costata
Due sistemi richiedono credenziali, passaggio degli artefatti e diagnosi degli errori attraverso un confine; i loro contratti devono restare allineati.

Regole operative per un rilascio reversibile.

Lo stack definisce il percorso; queste regole chiariscono chi possiede lo stato, quali segnali valgono come evidenza e come cambiare la produzione senza trasformare il passaggio in un salto irreversibile.

D01

Rendere revisionabili le differenze tra ambienti

Prima di un rilascio, i valori specifici dell’ambiente e le responsabilità sullo stato sono visibili insieme, compreso chi risponde di dati, backup e ripristino. Ogni differenza diventa un input o un passaggio esplicito, non una correzione invisibile sull’ambiente in esecuzione.

Il compromessoRevisionare differenze e responsabilità richiede più preparazione, ma impedisce che drift di configurazione o compiti di ripristino senza proprietario emergano durante il cutover.

D02

Verificare il candidato da un estremo all’altro

Il candidato al rilascio viene seguito dall’immagine costruita fino all’ambiente inattivo, poi verificato con readiness, segnali infrastrutturali e smoke test. Nessun singolo indicatore verde sostituisce l’intero percorso.

Il compromessoRichiede più tempo che accettare una build riuscita come prova; lo smoke test resta intenzionalmente circoscritto e non pretende di coprire ogni workflow di business.

D03

Separare l’evidenza sull’artefatto dall’autorità sul traffico

Una build riuscita crea un candidato, ma non gli concede accesso alla produzione. Lo stesso artefatto viene distribuito e provato sullo slot blue/red inattivo, mentre la decisione di spostare il traffico resta un’azione distinta dell’operatore.

Il compromessoQuesta governance aggiunge passaggi di responsabilità e richiede che entrambi gli slot restino pronti, ma impedisce di scambiare il successo della build per un’approvazione al rilascio.

D04

Rendere il cutover esplicito e reversibile

Il traffico si sposta soltanto quando le verifiche sono visibili e un operatore approva il passaggio. Lo slot precedente resta il percorso di ritorno chiaro invece di essere sovrascritto.

Il compromessoIl gate introduce una pausa intenzionale, ma mantiene visibili l’autorità finale sulla produzione e la possibilità di tornare indietro quando le evidenze sono incomplete.

Delivery e verifica.

Ho ordinato il lavoro seguendo dipendenze e reversibilità: base Google Cloud, packaging dei workload, valori d’ambiente esternalizzati, spostamento delle responsabilità sui dati e infine esercizio del percorso di rilascio prima dello switch produttivo.

I percorsi dimostrativo e produttivo restano distinti. La produzione passa da GitLab CI a Cloud Build e Artifact Registry prima di raggiungere lo slot GKE inattivo, invece di sovrascrivere quello live.

La verifica combina readiness Kubernetes, alert e segnali Google Cloud con uno smoke test prima dello switch. Non prova ogni flusso di business. Stabilisce che il candidato è abbastanza sano per un cutover controllato.

Il risultato consegnato.

La migrazione ha sostituito un percorso on-premise specifico per ambiente con moduli infrastrutturali riutilizzabili, workload impacchettati, servizi dati gestiti e due slot produttivi controllati.

Il risultato utile non è semplicemente “gira su Google Cloud”. È un percorso di rilascio revisionabile prima del deploy, verificabile prima dello spostamento del traffico e ripetibile per l’ambiente successivo.

Non associo al risultato una percentuale inventata di velocità o affidabilità. Il cambiamento difendibile è strutturale: meno ipotesi specifiche per ambiente, responsabilità operative esplicite e una decisione produttiva reversibile.

Cosa dimostra questo caso

Organizzazione, prodotto, endpoint, configurazione storage, costi, volumi e date di consegna sono omessi. Componenti e sequenza di rilascio provengono dal record di progetto.