Principi cloud-native e 12-factor

Progettare cloud-native significa costruire microservizi indipendenti, rilasciabili singolarmente e comunicanti via API, seguendo i principi 12-factor. I punti che l’esame premia: la configurazione vive nell’ambiente (mai hardcoded nel codice), i backing service (database, cache, code) sono risorse collegate e sostituibili, i log sono un flusso di eventi su stdout/stderr raccolto dalla piattaforma (in Cloud Logging), e i processi sono stateless e disposable — devono poter partire e morire in fretta senza perdere dati.

Stateless non vuol dire “senza stato”, ma stato esternalizzato: la sessione utente, i file, i contatori non vivono nella memoria dell’istanza (che scala e viene distrutta), bensì in backing service dedicati. Sessione e cache condivisa vanno in Memorystore (Redis/Memcached gestito); i dati persistenti in Firestore, Cloud SQL o Spanner; i file utente in Cloud Storage (spesso serviti al client con un signed URL a scadenza, senza esporre le credenziali). Questo abilita autoscaling orizzontale e failover senza sticky session.

Scelta del compute

Il cuore dell’esame è scegliere il servizio giusto per lo scenario, bilanciando controllo, latenza, costo e operatività:

  • Cloud Run: container stateless serverless che scala fino a zero. Ideale per API HTTP, web app ed elaborazioni request-driven. Leve chiave: concurrency (più richieste per istanza), min-instances per mitigare il cold start, e il traffic splitting tra revision per canary e blue/green.
  • GKE: orchestrazione Kubernetes quando servono controllo fine su networking, sidecar/service mesh, workload con requisiti particolari (GPU, DaemonSet, protocolli non-HTTP) o portabilità multi-cloud. Massima flessibilità, maggiore onere operativo.
  • Cloud Functions: event-driven, unità di codice attivata da un trigger (HTTP, evento Cloud Storage, messaggio Pub/Sub). Perfetta per glue code, reazioni a eventi e integrazioni leggere; meno adatta a servizi long-running o con molte dipendenze.
  • App Engine: PaaS per web app quando si vuole delegare l’infrastruttura restando su un modello applicativo gestito.

Regola pratica: container stateless request-driven → Cloud Run; serve Kubernetes o controllo profondo → GKE; reagire a un singolo evento → Cloud Functions. Il vero vantaggio del container è la portabilità: la stessa immagine (build con Cloud Build, conservata in Artifact Registry) gira in locale, su Cloud Run e su GKE.

Caching, sessione e resilienza

Il caching riduce latenza e carico sui backing service: Memorystore ospita cache applicativa, sessioni condivise, rate limiting e leaderboard. Su cache locali per istanza non si può fare affidamento, perché l’autoscaling le rende incoerenti. Definisci sempre una strategia di invalidazione e una TTL.

Per la reliability, progetta per il fallimento. Applica retry con exponential backoff e jitter solo su errori transitori e idempotenti, per non amplificare il sovraccarico; abbina timeout, circuit breaker e graceful degradation (servi dati cache o una risposta ridotta quando una dipendenza è giù, invece di crollare). Per il lavoro asincrono con controllo del rate usa Cloud Tasks; per il fan-out di eventi a più consumer usa Pub/Sub. Gestisci i segreti in Secret Manager (mai in chiaro nel codice o nelle env) e autentica i servizi con Workload Identity/impersonation invece delle service account key. Diagnostica la latenza con Cloud Trace e i consumi CPU/memoria con Cloud Profiler.

Trappole tipiche d’esame

  • App che perde le sessioni dopo lo scale → soluzione: esternalizza lo stato in Memorystore; niente sessione in memoria locale, altrimenti sticky session e incoerenze.
  • Reagire a un file caricato su Cloud Storage → soluzione: Cloud Functions event-driven sul trigger dell’oggetto, non un servizio Cloud Run in polling.
  • Cold start penalizza la latenza percepita → soluzione: su Cloud Run imposta min-instances e alza la concurrency; non migrare a GKE solo per questo.
  • Job asincroni con rate limiting verso un’API fragile → soluzione: Cloud Tasks (esecuzione con controllo del rate), non Pub/Sub, che serve il fan-out di eventi.
  • Dipendenza esterna intermittente → soluzione: retry con exponential backoff e jitter + graceful degradation; il retry aggressivo senza backoff peggiora l’incidente.
  • Credenziali per accedere ai servizi Google → soluzione: Workload Identity/impersonation e Secret Manager; mai service account key o secret in chiaro nelle env.