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:
- I workload Vue, Spring Boot, Python, Temporal e Keycloak dovevano condividere un solo modello di deploy Kubernetes.
- Le responsabilità di PostgreSQL e MinIO dovevano passare a Cloud SQL e Cloud Storage senza nascondere il cambiamento dietro altri container.
- L’infrastruttura riutilizzabile doveva restare comune, mentre i valori specifici di ogni ambiente dovevano rimanere input revisionabili.
- La pipeline dimostrativa e quella di produzione richiedevano controlli diversi perché esponevano a rischi operativi diversi.
- 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Organizzazione, prodotto, endpoint, configurazione storage, costi, volumi e date di consegna sono omessi. Componenti e sequenza di rilascio provengono dal record di progetto.